数据结构(C语言版)全程更新第二篇震撼来袭
2015-12-17 10:27
447 查看
单链表的使用
在数据结构中,根据元素之间的不同特性,通常有下列4类基本结构:集合、线性结构、树形结构、图状结构或网状结构。本次,笔者将会奉上豪华的链表套餐,希望新学者可以更快的掌握单链表的插入、删除操作。线性结构中有两种存储结构,一种是顺序存储结构,一种是链式存储结构,本次,只会接受链式存储结构,之后会补更顺序存储结构。
顺序存储结构查找比较方便,但是插入和删除操作需要移动大量元素,因此插入和删除较为麻烦,而单链表却刚好与之相反,它插入和删除比较方便,但查找却麻烦。因此何时使用链式和顺序,需要根据自己的需求合理使用,从而达到效率最大化。
对于链表,之前我们介绍过了,它的插入和删除比较方便,因此在实际应用中,我们常常会使用到这两个操作,因为笔者不怎么会使用编辑器,不会画动态图,所以可能很难把这个问题给大家演示清楚,但是笔者还是会尽力在代码中多加注释,方便大家的理解。如果大家有课本的话,对照课本中的动态图,再结合笔者的注释和通俗易懂的代码,相信大家都能很快的掌握对于单链表的使用。加油
/* 1、程序设计规划(实现的功能、分几个模块、子函数) 2、 编写单链表创建子函数 3、 编写单链表插入某个结点的子函数 提示:在插入到第i个位置时,要先找到第i-1的结点,然后操作 4、 编写单链表删除某个结点的子函数 提示:在删除到第i个位置时,也要先找到第i-1的结点,然后操作 5、 编写单链表查询某个结点的子函数 6、 编写单链表显示子函数 7、 编写主函数Main(),通过功能菜单调用子函数 8、 编译调试程序 */ //本程序中函数名的定义规则:多单次组合时第一个单次首字母小写,第二个单词开始每个单次首字母大写(采用了java中的方法的命名规则) #include<stdio.h> #include<stdlib.h> typedef int Status; //在这里给int起别名Status typedef int ElemType; //在这里给int起别名ElemType //建立结构体,通过结构体建立链表指针、next域、data域 typedef struct LNode{ ElemType data; //data域,用来存放结点中的值 struct LNode *next; //用来指向下一个结点 }LNode,*LinkList; //打印链表 void printList(LinkList &L) { LinkList p; //定义变量p p=L->next; //将p变为第一个结点(头结点的下一个) while(p!=NULL){ //当p不空时候循环 printf("%d\t",p->data); //输出结点p对应的值; p=p->next; //令p指向p的下一个结点 } printf("\n"); } //建立一个创造链表并初始化的函数 void creatList(LinkList &L,Status number) //number为链表中结点的个数 { L=(LinkList)malloc(sizeof(LNode)); //为L动态分配内存空间 if(L==NULL){ //增强代码的健壮性 printf("动态内存分配失败\n"); exit(0); //退出程序 } L->next=NULL; //将表置空 LinkList p=L; //创建将结点p并指向L LinkList q; //创建结点q //初始化链表 for(int i=1;i<=number;i++){ //循环语句 q=(LinkList)malloc(sizeof(LNode)); //给结点q动态开辟空间 if(q==NULL){ //同理在增强代码健壮性 printf("为结点动态分配空间失败:"); exit(0); } p->next=q; // 将结点p的下一个结点指向q p=q; // 将结点p移动到q的位置 printf("data:"); scanf("%d",&(q->data)); // 给q的data域赋值 q->next=NULL; // 将q的下一个置空 } } //该函数的功能为给第location个位置插入元素data void insertList(LinkList &L,int location,int data)//location表示链表的第location个结点 , data表示为插入的数为data { LinkList p=L; //创建将结点p并指向L LinkList q; //创建结点q q=(LinkList)malloc(sizeof(LNode)); //为q动态分配内存空间 if(q==NULL){ //同理在增强代码健壮性 printf("为结点动态分配空间失败:"); exit(0); } //思考为什么是要找到location-1的位置,将p放到location-1这个位置 可以画图方便理解 for(int i=1;i<=location-1;i++){ p=p->next; } q->next=p->next; //将q的指向的下一个结点指向p目前的下一个结点,这样就断开了p和p的下一个结点直接的线 p->next=q; //接着将p的下一个结点指向q这样q就插入进来了 q->data=data; //这里的=后边的data是函数传来的data,别混淆了 printList(L); //打印新的链表 } //删除链表中的某个值的函数 void deleteList(LinkList &L,int location) //location表示要删除的第某个结点 { LinkList p=L; //创建将结点p并指向L LinkList q; //创建结点q //为什么在q没有分配内存空间时候一样可以使用? q=(LinkList)malloc(sizeof(LNode)); if(q==NULL){ //同理在增强代码健壮性 printf("为结点动态分配空间失败:"); exit(0); } Status data; //用于存储被删除的结点所对应的值,并输出 for(int i=1;i<=location-1;i++){ //还是找位置location-1 p=p->next; } q=p->next; //将q放在p的下一个结点 p->next=q->next; //断开p指向q的线,使线指到q的next的位置。相当于把q架空了 q->next=NULL; //使结点q的下一个指向置空 data=q->data; //用data存储将要被删除的结点q中的值 free(q); //释放q printf("删除的结点的数值为:%d",data); printf("\n"); printf("删除后的链表为:"); //打印新的链表 printList(L); } //查找链表中某个位置结点的值,因为之前的插入和删除操作的使用,链表的值已经变化了,不再是第一你输入的时候的链表值了。所以别混淆了 void seekList(LinkList L,int location) //location表示的是查找的那个元素的位置 { LinkList p=L; //创建将结点p并指向L for(int i=1;i<=location;i++){ //遍历链表找到你想操作的那个结点 p=p->next; } printf("你所查找的位置的结点的值为:"); printf("%d",p->data); //输出该结点data域中的值 printf("\n"); } //销毁链表 void destoryList(LinkList &L) { LinkList p=L; //到了这里相信大家都发现了这个。每个函数都出来一次,为什么?自己思考下 while(L){ //销毁链表时候要一个结点一个结点的删除,所以这里采用了循环语句 p=L->next; //一个结点一个结点的删除 free(L); L=p; } printf("线性表已被成功销毁\n"); } //菜单函数,实现各项功能 void Menu(void) { LinkList L; Status a; //用于控制开关 Status number; //用于指示链表中结点的个数 Status location,data; //用于函数传参时候数据的操作 while(1){ printf("\t\t---------实现单链表的创建请按1:---------\n"); printf("\t\t---------插入单链表的结点请按2:---------\n"); printf("\t\t-------删除单链表的某个结点请按3:-------\n"); printf("\t\t---------实现单链表的查找请按4:---------\n"); printf("\t\t---------实现单链表的销毁请按5:---------\n"); printf("\t\t---------------退出请按6:---------------\n"); scanf("%d",&a); switch(a){ case 1: printf("请输入链表的结点个数:"); scanf("%d",&number); creatList(L,number); //创建链表 //在调用函数时参数切不可写成这样creatList(&L,number);注意下初学者比较容易犯错 printf("是否需要打印出链表中的值:(是请按T,否请按N)\n"); char flag; //在判断时候用的变量 scanf("%s",&flag); //scanf("%c",&flag) 会被跳过scanf不信你试试 (*^__^*) …… if(flag=='T'){ printList(L); } else{ //这里的代码是为了增强健壮性,觉得太冗长的人可以注释掉 if(flag=='N'){ break; } else{ printf("输入有误请按要求输入\n"); break; } } break; case 2: printf("请输入你想在第几个位置插入元素:"); scanf("%d",&location); printf("\n"); printf("请输入你要插入的元素:"); scanf("%d",&data); insertList(L,location,data); //插入链表,在第location个位置插入元素data break; case 3: printf("请输入你想删除第几个位置的元素:"); scanf("%d",&location); deleteList(L,location); //删除链表中的某个位置的元素 break; case 4: printf("输入你想查看的第几个结点的值:"); scanf("%d",&location); //查找第location个结点 seekList(L,location); //寻找链表中的某个结点 break; case 5: destoryList(L); //使用完了销毁链表 break; case 6: exit(0); break; } } } //主函数 用来调用子函数 Status main(void) { Menu(); system("pause"); return 0; }
相关文章推荐
- <LeetCode OJ> (104 / 111) Maximum & Minimum Depth of Binary Tree
- 数据结构C语言版车牌号的查询与排序
- 数据结构和算法经典100题-第24题
- 【数据结构实验】图的深度优先/广度优先遍历
- 数据结构和算法经典100题-第23题
- 数据结构综合训练1
- 数据结构上机5二叉树遍历
- 数据结构-约瑟夫环
- 数据结构上机4队列-杨辉三角2
- 数据结构上机4队列-杨辉三角1
- 数据结构上机3栈-括号匹配
- 数据结构上机2单链表合并 非递减
- 数据结构上机1顺序表
- 考研系列之三-数据结构杂集
- 数据结构和算法经典100题-第22题
- 【C#数据结构】快速排序
- 【C#数据结构】简单选择排序
- memcached-数据结构
- 【C#数据结构】直接插入排序
- 数据结构实验4(排序算法的实现及性能分析)