数据结构实验1 链表 实现学生信息存储,功能 增删改查,实现 结构类型
来源:互联网 发布:安大网络教学综合平台 编辑:程序博客网 时间:2024/05/16 09:25
//一共三个结构,一个是学生的信息即struct Stu包括学生的基本信息和显示信息建立信息的函数,//一个是节点struct Node,包括数据项学生和指针域//一个是链表struct Line,包括增加节点函数enstudent(const Item & s),判断链表空满的函数//删除节点函数destudent() ,查询节点函数Node * search() ,修改节点函数void alter() //查找并显示函数void find() //除了三个结构还有两个函数 void showLine(Line * a) ,显示全部学生信息//和 void newstudent(Line & b) ,增加学生个数 这两个都在main()函数中使用#include<iostream.h>struct Stu //学生信息的结构{int id;char name[30];float score;void show()const //显示学生的信息{cout<<"学生信息:\n学号:"<<id<<"\n姓名:"<<name<<"\n分数"<<score<<endl;}void set() //新建学生信息{cout<<"请输入学号,姓名,分数\n ";cin>>id>>name>>score; }};typedef Stu Item; //让Item成为Stu的别名,看起来清楚一点,虽然Stu也比较短struct Node //链表的节点{Item item; //数据项Node * next; //节点的指针域};struct Line //链表主体{Node * front; //头节点Node * rear; //尾节点int items; //新建的节点数,后面用来判断链表是否为空或满int max; //最大节点数,由用户输入bool isfull() //判断链表是否为满,即满时节点数items和最大节点数max相等,是就返回true{return items==max; }bool isempty() //判断链表是否为空{return items==0;}bool enstudent(const Item & s) //增加新节点{if(isfull()) //先判断链表是不是满的,满的返回false表示无法加入新节点return false;Node * add = new Node; //new动态创建一个节点Node空间,用add标记if(add==NULL) //如果创建后add没有空间,即add==NULL,表示分配空间时失败,返回falsereturn false;add->item=s; //把add节点的数据项置为传入的Item类型的s,指针置为空,即NULLadd->next=NULL;items++; //创建的节点数加1if(front==NULL) //如果头节点front开始为空就是说,没有添加任何节点时,让front=add; //头节点add成为头节点elserear->next=add; //接上面若front开始不为空,就是已经有几个节点后,让 //add成为尾节点rear就是最后一个节点的下一个节点rear=add; //这里把尾节点标记为add return true;}bool destudent() //删除节点{if(isempty()) //判断是否为空return false;Node * p=front; //把p置为链表的头节点的地址Node * s=search(); //s是搜索返回的学生信息节点的地址if(p==s) //如果头节点和搜索的信息相同就删除这个头节点{front=front->next; //删除头节点时,先把头节点置为删除前头节点的下一个节点delete p; //因为已经把头节点的地址保存在p里面,这里就删除p就可以了cout<<"删除成功!";return true;}else if(p->next==s) //如果搜索到的结果和头节点的下一个节点相同那么就删除节点的下一个节点{Node * q=p->next; //把要删除的头节点的下一个节点保存在q里面以便删除p->next=p->next->next; //把p的下一个节点和p的下一个节点的下一个节点连接起来,之后才可以删除q delete q; //接上,保证链表不会断开cout<<"删除成功!";return true;}else{while(p->next!=s) //如果不是上面两个,那么让p指向p的下一个节点,直到p->next==s,{p = p->next;}p->next =s->next; //循环结束时p->next==s,即p是需要删除的搜索出来的s的上一个节点delete s; //接上,把要删除的s节点的上一个节点(即p)和下一个节点(即s->next)连接,使s脱离链表cout<<"删除成功!"; //最后删除sreturn true;}}Node * search() //查询节点,按学号查询{cout<<"请输入学生学号:\n";int sid;cin>>sid;Node * p=front; //把p置为头节点的地址while(p!=NULL&&p->item.id!=sid) //当p有数据时并且p数据项和id不同时循环{p=p->next;} //循环结束后p就是要查询的节点的地址return p;}void alter() //修改内容,先查到学生,再用学生结构Item的方法set()重置信息{cout<<"请输入要修改学生的学号\n";Node * p = search();p->item.set();}void find() //查找并显示{cout<<"请输入要查询的学生学号\n";Node * p = search();p->item.show();}};void showLine(Line * a) //显示全部学生信息{Node * p = a->front;while(p){p->item.show();p=p->next; //让p成为p的下一个地址,可以遍历所有链表节点}}void newstudent(Line & b) //增加学生个数{cout<<"按任意字符新建学生信息 输入\"q\"结束\n";char a;cin>>a;while(!b.isfull()&&(a!='q')) //当链表不为空并且a!=q时一直进行增加节点{Item temp;temp.set();b.enstudent(temp); //增加节点cout<<"按任意字符新建学生信息 输入\"q\"结束\n";cin>>a;}}int main(){cout<<"请输入新建学生个数\n";Line line; //建立链表cin>>line.max; //输入最大的节点数line.front=line.rear=NULL; //使链表的头尾节点为空line.items=0; //使节点个数为0newstudent(line); //增加节点cout<<"1.新建学生信息 2.删除 3.修改 4.查询 5.显示全部信息 6.退出\n";int a;cin>>a;while(a!=6){switch(a){case 1 :newstudent(line);break;case 2 :line.destudent();break;case 3 :line.alter();break;case 4 :line.find();break;case 5 :showLine(&line);break;default: cout<<"请输入数字1-6";}cout<<"1.新建学生信息 2.删除 3.修改 4.查询 5.显示全部信息 6.退出\n";cin>>a;}cout<<"程序退出";return 0;}写那阵的一点儿想法//一共三个结构,一个是学生的信息即struct Stu包括学生的基本信息和显示信息建立信息的函数,//一个是节点struct Node,包括数据项学生和指针域//一个是链表struct Line,包括增加节点函数enstudent(const Item & s),判断链表空满的函数//删除节点函数destudent() ,查询节点函数Node * search() ,修改节点函数void alter() //查找并显示函数void find() //除了三个结构还有两个函数 void showLine(Line * a) ,显示全部学生信息//和 void newstudent(Line & b) ,增加学生个数 这两个都在main()函数中使用 1.应该把学生信息单独定义成一个结构Stu,这样就能像使用其他系统定义的数据类型一样使用Stu,Stu和int float一样, 不同的是这里也定义了处理Stu的函数,并把这些函数放在了Stu结构里,虽然结构通常不在结构定义里定义函数(类这么做),但现在这么做会看起来清楚点(结构支持这种方式) 2.typedef Stu Item; 让Item成为Stu的别名,虽然Stu比较短,但是以后要是把Stu改成Students那么使用Item要简洁点儿,而且只需要修改typedef Stu Item; 这句话,和#define pi 3.14 想法差不多 3.struct Node 是链表的节点,课本上没有让这个成为一个结构,但是成为一个结构肯定会更清楚点儿,节点这个结构只包含数据域和指针元域,不在里面定义其他内容,因此,节点看起来更像系统里定义的内置类型,可以看作是4.struct Line 链表主体,这个是管理节点的结构 这个里面包含的数据元素是:头节点front 头节点是链表的地址,头节点像个绳子头,找到才能绳子头才能使用绳子. 使用链表: 比如打算找到另外一个学校的一个不认识但知道名字的学生,而且恰好一个好朋友也在这个学校,那么可以通过打电话找到这个朋友(自己电话里朋友的电话号码就是这个头节点,有了才有找到那个学生的希望),然后你朋友也不认识这个同学,他可以打电话给他的朋友(他电话里他朋友的电话就是“他这个节点”的指针域,可以用来找到他的朋友),然后他朋友也不认识,(并且每人电话里只有一个电话号码,只有一个)然后……最后终于找到了尾节点rear 尾节点存储的是最后一个节点的地址,和头节点类似(头节点是第一个节点的地址,并且头节点只使用了自己,但是尾节点像是一个标签,标注的是最后一个节点的位置,最后一个节点的本质并不是rear,但是使用rear却和使用最后一个节点效果相同,这么着好像叫rear是最后一个节点的别名更好理解点儿)使用rear可以立刻找到最后一个节点,不必从头开始找起,使用尾节点的目的(增加节点函数时用到)也是迅速找到最后一个节点,然后把新加的节点连在rear后面,再把更新后的链表的最后一个节点赋给rear,rear永远是最后一个节点的别名,即使只有一个节点,那么它既是头节点也是尾节点一共建立的节点个数items(在增加节点函数里会items++;)items是和max配合为判断链表是否为空的函数准备的用户要求使用的最大节点数max 比如用户打算输入50个学生信息,那么max=50;这个在main()函数里建立链表Line line;后由用户输入进cin>>line.max; 进行设置 使用max是因为要判断链表是否为空 {bool isfull()和bool isempty() 函数} 以便进行增加节点或删除节点, 当用户输入第51个学生或打算删除没有学生的链表时会出现错误 5. bool enstudent(const Item & s) 增加新节点因为函数是在管理节点的结构 struct Line 内部定义的,因此可以直接使用自己结构的数据项front,在main()函数中建立 struct Line的实例line后,整个链表的地址就是line.front了,链表地址内置到了结构实例里面了,用起来比较好用,而且这个不是我自己想的……所以应该靠谱 哈哈 然后就是增加节点,增加节点用传进来的参数const Item & s,s是学生类型的结构数据项 总共分三步,第一步 准备新节点 把s赋给动态建立(动态分配的内存会一直存在,链表要求节点一直存在不会随函数的生命结束而结束)的节点Node * add = new Node;的数据项 即add->item=s; 并把新节点指针域置为空(最后点指针都置为空,以标志链表结束) 即add->next=NULL; 这里即把新节点准备好了(items++; )第二步 新节点加入到链表 这里需要判断链表是否为空,没加入节点时为空(main() 里设置了line.front=line.rear=NULL;使链表的头尾节点为空) 为空那么就把这个节点赋给front,即front=add; 不为空,即已经加入了几个节点了,那么就把新节点加入到尾节点的后面 即rear->next=add; 第三步 更新尾节点,使尾节点指向更新后的链表的最后的节点,即rear=add; 6.bool destudent() 删除节点这个函数做的不好,应该有简单点儿的方式删除节点需要找到要删除的节点的前一个节点,因为要保证链表不断,找到前驱结点后,把前驱结点和要删除节点的下一个节点连接起来,使要删除的节点脱离链表(之前要保存要删除节点的地址,因为脱离了不保存在其他地方,就找不到了,也就无法删除了) 然后删除保存的地址(和删除原节点效果相同)删除节点也是三步,一找到前驱结点;二连接前驱结点和下一个节点,使要删除节点脱离链表;三,删除 7.总结一下就是先组织程序的结构,这里让学生信息是一个结构并包含对它的操作函数, 然后再用学生结构作为数据项建立节点的结构类型 最后再建立管理节点(即链表)的结构,并包含对它的操作函数 然后再写对应的函数就行了 在三个结构外面再增加对链表结构操作的函数 void showLine(Line * a) ,显示全部学生信息 和 void newstudent(Line & b) ,增加学生个数