无头结点单链表的逆置_无头结点的单链表(C语言)

这篇博客详细介绍了如何使用C语言实现无头结点的单链表,包括链表的定义、单链表的操作如头插法、尾插法、头删和尾删,以及查找、插入、删除指定元素的功能。同时,提供了相应的源代码示例和测试代码,便于理解和实践。
摘要由CSDN通过智能技术生成

1.单链表:

在顺序表中,用一组地址连续的存储单元来一次存放线性表的结点,因此结点的逻辑顺序与物理顺序是一致的。但链表却不同,链表是用一组任意的存储单元来存放 线性表的结点,这组存储单元可以是连续的,也可以是非连续的,甚至是零散分布在内存的任何位置上。因此,链表中结点的逻辑顺序与物理顺序不一定相同。为了正确表示节点间的逻辑关系,必须在存储线性表的每个数据元素的同时,存储指示其后继结点的地址信息,这两部分信息共同构成了单链表结点的结构,如下图:

cbb2aa63193686938077374534139a68.png

结点包括两个域,数据域用来存放结点的值,指针域用来存储数据元素的直接后继的地址(或位置)。线性表正是通过每个结点的指针域将线性表的n个结点按其逻辑顺序连接在一起的。由于此线性表的每个节点只有一个next指针域,故将这种链表叫做单链表。

由于单链表中的每一个结点除了第一个节点外,它们的存储地址存放在其前驱结点的指针域中,由于第一个节点无前驱,所以应该设一个头指针指向第一个节点,本文中设置了first指针指向第一个结点。单链表中的最后一个节点无直接后继,所以指定单链表的最后一个结点的指针域为"空"(NULL)。

一般情况下,使用链表,只关心链表中结点的逻辑顺序,并不关心每个结点的实际存储位置,因此通常用箭头来表示链域中的指针,于是链表就可以更直观地画成用箭头链接起来的结点序列,如图:

387cc1aa95a471219a5c7dcff5d0bf7e.png  有时候,为了操作的统一方便,可以在单链表的第一个结点前附设一个头结点,头结点的数据域可以存储一些关于线性表的长度等附加信息,也可以不存储任何信息,对头结点的数据域无特别规定,而头结点的指针域用来存储指向第一个结点的指针(即第一个结点的存储位置)。如果线性表为空,则头结点的指针域为"空"。如图所示:

a907ffd8280556a9463ff4fcd11f3a69.png    

7533525c3e8fff737fe6cc6c9065a3dd.png

2.单链表操作:

头插过程:

2723b8a84cf9406f8d9e808663016d19.png

头插的方式如上图所示。采用头插法得到的单链表的逻辑顺序与输入元素顺序相反,亦称头插法为逆序建表法。在这只介绍头插法的示意图,对于尾插、头删、尾删、可以参考《数据结构----用C语言描述》(耿国华主编)这本书。下面的代码中,实现了头插、尾插、头删、尾删,读者可以仔细研究研究。(本文所编写的代码是在VS2013编译环境下运行的)

3.运行代码:

Linklist.h文件包括各个操作函数的声明以及包含的头文件,test.c包含了测试代码,Linklist.c文件里主要是各个操作函数的具体实现。

1 //Linklist.h

2 #pragma once

3 #include

4 #include

5 #include

6

7 typedef intLDataType;8 typedef structLinklist9 {10 LDataType data;11 struct Linklist *next;12 }Linklist, *pLinklist;13

14 //接口函数

15 pLinklist BuyNewNode(LDataType data);//动态生成新节点

16 void InitLinklist(pLinklist *pL);//初始化单链表

17 void PushBackLinklist(pLinklist *pL, LDataType data);//尾插

18 void PushFrontLinklist(pLinklist *pL, LDataType data);//头插

19 void PopBackLinklist(pLinklist *pL);//尾删

20 void PopFrontLinklist(pLinklist *pL);//头删

21 void PrintLinklist(Linklist *pL);//打印单链表

22 pLinklist FindLinklist(pLinklist *pL, LDataType data);//查找指定元素,返回指定元素的位置

23 void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data);//指定位置插入

24 void RemoveLinklist(pLinklist *pL, LDataType data);//删除第一个指定元素

25 void RemoveAllLinklist(pLinklist *pL, LDataType data);//删除所有的指定元素

26 int IsEmptyLinklist(pLinklist pL);//判断链表是否为空,为空返回1;不为空返回0;

27 void DestoryLinklist(pLinklist *pL);//销毁单链表

1 //Linklist.c

2 #include"Linklist.h"

3 pLinklist BuyNewNode(LDataType data)//生成新节点

4 {5 pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist));6 if (NewNode ==NULL)7 {8 printf("动态开辟内存空间失败\n");9 return;10 }11 NewNode->data =data;12 NewNode->next =NULL;13 returnNewNode;14 }15 void InitLinklist(pLinklist *pL)//初始化

16 {17 assert(pL !=NULL);18 (*pL) =NULL;19 }20 void PushBackLinklist(pLinklist *pL, LDataType data)//尾插

21 {22 assert(pL !=NULL);23 pLinklist NewNode =BuyNewNode(data);24 if (*pL ==NULL)25 {26 *pL =NewNode;27 return;28 }29 pLinklist cur = *pL;30 while (cur->next)31 {32 cur = cur->next;33 }34 cur->next =NewNode;35 }36 void PushFrontLinklist(pLinklist *pL, LDataType data)//头插

37 {38 assert(pL !=NULL);39 pLinklist NewNode =BuyNewNode(data);40 if (*pL ==NULL)41 {42 *pL =NewNode;43 return;44 }45 NewNode->next = *pL;46 *pL =NewNode;47 }48 int IsEmptyLinklist(pLinklist pL)//判断是否为空链表

49 {50 if (pL ==NULL)51 return 1;52 return 0;53 }54 void PopBackLinklist(pLinklist *pL)//尾删

55 {56 assert(pL !=NULL);57 if (IsEmptyLinklist(*pL))//链表为空,没有节点

58 {59 printf("链表为空,删除操作失败\n");60 return;61 }62 pLinklist cur = *pL;63 pLinklist pre = NULL;//保存cur的前一个节点

64 if (cur->next == NULL)//有一个节点

65 {66 *pL =NULL;67 free(cur);68 cur =NULL;69 return;70 }71 while (cur->next)72 {73 pre =cur;74 cur = cur->next;75 }76 pre->next =NULL;77 free(cur);78 cur =NULL;79 }80 void PopFrontLinklist(pLinklist *pL)//头删

81 {82 assert(pL !=NULL);83 if (*pL ==NULL)84 {85 printf("链表为空,删除操作失败\n");86 return;87 }88 pLinklist cur = *pL;89 *pL = cur->next;90 free(cur);91 cur =NULL;92 }93 pLinklist FindLinklist(pLinklist *pL, LDataType data)//查找指定元素,返回指定元素的位置

94 {95 assert(pL !=NULL);96 pLinklist cur = *pL;97 while(cur)98 {99 if (cur->data ==data)100 {101 returncur;102 }103 cur = cur->next;104 }105 returnNULL;106 }107 void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data)//指定位置前面插入

108 {109 assert(pL !=NULL);110 pLinklist NewNode =BuyNewNode(data);111 pLinklist cur = *pL;112 while (cur->next !=p)113 {114 cur = cur->next;115 }116 NewNode->next =p;117 cur->next =NewNode;118 }119 void RemoveLinklist(pLinklist *pL, LDataType data)//删除第一个指定元素

120 {121 assert(pL !=NULL);122 pLinklist cur =NULL;123 pLinklist p = *pL;124 pLinklist pre =NULL;125 cur = FindLinklist(pL, data);//找到要删除的指定元素

126 if (cur ==NULL)127 {128 printf("没找到要删除的指定元素,删除失败\n");129 return;130 }131 if (*pL == cur)//位于第一个节点

132 {133 *pL= cur->next;134 free(cur);135 cur =NULL;136 return;137 }138 while (p!=cur)139 {140 pre =p;141 p = p->next;142 }143 pre->next = cur->next;144 free(cur);145 cur =NULL;146 }147 void RemoveAllLinklist(pLinklist *pL, LDataType data)//删除所有的指定元素

148 {149 assert(pL !=NULL);150 pLinklist cur =NULL;151 pLinklist p = *pL;152 pLinklist pre = *pL;153 while(p)154 {155

156 if (p->data == data && (*pL) ==p)157 {158 pre =p;159 p = p->next;160 *pL =p;161 free(pre);162 pre =NULL;163 }164 else if (p->data ==data)165 {166 cur =p;167 p = p->next;168 pre->next =p;169 free(cur);170 cur =NULL;171 }172 else

173 {174 pre =p;175 p = p->next;176 }177 }178

179 }180 void PrintLinklist(Linklist *pL)//打印单链表

181 {182 pLinklist cur =pL;183 while(cur)184 {185 printf("%d-->", cur->data);186 cur = cur->next;187 }188 printf("NULL\n");189 }190 void DestoryLinklist(pLinklist *pL)//销毁单链表,放置内存溢出

191 {192 assert(pL !=NULL);193 pLinklist cur = *pL;194 pLinklist pre = NULL;//保存cur的前一个节点

195 if (*pL ==NULL)196 {197 printf("链表为空\n");198 return;199 }200 if (cur->next == NULL)//只有一个节点

201 {202 *pL =NULL;203 free(cur);204 cur =NULL;205 return;206 }207 while(cur)208 {209 pre =cur;210 cur = cur->next;211 free(pre);212 pre =NULL;213 }214 }

1 //test.c测试函数

2 #include"Linklist.h"

3

4 voidtest()5 {6 pLinklist cur = NULL;//用来接收FindLinklist的返回值

7 Linklist *first =NULL;8 InitLinklist(&first);//初始化9 //PushBackLinklist(&first, 1);//尾插元素10 //PushBackLinklist(&first, 2);11 //PushBackLinklist(&first, 3);12 //PushBackLinklist(&first, 4);13 //PushBackLinklist(&first, 5);14 //PrintLinklist(first);//打印单链表

15 PushFrontLinklist(&first, 6);//头插元素

16 PushFrontLinklist(&first, 7);17 PushFrontLinklist(&first, 8);18 PushFrontLinklist(&first, 9);19 PushFrontLinklist(&first, 10);20 //PopBackLinklist(&first);//尾删一个节点21 //PopFrontLinklist(&first);//头删一个节点22 //PrintLinklist(first);//打印单链表23 //DestoryLinklist(&first);24 //cur = FindLinklist(&first, 8);25 //InsertLinklist(&first, cur, 11);26 //printf("在8前面插入11得:");27 //PrintLinklist(first);//打印单链表28 //printf("删除11得:");29 //RemoveLinklist(&first, 11);30 //PrintLinklist(first);

31 PushFrontLinklist(&first, 7);32 PushFrontLinklist(&first, 7);33 //RemoveLinklist(&first, 7);

34 RemoveAllLinklist(&first, 7);35 PrintLinklist(first);36

37 //RemoveAllLinklist(&first, 7);//删除所有的7

38 }39 intmain()40 {41 test();42 system("pause");43 return 0;44 }

4.尾插法建立单链表如下图:

测试图:                                                                                                                         运行图:

754a248993a589473d9748bae5689862.pnge85dda4a3503c8bee21e0620856fc7c4.png

5.头插法建立单链表如下图:

测试图:                                                                                    运行图:

fc110dbf238cccfef8ac4640b5ea300b.png 

22fea983f2fdc4c22407e8b332ce0906.png

6.头删和尾删一个结点:

测试图:                                                                              运行图:

eaefe842fd124cb5c4a57f99be3c55be.png  

ac5800e1e9626f0a37181d3c4adb5cfc.png

7.在指定位置插入元素:

测试图:                                                                          运行图:

9da9785b9c73d571a5c9e6cda9389deb.png  

13a3ca37ee3e691b8d7a55d1db75cdf3.png

除这几个操作外,还有删除指定元素RemoveLinklist(删除第一个找到的指定元素),删除所有的指定元素RemoveAllLinklist。因为本文中单链表的结点是动态开辟的,因此还要实现销毁函数DestoryLinklist,防止内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值