64,681
社区成员
发帖
与我相关
我的任务
分享
// 头文件LinkList.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include"iostream"
#include <stdlib.h>
#include<string>
#include<string.h>
using namespace std;
struct LinkNode
{
string name;
// 工号和电话号码用浮点数保存不合理,换成int
// 后面所有的double我都会换成int,并且不再用注释说明
// double number; //工号
// double telenumber; //电话号码
int number; //工号
int telenumber; //电话号码
LinkNode* next;
// 添加成员变量的初始化,当然,这并非绝对必要,只是我看不惯这里的警告
LinkNode(LinkNode *ptr = NULL)
:number(0), telenumber(0)
{
next = ptr;
}
// 真是危险的写法,尽量不要重名,虽然这种情况编译器能正确分辨
// 添加next指针的初始化
// LinkNode(string name, double number, double telenumber) :
// name(name), number(number), telenumber(telenumber)
LinkNode(string name, int num, int tel) :
name(name), number(num), telenumber(tel), next(NULL)
{
}
// LinkNode(string name,double number,double telenumber,LinkNode *next):
// name(name),number(number),telenumber(telenumber),next(next){}
};
class LinkedList
{
public:
LinkedList()
{
// 为了方便处理,这里创建一个头结点
// 另外,错误的根源也在此
// first = NULL;
first = new LinkNode();
}
// 这里最后的分号有些多余,不过不影响什么,每个人都会无意中碰到这种情况
~LinkedList()
{
Empty();
}
;
void create();
LinkNode* delName(LinkNode *first, string name); //按姓名删除
LinkNode* delNum(LinkNode* L, int i); //按工号删除
// 这个是演示函数
void delTel(int tel); // 按电话号码删除
bool insert(string name, int num, int tel, int i); //插入
LinkNode* searchName(/*LinkNode* L,*/string name); //按姓名查找
LinkNode* searchNum(int num); //按工号查找
LinkNode* searchTele(int tele); //按电话查找
void Show(); //显示通讯录
LinkNode *first; //头指针
private:
LinkNode * Locate(int i);
void Empty();
};
void LinkedList::Empty()
{
LinkNode* q;
while (first != NULL)
{
q = first->next;
first->next = q->next;
delete q;
}
// 这里也同时会释放掉头结点分配的内存
}
void LinkedList::create()
{
LinkNode *newNode, *current = first;
string name;
int num, tele;
cout << "请输入工号:" << endl;
cin >> num;
cout << "请输入姓名:" << endl;
cin >> name;
cout << "请输入电话号码:" << endl;
cin >> tele;
// 这里存在部分代码重复,可以换成无限循环 + 条件break的方式解决
while (num >= 0)
{
newNode = new LinkNode(name, num, tele);
if (newNode == NULL)
{
cerr << "存储分配错误!" << endl;
exit(1);
}
// 如果不使用头结点,那么第一次运行的时候,current为NULL,这里肯定内存访问错误
// 添加一个头结点之后,可以保证current不会为空
// 使用头结点可以减少特殊情况,如空链表插入等,其好处可以参考各种数据结构方面的书籍
current->next = newNode; //问题就出在这里
current = newNode;
cout << "请输入工号:" << endl;
cin >> num;
cout << "请输入姓名:" << endl;
cin >> name;
cout << endl << "请输入电话号码:" << endl;
cin >> tele;
}
// current->next=NULL;
}
// 你这两个del函数的逻辑我实在是不能理解,为什么还会有一个LinkNode*参数?
// 如果是想从整个链表中删除符合某项条件的节点的话,我给你写个示例delTel
void LinkedList::delTel(int tel)
{
LinkNode* pre = first;
LinkNode* p = first->next;
// 这里只用了一个临时变量,我觉得这比用两个更方便理解
while (p != NULL && p->telenumber != tel)
{
pre = p;
p = p->next;
}
if (p != NULL) // 找到节点了
{
pre->next = p->next; // 将p指向的节点从链表中移除
delete p;
}
}
LinkNode* LinkedList::delName(LinkNode *first, string name)
{
cout << "请输入删除人姓名: ";
cin >> name;
LinkNode *p = first;
if (p->next->name != name)
{
p = p->next;
}
p->next = p->next->next;
delete p;
return p;
}
LinkNode* LinkedList::delNum(LinkNode* L, int i)
{
LinkNode* p = L;
cin >> i;
if (p->number != i)
p = p->next;
delete p;
return p;
}
// 定位到第i个节点,返回值是这个节点的指针,返回NULL表示不存在第i个节点
LinkNode * LinkedList::Locate(int i)
{
if (i < 0)
return NULL;
// 添加头结点之后,第一个节点的指针就不是first了,而是first->next
// LinkNode* current = first;
LinkNode* current = first->next;
int k = 0;
while (current != NULL && k < i)
{
current = current->next;
k++;
}
return current;
}
// 插入到第i个节点之后
bool LinkedList::insert(string name, int num, int tele, int i)
{
LinkNode* current = Locate(i);
if (current == NULL)
return false;
LinkNode *newNode = new LinkNode(name, num, tele);
if (newNode == NULL)
{
cerr << "存储分配错误!" << endl;
}
// 添加到链表中,很好
newNode->next = current->next;
current->next = newNode;
return true;
}
LinkNode* LinkedList::searchName(string name)
{
#if 0
LinkNode* L = first;
LinkNode* p = L;
// 该函数的实现有问题,最起码得有个循环吧
// 另外,不检查指针是否为NULL,很容易就崩溃了
if (p->name != name)
p = p->next;
// ==写成=了
// if(p->next=NULL)return false;
if (p->next == NULL)
// 函数要返回LinkNode*,这里返回false肯定不对啦
return false;
cout << p->number << p->name << p->telenumber << endl;
#endif
// 修改实现
LinkNode* p = first;
while (p != NULL && p->name != name)
p = p->next;
if (p != NULL)
{
cout << p->number << p->name << p->telenumber << endl;
}
return p;
}
LinkNode* LinkedList::searchNum(int num)
{
LinkNode* p = first;
#if 0
if (p->number != num)
p = p->next;
// ==写成=了
// if (p->next = NULL)
if (p->next == NULL)
return false;
#endif
// 同searchName
while (p != NULL && p->number != num)
p = p->next;
return p;
}
LinkNode* LinkedList::searchTele(int tele)
{
LinkNode* p = first;
#if 0
if (p->telenumber != tele)
p = p->next;
// ==写成=了
// if (p->next = NULL)
if (p->next == NULL)
return false;
#endif
// 同searchNum
while (p != NULL && p->telenumber != tele)
p = p->next;
return p;
}
void LinkedList::Show()
{
// 添加头结点之后,第一个有效的存储节点为first->next
// 并且,判断链表是否为空也改为判断p,而不是first
LinkNode* p = first->next;
if (p == NULL)
// LinkNode* p = first;
// if (first == NULL)
{
cerr << "错误!" << endl;
exit(1);
}
else
{
while (p != NULL)
{
cout << p->name << p->number << p->telenumber << endl;
p = p->next;
}
}
}
#endif
// main.cpp
#include"LinkList.h"
#include<iostream>
using namespace std;
void jingcheng();
void find();
void del();
int main()
{
// system("color lf");
// system("mode con:cols=78 lines=35");
LinkedList L;
// 主程序的逻辑有些问题,你显然是想让操作可以一直进行,但是又不知道该怎么做吧?
// 下面是其中一种比较常见的思路:
// for (bool exit_ = false; !exit_; )
// {
// // 输出操作菜单
// int ch;
// cin >> ch;
// switch (ch)
// {
// case 1: break; // 处理各种命令,注意break
// case 2: break;
// case 3: break;
// case 4: exit_ = true; break; // 处理退出系统的命令
// default: break;
// }
// }
// 下面的代码我就不改了,你可以套用上面的形式自己练习一下^_^
jingcheng();
int ch;
cin >> ch;
//while(ch!=0){
// void xunhan(){
switch (ch)
{
case 1:
{
L.create();
L.Show();
}
// break;
case 2:
{
double num;
cout << "请输入工号:" << endl;
cin >> num;
string name;
cout << "请输入姓名:" << endl;
cin >> name;
double tele;
cout << "请输入电话号码:" << endl;
cin >> tele;
int i;
cout << "请输入序号:" << endl;
cin >> i;
while (num > 0)
{
L.insert(name, num, tele, i);
cout << "请输入工号:" << endl;
cin >> num;
cout << "请输入姓名:" << endl;
cin >> name;
cout << "请输入电话号码:" << endl;
cin >> tele;
cout << "请输入序号:" << endl;
cin >> i;
}
// break;
}
case 3:
{
find();
int hr;
cin >> hr;
switch (hr)
{
case 1:
{
string name;
cout << "请输入姓名:" << endl;
cin >> name;
LinkNode* p;
if (L.first == NULL)
{
cerr << "未找到!" << endl;
exit(1);
}
else
p = L.searchName(name);
cout << p->number << p->name << p->telenumber << endl;
// break;
}
case 2:
{
double num;
cout << "请输入工号:" << endl;
cin >> num;
LinkNode* p;
if (L.first == NULL)
{
cerr << "未找到!" << endl;
exit(1);
}
else
p = L.searchNum(num);
cout << p->number << p->name << p->telenumber << endl;
// break;
}
case 3:
{
double tele;
cout << "请输入电话号码:" << endl;
cin >> tele;
LinkNode* p;
if (L.first == NULL)
{
cerr << "未找到!" << endl;
exit(1);
}
else
p = L.searchTele(tele);
cout << p->number << p->name << p->telenumber << endl;
// break;
}
default:
break;
}
}
case 4:
L.Show();
case 5:
{
del();
int co;
cin >> co;
switch (co)
{
case 1:
{
}
}
}
;
}
return 0;
}