c语言数据结构:单链表
各位朋友们,伙计们,大家好!
|
|
创建链表
链表链表,顾名思义,就是像链子一样连在一起的表,咳咳,虽说有些废话,但确实如此,它是结构体与结构体之间以指针互相连接着,上一个结构体的指针指向下一个结构体,这样就形成了一个链表,它相对于数组有什么好处呢,大家都知道,数组内的内存空间是预先分配好的,而且也不能在使用过程中动态的改变其空间大小,这样就会有一个很大的弊端,比如给一个int型数组分配了100个内存空间,那么它就只能最多存100个数据,超过了就完蛋,存少了还浪费内存,就很烦,然而链表就没有这个问题,你有多少数据就开辟多少内存空间,不要某个数据还可以释放掉其内存空间,而且支持多个不同类型的数据在一块,多好!所以,学会了链表,数组只能躲在一边默喊mmp。
咳咳,话不多说,上代码!
#include <stdio.h>#include <stdlib.h> //此头文件包函malloc动态申请内存函数//创建一个名为list的结构体typedef struct list{//结构体数据,你想多整几个也行,我在这只放了一个,不是我想偷懒啊int data;//弄一个指向下一个结点的结构体的尾指针struct list* next;}L; //用typedef让L来代替struct list,节约点按键盘次数//创建链表//L* 为此函数的类型为L*也就是struct list*,返回结构体函数指针L* creatorList(){//定义一个结构体指针并分配内存空间,分配大小为此结构体所占内存大小L* headlist = (L*)malloc(sizeof(L));//表头只是起到一个引导作用,所以不用给其赋值//刚创建的链表为空,所以需要让表头的尾结点指向NULLheadlist->next = NULL;//返回创建好的链表return headlist;}
创建结点
既然链表已经创建好了,那么接下来就是创建结点,结点里存放我们数据,结点的创建跟上面的操作类似,如果这块有啥问题可以直接来问我就可以了。
话不多说,上代码!
//创建结点L* creatorNode(int data){//跟之前创建链表的时候相同,结点也需要申请内存空间L* newNode = (L*)malloc(sizeof(L));//不过,之前创建的链表只有表头,只起到了引导作用//所以,结点里面就可以放数据了newNode->data = data;//将结点的尾指针指向NULLnewNode->next = NULL;//返回结点return newNode;}
插入结点
//函数参数为要插入的链表和要插入其中的结点void insertNode(L* head,L* newNode){//首先先让新结点的尾指针指向头结点的尾指针所指的结点newNode->next = head->next;//再让头结点的尾指针指向新结点head->next = newNode;}
void insertNode(L* head,L* newNode){//首先再定义一个指针指向链表的头结点L* pMove = head; //此做法是让head一直是链表头结点while(pMove->next!=NULL) //判断pMove是否移动到了链表的最后一个结点pMove = pMove->next; //使pMove移动至下一个节点//循环完毕之后表示pMove已经指向了链表的最后一个结点pMove->next = newNode; //将pMove,即最后的结点的尾指针指向新结点}
void insertNode(L* head,L* newNode){L* pMove = head; //此做法是让head一直是链表头结点//判断pMove是否移动到了尾结点while(pMove->next!=NULL){//判断pMove所指结点所指结点的数据的数是否小于新结点的数据,然后再判//断pMove所指结点的尾指针所指的结点的数据是否大于新结点数据if(pMove->data<newNode->data&&pMove->next->data>newNode->data){//条件成立,此下操作就跟头插法差不多//让新结点的尾指针指向pMove所指结点的尾指针所指的结点newNode->next = pMove->next;//让pMove所指结点的尾指针指向新结点pMove->next = newNode;//插入完成,return返回return;}//让pMove指向下一个结点pMove = pMove->next;}//循环完毕后,此时pMove为链表尾结点,让pMove所指结点的尾指针指向新结点pMove->next = newNode;}
查询结点
大家用过数组吧,其实链表的查询方法就和数组差不多,比如我想在数组里找一个数据,我会用循环来让数组里的元素和我要查找的数一一比较,直到找到为止,而链表也是如此,不过只是将数组元素换成了链表结点。
上代码!!!
void queryNode(L* head,int data){//定义一个整形i的目的是显示其所查询的数据在第几个结点int i=1;//这里我就不讲了,跟上面解释一样L* pMove = head->next;while(pMove){//判断数据是否匹配if(pMove->data==data){//输出查找到的结点数据和它所在结点位置printf("已找到数据:%d,它在第%d结点",pMove->data,i);//已查找到,return返回,不让继续执行下面程序return;}i++;pMove = pMove->next;}//循环结束表示没有找到printf("未找到匹配数据\n");}
修改结点数据
上代码!!!
void changeNode(L* head,int data){L* pMove = head->next;while(pMove){//如果数据匹配if(pMove->data==data){printf("请输入修改后的数据:");scanf("%d",&data);//将此结点数据修改pMove->data = data;printf("修改完成!\n");return;}pMove = pMove->next;}//循环结束表示没有找到匹配结点printf("未找到匹配结点\n");}
删除结点
话不多说,上代码!!!
void deteleNode(L* head,int data){L* pMove = head;//定义一个结构体指针,指向pMove所指结点的下一个节点L* dpMove = pMove->next;while(dpMove){//如果结点数据匹配if(dpMove->data==data){//这里的操作就跟头插入差不多//让pMove所指结点的尾指针指向dpMove所指结点的尾指针所指的结点pMove->next = dpMove->next;//释放dpMove所指的结点内存free(dpMove);printf("删除完成!\n");return;}pMove = pMove->next;dpMove = pMove->next;}//循环结束表示没有找到匹配结点printf("未找到匹配结点\n");}
输出链表
终于到输出了,赶紧弄完去打把LOL,哈哈哈哈!
上代码!!!
void printlist(L* head){//让PMove指向头结点的下一个结点L* pMove = head->next;//如果PMove所指结点为NULL,则表示其链表为空if(pMove==NULL){printf("链表为空\n");return;}//这里的头是表示头结点,它起一个引导作用printf("头");//当pMove不为NULL,同不为0时while(pMove){//输出结点数据printf("->%d",pMove->data);//让pMove指向下一个结点pMove = pMove->next;}//结点输出完输出NULL的意义为,能更直观的看到链表的结构printf("->NULL\n");}
销毁链表
话不多说了,上代码!!!
尾删法:
void detelelist(L* head){L* pMove;L* detele;while(1){pMove = head;//如果下面的条件成立,表示链表为空,跳出循环if(pMove->next==NULL)break;//判断pMove所指结点的尾指针所指的尾指针所指的结点是否为NULL//此做法是为了给detele留个位位好释放它所指的尾结点while(pMove->next->next!=NULL)pMove = pMove->next;//此时pMove所指的结点的尾指针所指的结点为尾结点//让detele指向它!!!detele = pMove->next;//让pMove所指的结点的尾结点指向detele所指结点的尾指针所指,即NULLpMove->next = detele->next;//释放它!!!free(detele);//每释放一次输出一次链表printlist(head);}//此时链表为空,将头结点指针置为NULLhead = NULL;}
头删法:
void detelelist(L* head){L* pMove = head->next;while(pMove){//让头结点的尾指针指向pMove所指结点的尾指针所指的结点head->next = pMove->next;//釈放する!!(释放它!!)free(pMove);//让pMove指向下一个结点pMove = head->next;//每释放一个结点输出一次链表printlist(head);}//此时链表为空,将头结点指针置为NULLhead = NULL;}
typedef struct list{int data;struct list* next;}L;L* creatorList(){L* headlist = (L*)malloc(sizeof(L));headlist->next = NULL;return headlist;}L* creatorNode(int data){L* newNode = (L*)malloc(sizeof(L));newNode->data = data;newNode->next = NULL;return newNode;}void insertNode(L* head,L* newNode){L* pMove = head;while(pMove->next!=NULL){if(pMove->data<newNode->data&&pMove->next->data>newNode->data){newNode->next = pMove->next;pMove->next = newNode;return;}pMove = pMove->next;}pMove->next = newNode;}void queryNode(L* head,int data){int i=1;L* pMove = head->next;while(pMove){if(pMove->data==data){printf("已找到数据:%d,它在第%d结点",pMove->data,i);return;}i++;pMove = pMove->next;}printf("未找到匹配数据\n");}void changeNode(L* head,int data){L* pMove = head->next;while(pMove){if(pMove->data==data){printf("请输入修改后的数据:");scanf("%d",&data);pMove->data = data;printf("修改完成!\n");return;}pMove = pMove->next;}printf("未找到匹配结点\n");}void deteleNode(L* head,int data){L* pMove = head;L* dpMove = pMove->next;while(dpMove){if(dpMove->data==data){pMove->next = dpMove->next;free(dpMove);printf("删除完成!\n");return;}pMove = pMove->next;dpMove = pMove->next;}printf("未找到匹配结点\n");}void printlist(L* head){L* pMove = head->next;if(pMove==NULL){printf("链表无数据\n");return;}printf("头");while(pMove){printf("->%d",pMove->data);pMove = pMove->next;}printf("->尾\n");}void detelelist(L* head){L* pMove = head->next;while(pMove){head->next = pMove->next;free(pMove);pMove = head->next;printlist(head);}head = NULL;}void main(){L* list = creatorList();L* newNode;int data;while(1){printf("请输入结点数据(0为停止输入):");scanf("%d",&data);if(data==0)break;newNode = creatorNode(data);insertNode(list,newNode);printf("输出链表:\n");printlist(list);printf("\n");}printf("请输入所要查找的数据:");scanf("%d",&data);queryNode(list,data);printf("\n请输入所要修改的结点数据:");scanf("%d",&data);changeNode(list,data);printlist(list);printf("\n请输入所要删除的结点:");scanf("%d",&data);deteleNode(list,data);printlist(list);getchar();getchar();printf("\n删除链表数据:\n");detelelist(list);}
代码里插入结点函数我用了排序插入法,销毁链表函数我用了头删法,大家可以使用上面的其他方法,如果有什么问题可以问我,下次我将做一个双向链表,ok,希望大家看完之后能点一个在看、分享,作者在此多谢啦!!!
| 至此,所有单链表操作完结!!撒花!! |
