無頭結點的單鏈表(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