#include <IOSTREAM> #include <IOMANIP> #include <STRING> using namespace std; typedef struct Student { int id; char name[20]; char sex[20]; struct Student *next; }node; typedef node * pnode; pnode Create(); void Print(pnode h); void Sort(pnode h); int Length(pnode h); void Delete(pnode h,int num); void Insert(pnode h,int num,char * name,char * sex); int main() { char command[10] = "1"; pnode h; while(strcmp(command,"q")!=0) { cout << "请输入命令:" << endl; cout <<"-----------------------------" << endl; cout <<"1: 创建链表" << endl; cout <<"2: 插入节点" << endl; cout <<"3: 删除节点" << endl; cout <<"4: 链表排序" << endl; cout << "5:打印链表" << endl; cout << "6:链表长度" << endl; cout <<"q:退出" << endl; cout <<"-----------------------------" << endl; cin >> command; if(0==strcmp(command, "1")) { h = Create(); Print(h); } else if(0==strcmp(command, "2")) { cout << "请输入学号,姓名,性别:\n"; node temp; // cin >> temp.id ; // getchar(); // cin.getline(temp.name,20); // cin.getline(temp.sex,20); temp.id = 10; strcpy(temp.name , "weilele"); strcpy(temp.sex, "female"); Insert(h,temp.id,temp.name,temp.sex); } else if(0==strcmp(command, "3")) { } else if(0==strcmp(command, "4")) { Print(h); } else if(0==strcmp(command, "5")) { Print(h); } else if(0==strcmp(command, "6")) { cout << "链表长度:" << Length(h) << endl; } } return 0; } pnode Create() { pnode h; pnode p,q; bool flag = true; //建立一个头节点 h = new node; h->id=0; strcpy(h->name,"none"); h->next = NULL; p=h; int id; char name[20]; char sex[20]; //注意这里的cin无法直接读取空格隔开的元素的值 //将数字转换成字符串? while (flag) { cout << "请输入学生的学号,姓名,性别:\n" << endl; string str1; string str2; string str3; char temp; cin>> id ; char c = getchar(); cin.getline(name,20); // 读取一行数据,允许中间出现空格 cin.getline(sex,20); //cin >> id; if(id!=0) { q = new node; q->id = id; strcpy(q->name,name); strcpy(q->sex,sex); q->next = NULL; p->next = q; p=p->next; } else //退出输入 { flag = false; } } return h; } void Print(pnode h) { pnode q= h->next; if(q==NULL) { cout << "链表为空!" << endl; return; } cout << "打印链表:" << endl; int i=0; while(q!=NULL) { cout << "节点"<<i++ << "\t"<< "学号:"<< q->id << "姓名:"<< q->name <<"性别:"<< q->sex << endl; q=q->next; } } int Length(pnode h) { pnode p=h->next; int n = 0; while(p!=NULL) { n++; p = p->next; } return n; } void Delete(pnode h,int num) { pnode p1 = h->next; pnode p2; if(p1==NULL) { cout << "链表为空!无法查找" << endl; return; } while (p1->id!=num && p1->next != NULL) { p2= p1; p1 = p1->next; } if(p1->id == num) { if(p1 == h) //在h头 { p1 = h; h = h->next; delete p1; //释放掉头节点 } else if (p1->next == NULL) { delete p1; p2->next = NULL; } else { p2->next = p1->next; delete p1; } cout << "删除节点成功" << endl; } else { cout << "没有查找到对应节点,无法删除\n"; } } void Sort(pnode h) { if(h == NULL) { cout << "链表为空!无需排序" <<endl; return; } pnode p,q; p=h->next; while(p->next!=NULL) { q=p->next; while(q!=NULL) { if(q->id < p->id) { node temp; temp.id= p->id; strcpy(temp.name , p->name); strcpy(temp.sex, p->sex); p->id = q->id; strcpy(p->name, q->name); strcpy(p->sex,q->sex); q->id = temp.id; strcpy(q->name,temp.name); strcpy(q->sex,temp.sex); } q = q->next; } p = p->next; } cout << "排序完成,输出:" << endl; Print(h); } //插入操作,这里插入操作如果是在头节点之前会出现错误,所以要给链表一个头节点来避免错误//原因:这里函数的形参h是指针的值传递,在退出该函数后,指针的值并没有发生变化,因为传递的只是一份形参。在Insert中的所有操作是对指针的值的拷贝的操作,在函数中改变指针的值(h=s)其实是对h的拷贝的改变,所以函数执行完后,原来实参的值并没有发生改变// void Insert(pnode h,int num,char * name,char * sex) { pnode p1,p2; p1 =h->next; pnode s = new node; s->id = num; strcpy(s->name,name); strcpy(s->sex ,sex); if(h== NULL) { h = s; cout << "插入成功" << endl; Print(h); return; } while (p1->id<s->id && p1->next!=NULL) { p2 = p1; p1 = p1->next; } if(p1==h->next) { if(p1->id>s->id) { h->next = s; s->next = p1; } else { p1->next = s; s->next = NULL; } } else if(p1->next == NULL) { p1->next = s; s->next = NULL; } else { p2->next = s; s->next = p1; } Print(h); }
数据结构中,在单链表的开始结点之前附设一个类型相同的结点,称之为头结点。头结点的数据域可以不存储任何信息,头结点的指针域存储指向开始结点的指针(即第一个元素结点的存储位置)。
作用
1、防止单链表是空的而设的.当链表为空的时候,带头结点的头指针就指向头结点.如果当链表为空的时候,单链表没有带头结点,那么它的头指针就为NULL.
2、是为了方便单链表的特殊操作,插入在表头或者删除第一个结点.这样就保持了单链表操作的统一性!
3、单链表加上头结点之后,无论单链表是否为空,头指针始终指向头结点,因此空表和非空表的处理也统一了,方便了单链表的操作,也减少了程序的复杂性和出现bug的机会。
4、对单链表的多数操作应明确对哪个结点以及该结点的前驱。不带头结点的链表对首元结点、中间结点分别处理等;而带头结点的链表因为有头结点,首元结点、中间结点的操作相同 ,从而减少分支,使算法变得简单 ,流程清晰。对单链表进行插入、删除操作时,如果在首元结点之前插入或删除的是首元结点,不带头结点的单链表需改变头指针的值,在C 算法的函数形参表中头指针一般使用指针的指针(在C+ +中使用引用 &);而带头结点的单链表不需改变头指针的值,函数参数表中头结点使用指针变量即可。
时间: 2024-11-10 04:06:46