单链表——带头节点

一、链表简介

  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

    

posted @ 2015-06-26 20:59  enjoy_now  阅读(4957)  评论(0编辑  收藏  举报