您的位置:首页 > 其它

单链表基本操作详解

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>


还是蛮累的,写的,希望可以帮助到你!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息