单链表基本操作详解
2016-06-04 22:12
453 查看
# 单链表
文中提到的内容的链接一并列在这里:单链表详细分析的博客链接:http://blog.csdn.net/bitboss/article/details/51586293
顺序表:http://blog.csdn.net/bitboss/article/details/51559175
冒泡排序:http://blog.csdn.net/bitboss/article/details/51559034
选择排序:http://blog.csdn.net/bitboss/article/details/51576143
插入排序:http://blog.csdn.net/bitboss/article/details/51576115
@ 昨天用6个小时将单链表初步成型,那么说好的高质版就在今天完成!
@ 首先,因为前面实现过顺序表,就先来说说顺序表和单链表的区别吧!(画图功底太差,本篇无插图)
@ 顺序表存储位置是相邻连续的,可以随即访问的一种数据结构,一个顺序表在使用前必须指定起长度,一旦分配内存,则在使用中不可以动态的更改。他的优点是访问数据是比较方便,可以随即的访问表中的任何一个数据。
@ 链表是通过指针来描述元素关系的一种数据结构,他可以是物理地址不连续的物理空间。不能随即访问链表元素,必须从表头开始,一步一步搜索元素。它的优点是:对于数组,可以动态的改变数据的长度,分配物理空间。
@ 在使用中:如果一个数组在使用中,查询比较多,而插入,删除数据比较少,数组的长度不变时,选顺序表比较合理。如果插入,删除,长度不定的数组,可以选链表。
# 我在这篇文章将函数功能一个一个列出来单独说明,最后将全部综合在一起列出来;
先将自定义的头文件包含一些函数的声明列出来,还有主函数包含测试部分,请先看这部分,方便理解后面的内容!
代码中包含部分注释!!!
@ “LinkList.h”
#define _CRT_SECURE_NO_WARNINGS 1//消除scanf的警告! #ifndef __LINKLIST_H__//防止头文件的重定义 #define __LINKLIST_H__ //将所有引入的头文件都放到自定义的头文件中即可! #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int DataType;//将int重命名,方便修改,如果元素是char只需要将int改为char; enum Select//将所有选项用枚举表现出来,方便阅读;很有必要的操作,增强代码的可读性; { EXIT, INSERT, PRINT, REMOVE, REMOVEALL, SEARCH, SORT, PUSHF, PUSHB, POPF, POPB, DOSTORY, EASER, }; typedef struct LinkNode { DataType data; struct LinkNode* next; }LinkNode,*pLinkNode;//结点结构体 typedef struct LinkList//将头指针单独封装一个结构体方便使用! { LinkNode* pHead;//头结点指针 }LinkList ,*pLinkList;//链表 void InitLinkList(pLinkList pList);//初始化列表 void PrintList(pLinkList pList);//打印 void DostoryList(pLinkList pList);//free链表 void PopBack(pLinkList pList);//尾删 void PopFront(pLinkList pList);//头删 void PushBack(pLinkList pList,DataType x);//尾插 void PushFront(pLinkList pList,DataType x);//头插 void Insert(pLinkList pList,pLinkNode pos,DataType x);//指定位置前或者后插入元素 pLinkNode Find(pLinkList pList,DataType x);//查找 void Search(pLinkList pList,DataType x);//查找指定元素; void Remove(pLinkList pList,DataType x);//删除指定元素 void RemoveAll(pLinkList pList,DataType x);//删除所有出现的指定元素 void Erase(pLinkList pList,pLinkNode pos);//删除指定位置的元素 void BubbleSort(pLinkList pList);//冒泡排序链表元素 void Exit(pLinkList pList); #endif //__LINKLIST_H__
@ test.c
#include"LinkList.h" //注意:请仔细阅读自定义头文件"LinkList.h"的内容!!! //打印菜单这个,主要看自己喜好,设计的好看一点总是没问题的; //注意的是你每次进行选择一个操作前都要打印一次菜单! void Print() { printf("\n————————————————————\n"); printf("***************************************\n"); printf("**** 0.退出 ******\n"); printf("**** 1. 插入元素 ******\n"); printf("**** 2. 打印链表 ******\n"); printf("**** 3. 删除指定元素 ******\n"); printf("**** 4. 删除所有出现的指定元素 ******\n"); printf("**** 5. 查找 ******\n"); printf("**** 6. 排序 ******\n"); printf("**** 7. 头插 ******\n"); printf("**** 8. 尾插 ******\n"); printf("**** 9. 头删 ******\n"); printf("**** 10. 尾删 ******\n"); printf("**** 11. 释放链表 ******\n"); printf("**** 12. 删除指定位置的元素 ******\n"); printf("***************************************\n"); printf("\n————————————————————\n"); } void test() { LinkList List;//定义一个LinkList类型的结构体; int select = 0;// 接收的选择用select保存 DataType x = 0;//指定插入或者删除的元素用x保存 DataType pos = 0;//用来接收指定位置的信息, //但是注意,使用时的pos真正的类型确实调用Find函数的返回值 InitLinkList(&List);//真正开始操作前先将List初始化;这一步着为重要! while(1)//设置为死循环的目的在于不断地进行功能选择; { Print();//打印菜单 printf("请输入选项:> "); scanf("%d",&select); //这里需要说明的是调用函数是对链表List都是传址操作; //关于传址和传值的问题一定要搞清楚! switch(select)//判断选项;对于选项过多的情况下switch 其实并不是那么好用, { //大家想想如何改进; case EXIT: Exit(&List);//退出; break; case INSERT://插入成员; printf("请输入要在哪一个位置前插入:> "); scanf("%d",&pos); printf("请输入要插入的元素:> "); scanf("%d",&x); Insert (&List,Find(&List,pos),x); break; case PRINT://打印链表 PrintList(&List); break; case REMOVE://删除指定成员 printf("请输入指定删除元素:> "); scanf("%d", &x); Remove(&List,x); break; case REMOVEALL://删除找到的所有指定元素; printf("请输入指定删除元素:> "); scanf("%d", &x); RemoveAll(&List,x); break; case SEARCH://查找指定成员; printf("请输入指定查找元素:> "); scanf("%d", &x); Search(&List,x); break; case SORT://这里只采用冒泡排序; BubbleSort(&List); break; case PUSHF://头插; printf("请输入要插入的元素:> "); scanf("%d",&x); PushFront (&List,x); break; case PUSHB://尾插; printf("请输入要插入的元素:> "); scanf("%d",&x); PushBack (&List,x); break; case POPF://头删; PopFront (&List); break; case POPB://尾删 PopBack (&List); break; case EASER://删除指定位置的元素; printf("请输入指定位置元素:>\n"); scanf("%d",&pos); Erase(&List,Find(&List,pos));//注意这里的参数!!! break; case DOSTORY://释放顺序表内存; DostoryList (&List); break; default://处理异常选项输入; printf("the select is default!\n"); break; } } } int main() { test(); system("pause"); return 0; }
******************************那么下面开始分布讲解*****************************************************
/* pLinkNode AddMemory():新增节点开辟空间!
为什么要把新增结点包装成一个函数呢,其实很简单,你想想看,
你的代码里面好多地方都用到了这样同样的代码,那你岂不是要把这同样的代码写好几遍,
不但浪费了时间,而且让代码看起来很臃肿,你难道不想让你的代码看起来更清爽吗?
# 注意: 返回值类型!
# 注意: 要了解malloc的函数功能和参数;
# 注意: 对是否开辟成功要做判断,要不然可是很危险的!
*/
pLinkNode AddMemory() { pLinkNode newNode = (pLinkNode)malloc(sizeof(LinkNode )); if(newNode == NULL) { printf("out of memory\n"); exit(0); } return newNode ; }
/* pLinkNode Find(pLinkList pList,DataType x)//只找出第一次出现的x
公用的查找函数,就是给定一个成员,我现在要你找到他,因为是公用的函数嘛,就不打印了,
让它返回该成员的地址即可! 比如 功能里面有一个Serch,就可以直接通过调用Find函数实现!
# 注意:函数是有返回值的,返回值类型为NULL;
*/
<span style="color:#000000;">pLinkNode Find(pLinkList pList,DataType x)//只找出第一次出现的x { pLinkNode cur = NULL; assert(pList); cur = pList ->pHead ; while(cur) { if(cur->data == x) break; cur = cur->next ; } return cur; }//公用的查找函数 </span>
/* void InitLinkList(pLinkList pList)
初始化链表,简单的说,就是我现在要有一个链表,
那好,我给你个头节点,现在里面都没放,你自己想放什么就自己拿去用吧!
有没有感觉像你老爸给了你一张银行卡,密码告诉你了,让你随便用!哈哈,感觉很霸气吧!
# 注意:在测试部分,千万不要忘记调用初始化函数,后果很可怕! 很吓人吧!
*/
<span style="color:#000000;">void InitLinkList(pLinkList pList) { assert(pList); pList->pHead = NULL; }//初始化列表 </span>
/* void PrintList(pLinkList pList):打印链表
这个打印链表写起来很简单,我建议同学们一般将这个函数写的早一点,
写这种功能比较多的代码时,最好完成一个功能就调试一下,这样可以避免
写完之后看到一大堆错误,看都看不下去了,毕竟人无完人;很实用的方法!
# 注意: 打印链表的时候千万得注意循环的条件,不要非法访问了内存,很头痛的!
# 注意: assert 的使用只在这里强调一次,这是一个良好的编程习惯,有时还比if语句好用;
# 注意: const的使用也很有必要,在这里我暂时没使用,很冷吧!
*/
<span style="color:#000000;">void PrintList(pLinkList pList) { pLinkNode cur = NULL; assert(pList); cur = pList->pHead ; while( cur!=NULL ) { printf("%d->",cur->data ); cur = cur->next ; } printf("over\n"); }//打印 </span>
void DostoryList(pLinkList pList):
释放单链表 正所谓有借有还,再借不难;多么经典的人生哲理啊,内存是计算机的,我们既然要为单链表开辟内存,
那就要向计算机借内存,那好了,你用了之后就不还了,是不是很没品啊,如果大家都借了不还,你想想 内存能有多
少;是不是很可怕;所以咱们嘛,优秀的程序员嘛,有借有还,避免内存泄漏! 是不是有的 同学想说,刚才你还讲
老爸给的银行卡呢! 可是那是前话,这是后话,哈哈!
# 注意:malloc是从堆上开辟空间的(所以本来就少的可怜,类似的还有realloc,之类的,大家可以了解,后期我会整
理);
# 注意: 当然,在这里又要说一个编程习惯,你把钱还了之后,是不是得在你的小账本上标记一下,这笔钱我已经还
了, 内存也一样,free之后,再置空,告诉计算机,我已经还了! 牛叉吧!*/
<span style="color:#000000;">void DostoryList(pLinkList pList) { pLinkNode cur = NULL; pLinkNode tmp = NULL; assert(pList); cur = pList->pHead ; if(pList ->pHead == NULL) return; while(cur) { tmp = cur->next ; free(cur); cur = NULL; cur = tmp; } pList ->pHead = NULL; } </span>
/* void PushFront(pLinkList pList,DataType x): 头插法;
头插法,望文生义,语文不是体育老师教的同学应该都能看出来,就是从头部插入一个元素,
那么,岂不是很简单了,既然我们有头指针,那么在头指针后面加入一个结点,将新增元素
放到新节点的data里,而新节点的next部分就存放原本头节点的内容了!而头指针就指向我
新插入的节点了,反正我就是排头!管你链表里有没有元素我就是蛮横里的往里插,任性吧!
@ 其实C语言里就是变量必须定义在代码块的最开始,这个其实很蛋疼的,如果可以把这个改进的
话,C就完美了,不知道有没有同样感觉的!(个人吐槽)
# 注意: 增加成员就要开辟空间,调用AddMemory();
# 注意: 别忘了将新成员x放入新节点newNode;
# 注意: 头指针一定得指向我的newNode;
*/
<span style="color:#000000;">void PushFront(pLinkList pList,DataType x) { pLinkNode cur = NULL; pLinkNode newNode = AddMemory();//只要增加新成员就得开辟空间,顶住的话就不多说了! assert(pList); cur = pList ->pHead ; newNode ->data = x; newNode ->next = cur; pList ->pHead = newNode ; }//头插 </span>
/* void PushBack(pLinkList pList,DataType x):尾插法
尾插法不用我望文生义了吧! 看谁不爽,就让谁当吊车尾! 当然,不太形象啊!
反正我就是想把你放在最后一名; 等等,要让新成员是最后一名,那么是不是得看看
以前的最后一名是谁了,找到以前的吊车尾,然后将新成员放在它后面,就OK了!
同样,得先为新成员开辟一个空间,然后将x放进去,newNode的next理所当然的为KUNN,
因为newNode后面没人了人嘛! 然后让上一个吊车尾记住新成员的位置,即将新成员
加入到链表里! 我的画图功底差,所以嘛!只能靠着三寸不烂之舌来讲了,讲的不好的
请多多包涵!
# 注意:如果链表为空,则需要单独处理,让pHead直接指向newNode;
# 注意:如果链表不为空,则需要找到并记住最后一个成员的地址,让它的next保存newNode;
*/
<span style="color:#000000;">void PushBack(pLinkList pList,DataType x) { pLinkNode cur = NULL; pLinkNode pvr = NULL; pLinkNode newNode = AddMemory(); assert(pList); cur = pList ->pHead ; newNode ->data = x; newNode ->next = NULL; if(cur == NULL) { pList ->pHead = newNode ; return; } while(cur) { pvr = cur; cur = cur->next ; } pvr->next = newNode ; }//尾插 </span>
/* void PopFront(pLinkList pList): 头删
头删,和头插一样任性,就是要将第一个成员删了,不管你是谁;
# 注意: 如果链表为空,直接返回,删无可删!
# 注意: 如果链表不为空,就要将第二个人成员的地址保存到头指针里;
就是将第一个成员的next的内容赋给phead;
其实,大家应该已经看出来链表的优点了,不管是删还是插,都不容一个一个挪动所有成员了;
在通讯录的模拟中,使用顺序表的弊端就在这里,大家可以好好体会一下两者的区别!
*/
<span style="color:#000000;">void PopFront(pLinkList pList) { pLinkNode cur = NULL; assert(pList); cur = pList ->pHead ; if(cur == NULL) return; pList->pHead = cur->next; free(cur); cur = NULL; }//头删 </span>
/* void PopBack(pLinkList pList): 尾删
尾删,删除链表的最后一个成员;我觉得我这句解释都是多余,侮辱了各位的智商,自我反省一会!
# 注意: 类似于尾插,要找到并且记住最后一个成员的地址;具体实现理解代码,解释多了也不好!
# 注意: 这个注意应该不冗余吧! 删了之后是不是得把内存还回去? 别怪我多嘴!
*/
<span style="color:#000000;">void PopBack(pLinkList pList) { pLinkNode cur = NULL; pLinkNode pvr = NULL; assert(pList); cur = pList->pHead ; if(pList ->pHead ==NULL) return; else if(cur ->next == NULL) { pList->pHead = cur->next; free(cur); cur = NULL; } else { while(cur->next) { pvr = cur; cur = cur->next ; } free(cur); pvr->next = NULL; } } </span>
/* void Insert(pLinkList pList,pLinkNode pos,DataType x):将指定元素插入到指定位置前
这个函数嘛,其实有点那啥,你们都懂!在这里我只实现了在指定位置前插入成员,之后的
位置类似;如果你有好好看test.c部分,那么就会发现,这个函数调用的时候,pLinkNode pos
这个参数是通过Find函数的返回值传过来的,为什么呢,其实也是无聊,通过找到指定位置后,
传过来地址,Insert函数在通过这个地址找到这个位置,在它前面插入一个元素,因为没有对
链表中重复元素做处理,所以可以类似于,在指定元素前插入一个新成员!
# 注意:要判断所给位置是否有效,判断Find函数的返回值!
*/
<span style="color:#000000;">void Insert(pLinkList pList,pLinkNode pos,DataType x) {//将指定元素插入到指定位置前, 插入指定位置后类似; pLinkNode cur = NULL; pLinkNode pvr = NULL; DataType tmp = x; pLinkNode newNode = AddMemory(); newNode ->data = tmp; assert(pList); cur = pList ->pHead ; if(cur == NULL) { PushFront (pList,x); return ; } if(pos == NULL) { printf("default locate!\n"); return; } newNode ->next = pos->next ; pos->next = newNode ; tmp = pos->data ; pos->data = newNode ->data ; newNode ->data = tmp; }//指定位置前或者后插入元素 </span>
/* void Search(pLinkList pList,DataType x):查找指定成员
前面介绍Find的时候已经提到了,我就不多说了,直接调用Find;
# 注意: 要接收Find的返回值,并进行判断;
*/
<span style="color:#000000;">void Search(pLinkList pList,DataType x) { pLinkNode cur = NULL; assert(pList); cur = Find(pList, x); if(cur == NULL) printf("the x wasn't searched!\n"); else printf("the search of result:> %d\n",cur->data ); }//查找指定元素; </span>
/* void Remove(pLinkList pList,DataType x)//只删除第一个匹配到的元素;
删除指定元素,这个函数只删除一个,
比如:我的单链表现在是 1->2->3->1->over;指定删除1;则变成2->3->1;
后面那个RemoveRll函数则是删除找到的所有指定元素,
比如我的单链表现在有 1->2->3->1->over;现在指定删除1,那么就会变成 2->3-over;
其实嘛,这里可以直接调用一下Find函数,再加上一些限定条件就可以了,不过为了不让你们
有翻上去找,我就重新写了;
# 注意:判断三种情况,链表尾空,链表只有一个元素,和两个以上元素的三种情况!
# 注意: 我这里直接调用了头删和尾删函数,既然写了干嘛放着不用!
*/
<span style="color:#000000;">void Remove(pLinkList pList,DataType x)//只删除第一个匹配到的元素; { pLinkNode cur = NULL; assert(pList); cur = pList ->pHead ; while(cur) { if(cur->data == x) { if(cur == pList ->pHead ) PopFront ( pList); else if(cur->next == NULL ) PopBack ( pList); else { pLinkNode tmp = NULL; cur->data = cur->next ->data ; tmp = cur->next ; cur->next = cur->next ->next ; free(tmp); tmp = NULL; } printf("\n Delete success!\n"); return; } cur = cur->next ; } printf("\nThe list haven't exist x!\n"); }//删除指定元素 </span>
/* void RemoveAll(pLinkList pList,DataType x):删除所有找到的指定元素
在说Remove的时候顺便说了这个函数,在这里就不继续啰嗦了!
# 注意: 删除第一个找到的成员后,要继续从当前位置往后找,知道链表结束!
# 注意: 在这里设置标志flag的意思是如果有找的x,循环结束后就输出 删除成功!
若是没有一个x可以删除,就输出链表没有该元素!同样可以试着调用Find函数实现!
*/
<span style="color:#000000;">void RemoveAll(pLinkList pList,DataType x) { pLinkNode cur = NULL; pLinkNode pon = NULL; int flag = 0; assert(pList); cur = pList ->pHead ; while(cur) { if(cur->data == x) { flag = 1; pon = cur->next ; if(cur == pList ->pHead ) { PopFront ( pList); cur = pon; } else if(cur->next == NULL ) { PopBack ( pList); cur = NULL; break; } else { pLinkNode tmp = NULL; cur->data = cur->next ->data ; tmp = cur->next ; cur->next = cur->next ->next ; free(tmp); tmp = NULL; } } else cur = cur->next ; } if(flag == 1) printf("\n Delete success!\n"); else printf("\nThe list haven't exist x!\n"); }//删除所有出现的指定元素 </span>
/* void Erase(pLinkList pList,pLinkNode pos):删除指定位置的元素;
这个和Isert类似,关于参数我就不多讲了;
*/
<span style="color:#000000;">void Erase(pLinkList pList,pLinkNode pos) { pLinkNode cur = NULL; pLinkNode pvr = NULL; assert(pList); cur = pList ->pHead ; if(pos == NULL) { printf("\nThe list haven't exist x!\n"); return ; } else if(pos == cur) { PopFront (pList); return ; } while(cur != pos) { pvr = cur; cur = cur->next ; } pvr->next = pos->next ; free(pos); pos = NULL; }//删除指定位置的元素 </span>
/* void BubbleSort(pLinkList pList)//冒泡排序单链表
关于排序单链表的问题,我只实现了冒泡排序,在顺序表中,我用了三种排序方法
星星排序,对于这里的冒泡排序,我也有专门的文章介绍,本质都是一样的,
重点在于控制循环的条件,所以请认真理解下面的代码!
纠正个错误,我这里写成了选择排序!
*/
<span style="color:#000000;">void BubbleSort(pLinkList pList)//冒泡排序单链表 { pLinkNode p = NULL; pLinkNode q = NULL; assert(pList); for(p = pList ->pHead ;p!=NULL; p = p->next ) { for(q = p->next;q!=NULL; q = q->next ) { if(p->data > q->data ) { DataType tmp = q->data ; q->data = p->data ; p->data = tmp; } } } }//冒泡排序链表元素 </span>
**************************************所有集合 LinkList.c***************************************
<span style="color:#000000;">#include"LinkList.h"//引入自定义的头文件,细心的你千万别忘记;
pLinkNode AddMemory() { pLinkNode newNode = (pLinkNode)malloc(sizeof(LinkNode )); if(newNode == NULL) { printf("out of memory\n"); exit(0); } return newNode ; }
pLinkNode Find(pLinkList pList,DataType x)//只找出第一次出现的x
{
pLinkNode cur = NULL;
assert(pList);
cur = pList ->pHead ;
while(cur)
{
if(cur->data == x)
break;
cur = cur->next ;
}
return cur;
}//公用的查找函数
void InitLinkList(pLinkList pList)
{
assert(pList);
pList->pHead = NULL;
}//初始化列表
void PrintList(pLinkList pList)
{
pLinkNode cur = NULL;
assert(pList);
cur = pList->pHead ;
while( cur!=NULL )
{
printf("%d->",cur->data );
cur = cur->next ;
}
printf("over\n");
}//打印
void DostoryList(pLinkList pList)
{
pLinkNode cur = NULL;
pLinkNode tmp = NULL;
assert(pList);
cur = pList->pHead ;
if(pList ->pHead == NULL)
return;
while(cur)
{
tmp = cur->next ;
free(cur);
cur = NULL;
cur = tmp;
}
pList ->pHead = NULL;
}
//free链表
void PushFront(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode newNode = AddMemory();//只要增加新成员就得开辟空间,顶住的话就不多说了!
assert(pList);
cur = pList ->pHead ;
newNode ->data = x;
newNode ->next = cur;
pList ->pHead = newNode ;
}//头插
void PushBack(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode pvr = NULL;
pLinkNode newNode = AddMemory();
assert(pList);
cur = pList ->pHead ;
newNode ->data = x;
newNode ->next = NULL;
if(cur == NULL)
{
pList ->pHead = newNode ;
return;
}
while(cur)
{
pvr = cur;
cur = cur->next ;
}
pvr->next = newNode ;
}//尾插
void PopFront(pLinkList pList)
{
pLinkNode cur = NULL;
assert(pList);
cur = pList ->pHead ;
if(cur == NULL)
return;
pList->pHead = cur->next;
free(cur);
cur = NULL;
}//头删
void PopBack(pLinkList pList)
{
pLinkNode cur = NULL;
pLinkNode pvr = NULL;
assert(pList);
cur = pList->pHead ;
if(pList ->pHead ==NULL)
return;
else if(cur ->next == NULL)
{
pList->pHead = cur->next;
free(cur);
cur = NULL;
}
else
{
while(cur->next)
{
pvr = cur;
cur = cur->next ;
}
free(cur);
pvr->next = NULL;
}
}
//尾删
void Insert(pLinkList pList,pLinkNode pos,DataType x)
{//将指定元素插入到指定位置前, 插入指定位置后类似;
pLinkNode cur = NULL;
pLinkNode pvr = NULL;
DataType tmp = x;
pLinkNode newNode = AddMemory();
newNode ->data = tmp;
assert(pList);
cur = pList ->pHead ;
if(cur == NULL)
{
PushFront (pList,x);
return ;
}
if(pos == NULL)
{
printf("default locate!\n");
return;
}
newNode ->next = pos->next ;
pos->next = newNode ;
tmp = pos->data ;
pos->data = newNode ->data ;
newNode ->data = tmp;
}//指定位置前或者后插入元素
void Search(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
assert(pList);
cur = Find(pList, x);
if(cur == NULL)
printf("the x wasn't searched!\n");
else
printf("the search of result:> %d\n",cur->data );
}//查找指定元素;
void Remove(pLinkList pList,DataType x)//只删除第一个匹配到的元素;
{
pLinkNode cur = NULL;
assert(pList);
cur = pList ->pHead ;
while(cur)
{
if(cur->data == x)
{
if(cur == pList ->pHead )
PopFront ( pList);
else if(cur->next == NULL )
PopBack ( pList);
else
{
pLinkNode tmp = NULL;
cur->data = cur->next ->data ;
tmp = cur->next ;
cur->next = cur->next ->next ;
free(tmp);
tmp = NULL;
}
printf("\n Delete success!\n");
return;
}
cur = cur->next ;
}
printf("\nThe list haven't exist x!\n");
}//删除指定元素
void RemoveAll(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode pon = NULL;
int flag = 0;
assert(pList);
cur = pList ->pHead ;
while(cur)
{
if(cur->data == x)
{
flag = 1;
pon = cur->next ;
if(cur == pList ->pHead )
{
PopFront ( pList);
cur = pon;
}
else if(cur->next == NULL )
{
PopBack ( pList);
cur = NULL;
break;
}
else
{
pLinkNode tmp = NULL;
cur->data = cur->next ->data ;
tmp = cur->next ;
cur->next = cur->next ->next ;
free(tmp);
tmp = NULL;
}
}
else
cur = cur->next ;
}
if(flag == 1)
printf("\n Delete success!\n");
else
printf("\nThe list haven't exist x!\n");
}//删除所有出现的指定元素
void Erase(pLinkList pList,pLinkNode pos)
{
pLinkNode cur = NULL;
pLinkNode pvr = NULL;
assert(pList);
cur = pList ->pHead ;
if(pos == NULL)
{
printf("\nThe list haven't exist x!\n");
return ;
}
else if(pos == cur)
{
PopFront (pList);
return ;
}
while(cur != pos)
{
pvr = cur;
cur = cur->next ;
}
pvr->next = pos->next ;
free(pos);
pos = NULL;
}//删除指定位置的元素
void BubbleSort(pLinkList pList)//冒泡排序单链表
{
pLinkNode p = NULL;
pLinkNode q = NULL;
assert(pList);
for(p = pList ->pHead ;p!=NULL; p = p->next )
{
for(q = p->next;q!=NULL; q = q->next )
{
if(p->data > q->data )
{
DataType tmp = q->data ;
q->data = p->data ;
p->data = tmp;
}
}
}
}//冒泡排序链表元素
void Exit(pLinkList pList)
{
DostoryList(pList);//退出的时候最好调用一次释放内存函数,
//当然作为一个优秀的程序员,你不会忘记这一步,而造成内存泄漏;
exit(0);
}
</span>
还是蛮累的,写的,希望可以帮助到你!
相关文章推荐
- 探索PowerShell (二) PowerShell的基本操作
- C#定义并实现单链表实例解析
- C#数据结构之单链表(LinkList)实例详解
- C语言实现单链表逆序与逆序输出实例
- C语言单链表常见操作汇总
- SQLite数据库安装及基本操作指南
- C数据结构之单链表详细示例分析
- javascript 学习笔记(一)DOM基本操作
- C++中单链表的建立与基本操作
- 深入单链表的快速排序详解
- Unity3D获取当前键盘按键及Unity3D鼠标、键盘的基本操作
- C语言创建和操作单链表数据结构的实例教程
- MySQL学习第五天 MySQL数据库基本操作
- C#中Linq查询基本操作使用实例
- C语言单链表的实现
- C++二叉树结构的建立与基本操作
- javascript dom 基本操作小结
- java实现单链表中是否有环的方法详解
- java实现单链表、双向链表