單鏈表——帶頭節點


一、鏈表簡介

  1 數據結構中,鏈表是最基礎的。然而鏈表根據不同的需求分成的種類很多,單向或雙向鏈表,循環或非循環鏈表,帶頭節點或者不帶頭節點的鏈表。

  2 本文實現——帶頭節點的單鏈表。

  3 由於僅僅是學習鏈表的基本操作,所以在數據字段僅僅設置一個字段;

     由於僅僅是學習基本操作,不涉及復雜的算法思想,所以不會很難,主要以代碼為主,附上必要的解釋即可。

 

二、具體實現

  整體分析:帶有頭節點的單鏈表的操作很方便,主要體現在插入和刪除時不需要判斷是否是第一個元素。

    1) 頭文件定義如下:

    
 1 #ifndef LinearList_LinkList_h
 2 #define LinearList_LinkList_h
 3 
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6 
 7 #define OK 1
 8 #define ERROR 0
 9 
10 
11 typedef int Status;
12 typedef int ElemType;
13 
14 
15 typedef struct LNode {
16     ElemType data;
17     struct LNode *pNext;
18 }LNode, *LinkList;
19 
20 //LinkList with head
21 Status CreateLinkListFromHead(LinkList *L, int nInputLength);
22 Status CreateLinkListFromRear(LinkList *L, int nInputLength);
23 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem);
24 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem);
25 Status DestroyLinkList(LinkList *L);
26 Status PrintLinkList(LinkList L);
27 
28 #endif
LinkList.h

     2)具體實現:

    1 建立單鏈表:

      思路: a)校驗參數

        b)校驗長度是否合法(不校驗也行。這里主要是為了防止非法輸入,快速返回)

        c)建立頭節點。(也有一種方法:單獨寫一個建立頭節點的函數。此處直接嵌入在建表的過程中。)

        d)循環建立節點,然后選擇不同的插入方法插入。

          

     詳解插入:

        a)插入代碼:

        設pNode指向待插入位置的前一個插入點,pInsertNode指向待插入的節點本身,則插入代碼如下:

        pInsertNode->pNext = pNode->pNext;

        pNode->pNext = pInsertNode;

        b)插入的方法:

          頭插法:每次插入點都選擇在頭節點的后一個節點,也就是整個有效鏈表的第一個位置。

              pNode指向待插入節點本身,L指向表頭節點。

              此時代碼如下:

              (在建立頭節點時,一定要先設置頭節點的指針域為空 L->pNext = NULL,否則到最后就無法設置表尾為空了。)

              pNode->pNext = L->pNext;

              L->pNext = pNode;

          代碼如下:

            
 1 Status CreateLinkListFromHead(LinkList *L, int nInputLength) {
 2     if (NULL == L) {
 3         printf("Error parament.");
 4         return ERROR;
 5     }
 6     
 7     *L = (LinkList)malloc(sizeof(LNode));
 8     if (NULL == *L) {
 9         printf("Out of memory.");
10         return ERROR;
11     }
12     (*L)->pNext = NULL; //because list is created from head. So make the list empty
13     
14     if (nInputLength < 1) {
15         printf("Error length.");
16         return ERROR;
17     }
18     
19     LNode *pNode;
20     int nValue;
21     
22     printf("Input the values:");
23     for (int i = 1; i <= nInputLength; i++) {
24         scanf("%d", &nValue);
25         
26         pNode = (LinkList)malloc(sizeof(LNode));
27         if (NULL == pNode) {
28             printf("Out of memory.");
29             return ERROR;
30         }
31         pNode->data = nValue;
32         
33         pNode->pNext = (*L)->pNext;
34         (*L)->pNext = pNode;
35     }
36     
37     return OK;
38 }
CreateLinkListFromHead

          尾插法:每次插入點都選擇在鏈表的表尾處。因此需要額外增加一個指針(pRear)用於標示鏈表表尾。

              起初,pRear指向表頭節點pRear = L;pNode指向待插入節點本身

              插入代碼如下:

              pRear->pNext = pNode;

              pRear = pRear->pNext;

              到最后一定要設置表尾為空:pRear->pNext = NULL;

          代碼如下:

            
 1 Status CreateLinkListFromRear(LinkList *L, int nInputLength) {
 2     if (NULL == L) {
 3         printf("Error parament.");
 4         return ERROR;
 5     }
 6     
 7     //build the head
 8     *L = (LinkList)malloc(sizeof(LNode));
 9     if (NULL == *L) {
10         printf("Out of memory.");
11         return ERROR;
12     }
13     (*L)->pNext = NULL; //make the list empty
14     
15     if (nInputLength < 1) {
16         printf("Invalid input length.");
17         return ERROR;
18     }
19 
20     int nValue;
21     LNode *pNode;
22     LNode *pRear = *L;
23     
24     printf("Input the values:");
25     for (int i = 1; i <= nInputLength; i++) {
26         scanf("%d", &nValue);
27         
28         pNode = (LinkList)malloc(sizeof(LNode));
29         if (NULL == pNode) {
30             printf("Out of memory.");
31             return ERROR;
32         }
33         pNode->data = nValue;
34         
35         pRear->pNext = pNode;
36         pRear = pRear->pNext;
37     }
38     
39     pRear->pNext = NULL;
40     
41     return OK;
42 }
CreateLinkListFromRear

     2 插入節點:

          思路:a)校驗參數

             b)建立待插入節點

             c)找到待插入點

             d)插入

          分析:純粹的插入就是那兩行代碼,然而重點在於插入點的合法性判斷以及插入點的定位。

             合法:當插入點大於表長時應該返回錯誤;

             插入點:一般來講,會定位到當前帶插入點的前一個位置;

            (其實也可以直接定位到帶插入點處,插入后交換前后元素即可。但當數據元素過多時不適合。)    

          代碼如下:

            
 1 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem) {
 2     if (NULL == L) {
 3         printf("Error parament.");
 4         return ERROR;
 5     }
 6     
 7     if (nIndex < 1) {
 8         printf("Invalid insert point.");
 9         return ERROR;
10     }
11     
12     int i = 0;
13     LNode *pNode;
14     LNode *qNode;
15     
16     qNode = (LinkList)malloc(sizeof(LNode));
17     if (NULL == qNode) {
18         printf("Out of memory.");
19         return ERROR;
20     }
21     qNode->data = eElem;
22     
23     //the key--find the insert point
24     pNode = *L;
25     while (NULL != pNode->pNext && i < nIndex - 1) {
26         pNode = pNode->pNext;
27         i++;
28     }
29     
30     //invalid insert point
31     if (i < nIndex - 1) {
32         printf("Invalid Insert point.");
33         return ERROR;
34     }
35     
36     //insert
37     qNode->pNext = pNode->pNext;
38     pNode->pNext = qNode;
39     
40     
41     return OK;
42 }
InsertToLinkList

     3 刪除節點:(刪除和插入類似)

          思路:a)校驗參數

             b)判斷鏈表是否為空

             c)找到待插入點

             d)取出待刪除元素中的值

             e)刪除

          分析:純粹的刪除代碼也就固定的兩行,然而重點在於刪除點的定位和刪除后指針的處理

            刪除點定位:也是需要定位到待刪除點的前一個位置;

            刪除后處理:free和置空

          代碼如下:

            
 1 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem) {
 2     if (NULL == L || NULL == pElem) {
 3         printf("Error parament.");
 4         return ERROR;
 5     }
 6     
 7     if (NULL == (*L)->pNext) {
 8         printf("The list is empty.");
 9         return ERROR;
10     }
11     
12     if (nIndex < 1) {
13         printf("Invalid delete point.");
14         return ERROR;
15     }
16     
17     int i = 0;
18     LNode *qNode;
19     LNode *pNode = *L;  //  in case of the first valid delete point, the pNode should point to the head.
20     
21     while (NULL != pNode->pNext && i < nIndex - 1) {
22         pNode = pNode->pNext;
23         i++;
24     }
25     
26     if (NULL == pNode->pNext) { // nIndex - 1 == i
27         printf("Invalid delete point.");
28         return ERROR;
29     }
30     
31     qNode = pNode->pNext;
32     pNode->pNext = qNode->pNext;
33     
34     *pElem = qNode->data;
35     free(qNode);
36     qNode = NULL;
37     
38     return OK;
39 }
DeleteFromLinkList 

      4 銷毀鏈表

          思路:a)校驗參數

             b)判斷是否為空

             c)遍歷鏈表,依次刪除。

          分析:銷毀鏈表比較簡單,只需要完整遍歷這條鏈表即可。

         代碼如下:

          
 1 Status DestroyLinkList(LinkList *L) {
 2     if (NULL == L) {
 3         printf("Error parament.");
 4         return ERROR;
 5     }
 6     
 7     if (NULL == (*L)->pNext) {
 8         printf("The list is empty.");
 9         return ERROR;
10     }
11     
12     LNode *pNode = (*L)->pNext;
13     while (NULL != pNode) {
14         (*L)->pNext = pNode->pNext;
15         free(pNode);
16         
17         pNode = (*L)->pNext;
18     }
19     
20     (*L)->pNext = NULL;
21     pNode = NULL;
22     
23     return OK;
24 }
DestroyLinkList

三、附上完整版鏈表實現代碼,方便完整拷貝,測試等。

  1 #include "LinkList.h"
  2 
  3 
  4 /*-----------------LinkList withhead-------------------------------------------------*/
  5 
  6 Status CreateLinkListFromHead(LinkList *L, int nInputLength) {
  7     if (NULL == L) {
  8         printf("Error parament.");
  9         return ERROR;
 10     }
 11     
 12     *L = (LinkList)malloc(sizeof(LNode));
 13     if (NULL == *L) {
 14         printf("Out of memory.");
 15         return ERROR;
 16     }
 17     (*L)->pNext = NULL; //because list is created from head. So make the list empty
 18     
 19     if (nInputLength < 1) {
 20         printf("Error length.");
 21         return ERROR;
 22     }
 23     
 24     LNode *pNode;
 25     int nValue;
 26     
 27     printf("Input the values:");
 28     for (int i = 1; i <= nInputLength; i++) {
 29         scanf("%d", &nValue);
 30         
 31         pNode = (LinkList)malloc(sizeof(LNode));
 32         if (NULL == pNode) {
 33             printf("Out of memory.");
 34             return ERROR;
 35         }
 36         pNode->data = nValue;
 37         
 38         pNode->pNext = (*L)->pNext;
 39         (*L)->pNext = pNode;
 40     }
 41     
 42     return OK;
 43 }
 44 
 45 Status CreateLinkListFromRear(LinkList *L, int nInputLength) {
 46     if (NULL == L) {
 47         printf("Error parament.");
 48         return ERROR;
 49     }
 50     
 51     //build the head
 52     *L = (LinkList)malloc(sizeof(LNode));
 53     if (NULL == *L) {
 54         printf("Out of memory.");
 55         return ERROR;
 56     }
 57     (*L)->pNext = NULL; //make the list empty
 58     
 59     if (nInputLength < 1) {
 60         printf("Invalid input length.");
 61         return ERROR;
 62     }
 63 
 64     int nValue;
 65     LNode *pNode;
 66     LNode *pRear = *L;
 67     
 68     printf("Input the values:");
 69     for (int i = 1; i <= nInputLength; i++) {
 70         scanf("%d", &nValue);
 71         
 72         pNode = (LinkList)malloc(sizeof(LNode));
 73         if (NULL == pNode) {
 74             printf("Out of memory.");
 75             return ERROR;
 76         }
 77         pNode->data = nValue;
 78         
 79         pRear->pNext = pNode;
 80         pRear = pRear->pNext;
 81     }
 82     
 83     pRear->pNext = NULL;
 84     
 85     return OK;
 86 }
 87 
 88 
 89 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem) {
 90     if (NULL == L) {
 91         printf("Error parament.");
 92         return ERROR;
 93     }
 94     
 95     if (nIndex < 1) {
 96         printf("Invalid insert point.");
 97         return ERROR;
 98     }
 99     
100     int i = 0;
101     LNode *pNode;
102     LNode *qNode;
103     
104     qNode = (LinkList)malloc(sizeof(LNode));
105     if (NULL == qNode) {
106         printf("Out of memory.");
107         return ERROR;
108     }
109     qNode->data = eElem;
110     
111     //the key--find the insert point
112     pNode = *L;
113     while (NULL != pNode->pNext && i < nIndex - 1) {
114         pNode = pNode->pNext;
115         i++;
116     }
117     
118     //invalid insert point
119     if (i < nIndex - 1) {
120         printf("Invalid Insert point.");
121         return ERROR;
122     }
123     
124     //insert
125     qNode->pNext = pNode->pNext;
126     pNode->pNext = qNode;
127     
128     
129     return OK;
130 }
131 
132 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem) {
133     if (NULL == L || NULL == pElem) {
134         printf("Error parament.");
135         return ERROR;
136     }
137     
138     if (NULL == (*L)->pNext) {
139         printf("The list is empty.");
140         return ERROR;
141     }
142     
143     if (nIndex < 1) {
144         printf("Invalid delete point.");
145         return ERROR;
146     }
147     
148     int i = 0;
149     LNode *qNode;
150     LNode *pNode = *L;  //  in case of the first valid delete point, the pNode should point to the head.
151     
152     while (NULL != pNode->pNext && i < nIndex - 1) {
153         pNode = pNode->pNext;
154         i++;
155     }
156     
157     if (NULL == pNode->pNext) { // nIndex - 1 == i
158         printf("Invalid delete point.");
159         return ERROR;
160     }
161     
162     qNode = pNode->pNext;
163     pNode->pNext = qNode->pNext;
164     
165     *pElem = qNode->data;
166     free(qNode);
167     qNode = NULL;
168     
169     return OK;
170 }
171 
172 Status DestroyLinkList(LinkList *L) {
173     if (NULL == L) {
174         printf("Error parament.");
175         return ERROR;
176     }
177     
178     if (NULL == (*L)->pNext) {
179         printf("The list is empty.");
180         return ERROR;
181     }
182     
183     LNode *pNode = (*L)->pNext;
184     while (NULL != pNode) {
185         (*L)->pNext = pNode->pNext;
186         free(pNode);
187         
188         pNode = (*L)->pNext;
189     }
190     
191     (*L)->pNext = NULL;
192     pNode = NULL;
193     
194     return OK;
195 }
196 
197 Status PrintLinkList(LinkList L) {
198     if (NULL == L) {
199         printf("Error parament.");
200         return ERROR;
201     }
202     
203     if (NULL == L->pNext) {
204         printf("The list is empty.");
205         return ERROR;
206     }
207     
208     LNode *pNode = L->pNext;
209     
210     while (NULL != pNode) {
211         printf("%d ", pNode->data);
212         pNode = pNode->pNext;
213     }
214     
215     return OK;
216 }
LinkList.h

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM