赞
踩
在增删的指定节点操作就用到了查,大家可以看完增删的前两个就去看看查是怎么操作的,然后方便对指定节点操作。
本篇文章是交大家如何用结构体指针实现增删查改,
百度百科链表:链表是一种物理存储单元上非连续、非顺序的存储结构,
数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
我的理解:多个有指针域的结构体的通过指针顺序链接在一起, 在内存中的存储是散落的
在内存如下存储:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
代码如下(示例):
#include <stdio.h> #include <stdlib.h> struct Test//结构体定义 { int data; struct Test *next; }; int main() { struct Test t1={1,NULL}; struct Test t2={2,NULL}; struct Test t3={3,NULL}; t1.next=&t2;//链表精髓在这,每个节点的next存放的是下一个节点的地址。这样就连接起来了。 t2.next=&t3; }
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> typedef struct node { int data; struct node * next; }node,*pnode;//node是取别名,pnode是类型,结构体指针类型 //struct node * pnode //创建头节点,初始化函数。返回头节点的指针。 pnode init() { pnode head = (pnode )malloc(sizeof(node)); //用malloc开辟空间,此时pnode == struct node * if(head == NULL)//此时做一个容错判断,如果没有开辟成功,打印错误 { perror("head fault"); } head->data = 0;//开辟空间之后里面是没有值的,最好给数据域和指针域分别赋值 head->next = NULL;//指针没有指向,指向NULL就ok,防止其乱指向 return head;//返回头节点指针,方便我们以后调用 }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
链表的增加
链表的删除
链表的查找
链表的改动
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
实现思路:(博主比较懒,三种插法只详细写了一个思路,思路都大同小异,我在每个插法代码的前面都画了内存操作图,里面有简单思路,每一行代码里面都给了注释,不理解的可以评论区留言呀)
第一步,创建新节点,然后把传递的值赋值给新节点
pnode pnew = (pnode )malloc(sizeof(node));//用malloc开辟空间,类型是pnode,大小是一个结构体的大小
第二步,写一个容错判断,如果pnew==NULL,说明创建不成功,直接退出
第三步:链接新节点到链表头下一个节点,何为链接,无非就是把下个节点的地址赋值给头节点的next;
pnew->next = head->next;//head->next原本存的是第二个节点的地址,现在把它赋值给新节点,那么是不是新节点的下一个就是原先的第二个节点了,就是实现图中1
第四步:把头结点和新节点连接起来
head->next = pnew;//此时,我们在把新节点和头节点链接起来,这样就是头节点指向新节点了,pnew本身就是一个指针
//每次都在头结点的后面增加,简称头插法 /**************************************************************** * 函数名: insertHead * 参 数: head 链表的头节点指针 * data 需要插入节点数据 * 返回值: 链表中节点个数 * 节点的个数保存在head的data中。 ****************************************************************/ int insertHead(node* head,int data) { //第一步:创建新节点,存入数据 pnode pnew = (pnode )malloc(sizeof(node));//用malloc开辟空间,类型是pnode,大小是一个结构体的大小 if(NULL == pnew)//容错判断新创建的节点是否成功 { perror("head NULL"); exit(0);//不成功就输出错误,然后退出 } pnew->data = data;//把传进来的值赋值给新节点 //第二步:链接新节点到链表头下一个节点,何为链接,无非就是把下个节点的地址赋值给头节点的next; //head的next为空的情况 pnew->next = head->next;//head->next原本存的是第二个节点的地址,现在把它赋值给新节点,那么是不是新节点的下一个就是原先的第二个节点了 //第三步:head不为空,把头节点的next指针指向新的节点 head->next = pnew;//此时,我们在把新节点和头节点链接起来,这样就是头节点指向新节点了,pnew本身就是一个指针 //当第二步赋值的时候,头节点与原先的第二个节点链接自动断开 //第四步:节点个数加一 (head->data)++;//因为我们头节点的数据域存的是节点个数 //第五步:返回头节点中节点数据; return head->data; }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/**************************************************************** * 函数名: insertEnd * 参 数: head 链表的头节点指针 * data 需要插入节点数据 * 返回值: 链表中节点个数 * 节点的个数保存在head的data中。 ****************************************************************/ int insertEnd(pnode head,int data) { //第一步:定义临时指针 node* ptmep = head; //第二部:遍历链表,找最后一个节点 while( ptmep->next != NULL) { ptmep = ptmep->next;//指针偏移 } //循环完之后,ptemp的next已经为NULL了 //第三步:创建新节点 pnode pnew = (pnode)malloc(sizeof(node));//malloc开辟空间 //第四步:给节点赋值 pnew->data = data; //第五步:新节点插入到链表末尾 pnew->next = NULL;//尾插法,新节点需放在最后,所以新节点后面没有节点了,指向null ptmep->next = pnew;//原最后一个节点指向新节点,那么原最后一个节点就成为了倒数第二个节点 //第六步:返回链表长度 (head->data)++; return head->data;//也可以直接return ++(head->data);一样的效果 }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/********************************************* * 函数名:insert * 参数: head头节点指针 * pos 需要插入的位置 * data 需要插入的数据 * 返回值: 链表的节点个数 * 作用: 在pos的位置插入一个节点 *****************************************************/ int insert(pnode head,int pos,int data) { // 第0步:判断pos是否超过节点个数 if(pos > head->data) { printf("无法插入指定位置,程序退出\n"); exit(0); } // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head;//赋值后,ptemp就相当与头节点,不过只是一个临时变量,程序结束就会释放 // 第二步: 创建节点,赋值 pnode pnew = (pnode)malloc(sizeof(node)); pnew->data = data; //第三步:找到pos的上一个节点 int i = 0; for ( i = 0; i < pos-1; i++)//for循环的第二个条件,小于pos,就循环到pos { ptemp = ptemp->next; } // 第四步:新节点连接到链表中 //4.1 新节点连接到第pos的节点上 pnew->next = ptemp->next;//p->next->next指向pos的下一个节点 //4.2 pos前一个节点(ptemp)的next指向新节点 ptemp->next = pnew; //第五步:返回节点数 (head->data)++; return head->data; }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/********************************************* * 函数名:deleteEnd * 参数: head头节点指针 * 返回值: 删除后的节点个数 * 作用: 在链表中删除最后一个节点 *****************************************************/ int deleteEnd(pnode head) { //第一步:定义临时变量,遍历,判断空 if(IsEmpty(head)) { printf("链表为空,无法删除\n"); return head->data; } pnode ptemp = head; //第二步:找倒数第二个节点 ptemp->next->next == NULL while(ptemp->next->next != NULL) { ptemp = ptemp->next; } //第三步:释放最后一个节点 free(ptemp->next); //第四步:把删除后剩下的最后一个节点的next=NULL; ptemp->next = NULL; //第五步:数据元素个数减1 return --(head->data); }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/********************************************* * 函数名:deleteEnd * 参数: head头节点指针 * 返回值: 删除后的节点个数 * 作用: 在链表中删除最后一个节点 *****************************************************/ int deleteEnd(pnode head) { //第一步:定义临时变量,遍历,判断空 if(IsEmpty(head)) { printf("链表为空没法删除\n"); return head->data; } pnode ptemp = head; //第二步:找倒数第二个节点 ptemp->next->next == NULL while(ptemp->next->next != NULL) { ptemp = ptemp->next; } //第三步:释放最后一个节点 free(ptemp->next); //第四步:把删除后剩下的最后一个节点的next=NULL; ptemp->next = NULL; //第五步:数据元素个数减1 return --(head->data); }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/********************************************* * 函数名: deletePos * 作 用: 删除pos位置的节点 * 参 数: head 链表的头指针 * pos 需要删除的节点位置 * 返回值: 返回链表中的节点个数 **********************************************/ int deletePos(pnode head,int pos) { //判断链表是否为NULL if(IsEmpty(head)) { printf("链表为null没法删除\n"); return head->data; } //第一步:定义临时变量 pnode ptemp = head; pnode pPos = NULL; //第二步:找到pos位置的前一个节点(保存pos位置) for (int i = 0; i < pos -1 ; i++) { ptemp =ptemp->next; if (!ptemp) { printf("\n位置不存在\n"); return head->data; } } pPos = ptemp->next; //保存pos位置指针 //第三步:把pos的前一个位置的next指针指向pos下一个位置。 ptemp->next = pPos->next; //第四步:释放pos位置节点 free(pPos); pPos = NULL; //第五步:节点个数减1(返回节点个数) return --(head->data); }
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在内存如下演示:
/********************************************* * 函数名:findNode * 参数: head头节点指针 * data 需要超找的数据 * 返回值: 如果成功返回找到的data位置的指针 * 如果失败返回NULL * 作用: 在链表中查找data的所在位置。 *****************************************************/ pnode findNode(pnode head,int data) { // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head; int num = 0; //记录data的位置 //第二步:遍历整改链表 while (NULL != ptemp->next ) { ptemp = ptemp->next; num++; //第三步: 比对是否找到 if(ptemp->data == data) { printf("data=%d在%d的位置\n",data,num); return ptemp; } } printf("%d在链表中没找到\n",data); return NULL; }
/********************************************************** * 函数名:changeData * 参数: head头节点指针 * pos 需要修改的数据的位置 * data 需要修改的数据 * 返回值: 如果成功返回ture,失败返回false * 作 用:把链表中pos位置的数据修改成data ***********************************************************/ int changeData(pnode head,int pos,int data) { // 第0步:判断pos是否超过节点个数,节点5,要是head只有4,就没有5节点来改变 if(pos > head->data) { printf("pos超出节点,无法修改\n"); } // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head; int i = 0; //第三步:找到pos节点 for(i=0;i<pos;i++) { ptemp = ptemp->next; } //上面一步一步偏移完之后,ptemp已经遍历到pos位置了就等与pos //第四步:替换数据 ptemp->data = data; //这里最好是弄一个返回值,来返回是否成功,也可以打印出来 return head->data; }
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> /*作 者:pzk 功 能:实现链表的增删查改 *第一个功能:头插法,每次都在头节点的后一个位置插入(链接到头节点上) *第二个功能:尾插法,每次插入都在链表的最后一个节点,使原本指向NULL的最后一个节点指向新节点 *第三个功能:指定位置插入,用for循环,找到指定节点的上一个节点,把新节点插入到指定节点的上一个节点的后面 *第四个功能:改变指定位置的值(也可以用值去查找,把旧值用新值代替,例如我想吧原本存2的指针改为存3) *第五个功能:查找,查找我们想要的值,并返回指定值的位置的指针 */ typedef struct node { int data; struct node * next; }node,*pnode;//node是取别名,pnode是类型,结构体指针类型 //struct node * pnode //创建火车头,初始化函数。返回火车头的指针。 pnode init() { pnode head = (pnode )malloc(sizeof(node)); //用malloc开辟空间,此时pnode == struct node * if(head == NULL)//此时做一个容错判断,如果没有开辟成功,打印错误 { perror("head fault"); } head->data = 0;//开辟空间之后里面是没有值的,最好给数据域和指针域分别赋值 head->next = NULL;//指针没有指向,指向NULL就ok,防止其乱指向 return head;//返回头节点指针,方便我们以后调用 } //第二步:头插法,在头节点的后面插入一个元素 /**************************************************************** * 函数名: insertHead * 参 数: head 链表的头节点指针 * data 需要插入节点数据 * 返回值: 链表中节点个数 * 节点的个数保存在head的data中。 ****************************************************************/ int insertHead(node* head,int data) { //第一步:创建新节点,存入数据 pnode pnew = (pnode )malloc(sizeof(node));//用malloc开辟空间,类型是pnode,大小是一个结构体的大小 if(NULL == pnew)//容错判断新创建的节点是否成功 { perror("head NULL"); exit(0);//不成功就输出错误,然后退出 } pnew->data = data;//把传进来的值赋值给新节点 //第二步:链接新节点到链表头下一个节点,何为链接,无非就是把下个节点的地址赋值给头节点的next; //head的next为空的情况 pnew->next = head->next;//head->next原本存的是第二个节点的地址,现在把它赋值给新节点,那么是不是新节点的下一个就是原先的第二个节点了 //第三步:head不为空,把头节点的next指针指向新的节点 head->next = pnew;//此时,我们在把新节点和头节点链接起来,这样就是头节点指向新节点了,pnew本身就是一个指针 //当第二步赋值的时候,头节点与原先的第二个节点链接自动断开 //第四步:节点个数加一 (head->data)++;//因为我们头节点的数据域存的是节点个数 //第五步:返回头节点中节点数据;a/* */ return head->data; } // 写尾部插入。 int insertEnd(pnode head,int data) { //第一步:定义临时指针 node* ptmep = head; //第二部:遍历链表,找最后一个节点 while( ptmep->next != NULL) { ptmep = ptmep->next;//指针偏移 } //循环完之后,ptemp的next已经为NULL了 //第三步:创建新节点 pnode pnew = (pnode)malloc(sizeof(node));//malloc开辟空间 //第四步:给节点赋值 pnew->data = data; //第五步:新节点插入到链表末尾 pnew->next = NULL;//尾插法,新节点需放在最后,所以新节点后面没有节点了,指向null ptmep->next = pnew;//原最后一个节点指向新节点,那么原最后一个节点就成为了倒数第二个节点 //第六步:返回链表长度 (head->data)++; return head->data;//也可以直接return ++(head->data);一样的效果 } /********************************************************** * 函数名:changeData * 参数: head头节点指针 * pos 需要修改的数据的位置 * data 需要修改的数据 * 返回值: 如果成功返回ture,失败返回false * 作 用:把链表中pos位置的数据修改成data ***********************************************************/ int changeData(pnode head,int pos,int data) { // 第0步:判断pos是否超过节点个数,节点5,要是head只有4,就没有5节点来改变 if(pos > head->data) { printf("pos超出节点,无法修改\n"); } // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head; int i = 0; //第三步:找到pos节点 for(i=0;i<pos;i++) { ptemp = ptemp->next; } //上面一步一步偏移完之后,ptemp已经遍历到pos位置了就等与pos //第四步:替换数据 ptemp->data = data; //这里最好是弄一个返回值,来返回是否成功,也可以打印出来 return head->data; } /********************************************* * 函数名:insert * 参数: head头节点指针 * pos 需要插入的位置 * data 需要插入的数据 * 返回值: 链表的节点个数 * 作用: 在pos的位置插入一个节点 *****************************************************/ int insert(pnode head,int pos,int data) { // 第0步:判断pos是否超过节点个数 if(pos > head->data) { printf("无法插入指定位置,程序退出\n"); exit(0); } // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head;//赋值后,ptemp就相当与头节点,不过只是一个临时变量,程序结束就会释放 // 第二步: 创建节点,赋值 pnode pnew = (pnode)malloc(sizeof(node)); pnew->data = data; //第三步:找到pos的上一个节点 int i = 0; for ( i = 0; i < pos-1; i++)//for循环的第二个条件,小于pos,就循环到pos { ptemp = ptemp->next; } // 第四步:新节点连接到链表中 //4.1 新节点连接到第pos的节点上 pnew->next = ptemp->next;//p->next->next指向pos的下一个节点 //4.2 pos前一个节点(ptemp)的next指向新节点 ptemp->next = pnew; //第五步:返回节点数 (head->data)++; return head->data; } /********************************************* * 函数名:findNode * 参数: head头节点指针 * data 需要超找的数据 * 返回值: 如果成功返回找到的data位置的指针 * 如果失败返回NULL * 作用: 在链表中查找data的所在位置。 *****************************************************/ pnode findNode(pnode head,int data) { // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head; //记录data的位置 int n=0; //第二步:遍历整改链表 //第三步: 比对是否找到 while(ptemp->next != NULL)//当循环到倒数第二个节点时,会先在里面偏移,偏移后对比值 { ptemp = ptemp->next; n = n+1;//记录节点的位置,每偏移一次就加1 if(ptemp->data == data)//如果链表此时位置的值与传进来的指定值一样,就打印出来 { printf("找到了!%d在%d的位置",ptemp->data,n); return ptemp;//返回此时节点的指针,并退出这个函数 } } printf("没找到"); return NULL; } // 判断链表是否为空,如果为空则返回真,否则返回假 bool IsEmpty(pnode head) { if(head->next == NULL)//也可以用头节点的值判断,其值为0说明没有其他节点,判断head是不是指向空也行 { return true; } return false; } /********************************************* * 函数名:deleteEnd * 参数: head头节点指针 * 返回值: 删除后的节点个数 * 作用: 在链表中删除最后一个节点 *****************************************************/ int deleteEnd(pnode head) { //第一步:定义临时变量,遍历,判断空 if(IsEmpty(head)) { printf("链表为空没法删除\n"); return head->data; } pnode ptemp = head; //第二步:找倒数第二个节点 ptemp->next->next == NULL while(ptemp->next->next != NULL) { ptemp = ptemp->next; } //第三步:释放最后一个节点 free(ptemp->next); //第四步:把删除后剩下的最后一个节点的next=NULL; ptemp->next = NULL; //第五步:数据元素个数减1 return --(head->data); } /********************************************* * 函数名: deleteHead * 作 用: 删除第一个数据节点 * 参 数: head 链表的头指针 * 返回值: 返回链表中的节点个数 **********************************************/ int deleteHead(pnode head) { //第0步:先判断是否链表为空 if(IsEmpty(head)) { printf("链表为空,无法删除\n"); return head->data; } //第一步:定义临时变量,保存头的下一个节点 pnode ptemp = head->next; //第二步:头节点的next连接到第二个节点 head->next = head->next->next;// //第三步:释放第一个数据节点 free(ptemp); ptemp->next = NULL;//把ptemp指针指向空,防止其乱指 //第四步:链表节点个数减1 (head->data)--; return head->data; } /********************************************* * 函数名: deletePos * 作 用: 删除pos位置的节点 * 参 数: head 链表的头指针 * pos 需要删除的节点位置 * 返回值: 返回链表中的节点个数 **********************************************/ int deletePos(pnode head,int pos) { //判断链表是否为NULL IsEmpty(head); //第一步:定义临时变量 pnode ptemp = head; pnode pnew; //第二步:找到pos位置的前一个节点(保存pos位置) for(int i=0;i<pos-1;i++) { ptemp = ptemp->next; if (!ptemp) { printf("\n位置不存在\n"); return head->data; } } //保存pos位置指针 pnew = ptemp->next; //第三步:把pos的前一个位置的next指针指向pos下一个位置。 ptemp->next = ptemp->next->next;//把下下个指针赋给自己用pnew操作就是ptemp->next=pnew->next //第四步:释放pos位置节点 free(pnew);//注意pnew->next和pnew是有区别的 pnew->next = NULL; //第五步:节点个数减1(返回节点个数) return --(head->data); } /************************************************ * 函数名: deletePos * 作 用: 对链表进行排序,使用选择排序算法 * 参 数: head 链表的头指针 * * 返回值: 无 ************************************************/ //这个不建议初学者去玩,学好增删查改就很ok了,一定要自己多敲代码 void LinkSort(pnode head) { //第一步:定义临时变量 pnode ptemp = head; pnode p = head; int temp = 0;//用于交换两个变量 while(ptemp->next != NULL) { ptemp = ptemp->next; p = ptemp; while(p->next) { p = p->next; if (p->data < ptemp->data) { temp = ptemp->data; ptemp->data = p->data; p->data = temp; } } } } void show(pnode head) { printf("链表有%d个节点\n",head->data);//因为我们的头节点的data存的是节点个数 // 第一步:定义临时变量,用来遍历到每个节点 pnode ptemp = head; //第二步:判断是否为最后一个节点 while(ptemp->next != NULL)//如果头节点->next为空,那么此时就是一个空链表,后面没有节点 { //第三步:寻找下一个节点 ptemp = ptemp->next;//这个地方可以自己思考理解一下,是怎么实现的 //原理很简单,ptemp->next原本是ptemp的下一个节点,这么一赋值,ptemp自动往右边移了一个节点 printf("%d-->",ptemp->data);//打印的时候,指针需要用->来操作,结构体的话可以不是指针类型可以用点操作,ptemp.data,结构体指针不能这么用 } printf("NULL\n"); } int main() { pnode head = init(); //头部插入5个元素 int i = 0; for(i=0;i<3;i++) { insertHead(head,i*10); } //尾部插入5个元素 for(i=0;i<3;i++) { insertEnd(head,i*100); } show(head); //changeData(head,5,6666); //show(head); //insert(head,6,9999); //show(head); //findNode(head,6666); //deleteHead(head); //deleteEnd(head); deletePos(head,2); show(head); return 0; }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。