1. 程式人生 > >靜態鏈表、循環鏈表、雙向鏈表(C代碼實現)

靜態鏈表、循環鏈表、雙向鏈表(C代碼實現)

一個 event 比較 hhhh 指向 移動 eve ini tle

靜態鏈表

對於沒有指針的編程語言,可以用數組替代指針,來描述鏈表。讓數組的每個元素由data和cur兩部分組成,其中cur相當於鏈表的next指針,這種用數組描述的鏈表叫做靜態鏈表,這種描述方法叫做遊標實現法。我們對數組的第一個和最後一個元素做特殊處理,不存數據。讓數組的第一個元素cur存放第一個備用元素(第一個未被占用的元素)下標,而數組的最後一個元素cur存放第一個有值的元素下標,相當於頭結點作用。空的靜態鏈表如下圖

技術分享圖片

技術分享圖片

當存放入一些數據時("甲""乙""丁""戊""己""庚"),靜態鏈表為:

技術分享圖片

靜態鏈表的插入操作

在靜態鏈表第三個位置插入"丙"後,結果如下:

技術分享圖片

靜態鏈表中要解決的是:如何用靜態模擬動態鏈表結構的存儲空間的分配,需要時申請,無用時釋放。

其主要的思想:(以我們如果要在乙 和 丁 中間插入一個丙 )

我們自己定義一個內存分配函數,如Malloc_SLL(StaticLinkList space)

1 //插入元素時,分配空間的下標(從備用鏈表中去取出)
2 int Malloc(StaticLinkList L)
3 {
4     int i = L[0].cur;               //獲取備用鏈表的下表
5     if (i)                           //鏈表不為空
6         L[0
].cur = L[i].cur; //將第一位的遊標改成備用鏈表的下表+1 7 return i; 8 }

然後再修改遊標表示,如上圖

代碼附上:

 1 //靜態鏈表中i位置插入一個元素
 2 bool StaticLinkListInsert(StaticLinkList L, int i, int key)
 3 {
 4     //判斷插入點是否合理
 5     if (i<1 || i>StaticLinkListLength(L)+1)
 6     {
 7         return false;
 8     }
 9
int j = Malloc(L); 10 int k = MAXSIZE - 1; 11 if (j) 12 { 13 for (int l = 1; l <= j - 1; l++) 14 { 15 k = L[k].cur; 16 } 17 L[j].data = key; 18 L[j].cur = L[k].cur; 19 L[k].cur = j; 20 return true; 21 } 22 return false; 23 24 }

靜態鏈表的刪除操作

刪除操作其實就是插入操作的逆操作

我們同樣要自己定義一個Free函數

void Free(StaticLinkList L, int k)
{
    L[k].cur = L[0].cur;
    L[0].cur = k;
}

獲取要刪除的元素下標後,開始修改遊標

 1 bool StaticLinkListDelete(StaticLinkList L,int i, int *key)
 2 {
 3     if (i < 1 || i >= StaticLinkListLength(L))
 4     {
 5         return false;
 6     }
 7     int k = MAXSIZE - 1;
 8     for (int l = 1; l <= i-1; l++)
 9     {
10         k = L[k].cur;
11     }
12     int j = L[k].cur;
13     *key = L[j].data;
14     L[k].cur = L[j].cur;
15     Free(L, j);
16     return true;
17 }

刪除"甲"後,靜態鏈表如下:

技術分享圖片

總結一下靜態鏈表的優缺點:

優點:在插入和刪除時,只需要修改遊標,不需要移動元素。從而改進了在順序存儲結構中的插入和刪除需要移動大量元素的特點。

缺點:沒有解決連續存儲分配帶來的表長難以確定的問題;失去了順序存儲結構隨機存儲的特性。

Copy 了大佬一些些文字和圖片:

https://www.cnblogs.com/zhaoxy/p/7754906.html

靜態鏈表實現的一些基本操作:(附上代碼)

技術分享圖片
  1 #include<stdio.h>
  2  
  3 #define MAXSIZE 7
  4 #define true 1
  5 #define false 0
  6  
  7 typedef int bool;
  8  
  9 typedef struct
 10 {
 11     int data;
 12     int cur;
 13 }StaticLinkList[MAXSIZE];
 14  
 15 //初始化靜態鏈表,0位置cur指向1位置,1位置cur指向2位置...MAXSIZE-1位置指向0位置
 16 void InitStaticLinkList(StaticLinkList L)//本來想用小寫l的,但是小寫l看起來太怪了
 17 {
 18     for (int i = 0; i < MAXSIZE - 2; i++)
 19     {
 20         L[i].cur = i + 1;//最後一個元素指向的是尾節點
 21     }
 22     L[MAXSIZE - 2].cur = 0;//備用鏈表的最後一個空元素的cur指向0,這一行不能省。
 23     L[MAXSIZE - 1].cur = 0;
 24 }
 25  
 26  
 27 //求靜態鏈表中元素個數,不包括頭尾節點
 28 int StaticLinkListLength(StaticLinkList L)
 29 {
 30     int i = L[MAXSIZE - 1].cur;
 31     int j = 0;
 32     while (i)
 33     {
 34         j++;
 35         i = L[i].cur;
 36     }
 37     return j;
 38 }
 39  
 40 //插入元素時,分配空間的下標
 41 int Malloc(StaticLinkList L)
 42 {
 43     int i = L[0].cur;
 44     if (i)
 45         L[0].cur = L[i].cur;
 46     return i;
 47 }
 48  
 49  
 50 //靜態鏈表中i位置插入一個元素
 51 bool StaticLinkListInsert(StaticLinkList L, int i, int key)
 52 {
 53     //判斷插入點是否合理
 54     if (i<1 || i>StaticLinkListLength(L)+1)
 55     {
 56         return false;
 57     }
 58     int j = Malloc(L);
 59     int k = MAXSIZE - 1;
 60     if (j)
 61     {
 62         for (int l = 1; l <= j - 1; l++)
 63         {
 64             k = L[k].cur;
 65         }
 66         L[j].data = key;
 67         L[j].cur = L[k].cur;
 68         L[k].cur = j;
 69         return true;
 70     }
 71     return false;
 72     
 73 }
 74  
 75  
 76 void Free(StaticLinkList L, int k)
 77 {
 78     L[k].cur = L[0].cur;
 79     L[0].cur = k;
 80 }
 81  
 82 //刪除第i個元素
 83  
 84 bool StaticLinkListDelete(StaticLinkList L,int i, int *key)
 85 {
 86     if (i < 1 || i >= StaticLinkListLength(L))
 87     {
 88         return false;
 89     }
 90     int k = MAXSIZE - 1;
 91     for (int l = 1; l <= i-1; l++)
 92     {
 93         k = L[k].cur;
 94     }
 95     int j = L[k].cur;
 96     *key = L[j].data;
 97     L[k].cur = L[j].cur;
 98     Free(L, j);
 99     return true;
100 }
101  
102 //遍歷
103 void StaticLinkListTraverse(StaticLinkList L)
104 {
105     int k = MAXSIZE - 1;
106     while (L[k].cur)
107     {
108         k = L[k].cur;
109         printf("%d ", L[k].data);
110     }
111     printf("\n");
112 }
113  
114 int main(void)
115 {
116     StaticLinkList L;
117     printf("初始化鏈表:\n");
118     InitStaticLinkList(L);
119     printf("初始化鏈表之後,鏈表的長度為:%d\n", StaticLinkListLength(L));
120     printf("插入1,2,3,4,5\n");
121     StaticLinkListInsert(L, 1, 1);
122     StaticLinkListInsert(L, 1, 2);
123     StaticLinkListInsert(L, 1, 3);
124     StaticLinkListInsert(L, 1, 4);
125     StaticLinkListInsert(L, 1, 5);
126     printf("遍歷鏈表:\n");
127     StaticLinkListTraverse(L);
128     printf("鏈表長度為:%d\n", StaticLinkListLength(L));
129     printf("刪除第二個元素:\n");
130     int key;
131     StaticLinkListDelete(L, 2, &key);
132     printf("刪除的元素值為:%d\n", key);
133     printf("遍歷鏈表:\n");
134     StaticLinkListTraverse(L);
135  
136 }
View Code

技術分享圖片

並且附上代碼來源:

https://blog.csdn.net/hhhhhyyyyy8/article/details/81027728

循環鏈表

1、循環鏈表:

      這個就是在單鏈表的基礎上頭尾相接了,將最後一個結點的指針指向了L->next;這裏我們也不多做贅述,它的大部分操作和單鏈表是相似的。

      還有一點要註意的就是判斷一個循環鏈表是否為空條件是看頭結點是否指向其本身。

技術分享圖片

技術分享圖片

雙向鏈表

所謂雙向就是說有兩個方向,其實就是在單鏈表的基礎上,多了一個前驅的指針域,用來指向前驅元素,其解決了單鏈表單向性這一缺點(只能順著後繼元素遍歷)

雙向循環鏈表,與循環鏈表類似,帶頭結點的雙向循環空鏈表如下圖(左),非空如下圖(右邊)

技術分享圖片

技術分享圖片


那麽入定義一個雙向鏈表呢?

1  typedef struct DulNode
2 {
3      struct DulNode *prior;                      //前驅指針
4      struct DulNode *next;                       //後繼指針
5      ElemType e;                                 //數據域
6 }DulNode,*DuLinkList;

插入操作

技術分享圖片

對比單鏈表學習,復雜並且靈活

插入關鍵代碼:

1  s->prior = p;           //把p賦值給s的前驅,s的前驅指向p
2  s->next = p->next;      //把p->next賦值給s的後繼 
3  p->next->prior = s;     //把s賦值給p-next的前驅
4 p->next = s;            //把s賦值給p的後繼

刪除操作

技術分享圖片

刪除操作關鍵代碼:

1 P->prior->next = p->next; //把p->next的值賦給p->prior的後繼
2 p->next->prior = P->prior;//把p=>prior賦值給p->next的前驅

復習回顧:

我們對線性表的兩大結構進行了學習,先是學習了比較容易的順序存儲結構,,指的是用一段地址連續的存儲單元依次存儲線性表中的元素,我們通常使用數組來實現。

後面則是學習了鏈式存儲結構。它具有不收存儲空間的限制,可以比較快捷的插入和刪除的特點被廣為使用。然後還學習了動態鏈表的單鏈表、雙鏈表、循環鏈表,以及最後我們還學習了如何不使用指針處理鏈式結構的數據關系---靜態鏈表。

總的來說,線性表就包含了順序存儲結構和鏈式存儲結構兩大結構。

技術分享圖片

靜態鏈表、循環鏈表、雙向鏈表(C代碼實現)