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


1.单链表:

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

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

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

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

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

      

2.单链表操作

   头插过程:

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

3.运行代码:

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

 1 //Linklist.h
 2 #pragma once
 3 #include<stdio.h>
 4 #include<assert.h>
 5 #include<stdlib.h>
 6 
 7 typedef int LDataType;  8 typedef struct Linklist  9 { 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     return NewNode;  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             return cur; 102  } 103         cur = cur->next; 104  } 105     return NULL; 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 void test()  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 int main() 40 { 41  test(); 42     system("pause"); 43     return 0; 44 }

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

  测试图:                                                                                                                         运行图:

 

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

   测试图:                                                                                    运行图:

 

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

  测试图:                                                                              运行图:

 

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

  测试图:                                                                          运行图:

 

 

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

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM