构建一个单链表,用来存储整数,实现单链表的增删查改输出清除等功能

构建一个单链表,链表中存储的是用户输入的整数

一、实现了以下功能:

  1. 链表初始化
  2. 链表判空
  3. 在指定结点之后添加结点
  4. 在指定结点之前添加结点(思路重要)
  5. 删除指定结点p
  6. 结点添加------首添&尾添
  7. 遍历并输出链表
  8. 查找链表的元素------按位序查找(封装起来,在List_Insert和List_DeleteByOrder这两个函数中调用)&按值查找
  9. 删除链表的元素------按值删除&按位删除
  10. 更改链表的指定元素
  11. 在链表的指定位置添加元素
  12. 在链表的指定位置添加元素(引入链表长度pList->size
  13. 链表的清空

二、亮点:用自己定义的数据结构struct _list表示整个链表

    该结构中存放了一个始终指向头结点的指针head,一个始终指向尾结点的指针tail,一个表示单链表长度的变量size

    指针head和tail给链表的结点添加带来方便,不需要遍历整个链表(函数List_AddOnTail)

    变量size给在链表指定位置添加结点带来方便,可以简化代码(函数List_Insert)

三、存在的问题(放在另一个随笔中):
在函数List_DeleteByValue中:链表中存在多个相同的元素相邻时,无法全部删除(重点是相邻,相同元素不相邻时均可删除)

只能删除第偶数个位置的元素

解决方法:

  1. 空间:将原来的链表进行拷贝(或者做一个辅助数组),对原来的链表进行判断,对备份链表进行删除操作(数据量太大时不推荐)
  2. 时间:不改动删除算法,用这个算法对这个链表进行多次操作,直到删除完为止
  3. 再加一个指针:prev,使用三指针方法解决

代码执行结果如下:

单链表增删查改_链表

代码如下:

  1 # include <stdio.h>
  2 # include <stdlib.h>
  3 # include <stdbool.h>
  4 //定义结构体(结点)
  5 typedef struct _node {
  6     int value;
  7     struct _node * next;
  8 } Node;
  9 
 10 //定义数据结构struct _list表示整个链表
 11 //存放链表的信息:头结点(如果有的话)或首结点、尾结点、链表长度等等
 12 typedef struct _list
 13 {
 14     Node* head;//始终指向首结点
 15     Node* tail;//始终指向尾结点
 16     int size;//表示链表的长度,用在List_Insert函数中,用来判断输入的位置i是否越界,可以简化代码
 17 } List;
 18 //初始化链表
 19 bool InitList(List* pList)
 20 {
 21     pList->head = pList->tail = NULL;
 22     pList->size = 0;
 23     return true;
 24 }
 25 //判空
 26 bool Empty(List* pList)
 27 {
 28     return (pList->head==NULL);
 29 }
 30 
 31 //在指定结点之后添加结点
 32 bool InsertNextNode(Node* p, int elem)
 33 {
 34     bool sign = true;
 35     if(p == NULL)
 36     {
 37         sign = false;
 38     }
 39     Node* s = (Node*)malloc(sizeof(Node));
 40     if(s == NULL)//内存分配失败
 41     {
 42         sign = true;
 43     }
 44     s->value = elem;
 45     s->next = p->next;
 46     p->next = s;
 47 
 48     return sign;
 49 }
 50 //在指定节点之前添加结点
 51 /*
 52 偷天换日的操作!
 53     指定结点的前驱结点是未知的,从头结点遍历的话时间复杂度高O(n)
 54     虽然结点不能交换位置,但是结点中的数据可以交换位置[O(1)]
 55 */
 56 bool InsertPriorNode(Node* p, int elem)
 57 {
 58     bool sign = true;
 59     if(p == NULL)
 60     {
 61         sign = false;
 62     }
 63     Node* s = (Node*)malloc(sizeof(Node));
 64     if(s == NULL)
 65     {
 66         sign = false;
 67     }
 68     //连接
 69     s->next = p->next;
 70     p->next = s;
 71     //下面两个语句是精髓
 72     s->value = p->value;//将结点p中的元素复制到s中
 73     p->value = elem;//p中元素替换为elem
 74 
 75     return sign;
 76 }
 77 //删除指定结点p(局限:当该结点是尾结点时,无法完成操作)
 78 bool DeleteNode(Node* p)
 79 {
 80     bool sign = true;
 81     if(p == NULL)
 82     {
 83         sign = false;
 84     }
 85     Node* q = p->next;//q指向p的后继结点
 86     p->value = p->next->value;//p结点和它的后继结点交换数据
 87     p->next = q->next;//将q结点删除
 88     free(q);
 89 
 90     return sign;
 91 }
 92 //结点添加(尾添加)
 93 Node* List_AddOnTail(List* pList, int number)//传入指针的指针
 94 {
 95     //分配结点空间,并写入p->value
 96     Node* p = (Node*)malloc(sizeof(Node));
 97     p->value = number;
 98     p->next = NULL;
 99     //head始终指向首结点,tail始终指向尾结点
100     //如果链表是空的,最新分配的结点(p)既是head,也是tail
101     if(pList->head == NULL)
102     {
103         pList->head = p;
104         pList->tail = p;
105     }
106     //如果链表不是空的,只需要处理tail
107     else
108     {
109         pList->tail->next = p;//此时链表的尾结点要指向新分配的结点
110         pList->tail = p;//新分配的结点成为链表的tail
111     }
112     pList->size ++;
113     pList->tail->next = NULL;//tail里面的指针必须是NULL
114 
115 /*  //在链表的尾结点之后添加结点,需要循环,
116     Node* last = pList->head;
117     if(last)
118     {
119         while(last->next)
120         {
121             last = last->next;
122         }
123         //接上去
124         last->next = p;
125     }
126     else
127     {
128         pList->head = p;
129     }
130 */
131     return pList->head;
132 }
133 //结点添加(头添)
134 Node* List_AddOnHead(List* pList, int n)
135 {
136     Node* p = (Node*)malloc(sizeof(Node));
137     p->value = n;
138     p->next = NULL;
139     if(pList->head == NULL)
140     {
141         pList->head = p;
142         pList->tail = p;
143     }
144     else
145     {
146         p->next = pList->head;
147         pList->head = p;
148     }
149     pList->size ++;
150     return pList->head;
151 }
152 //遍历输出链表
153 void List_Print(List* pList)
154 {
155     Node* p;
156     for(p=pList->head; p; p=p->next)
157     {
158         printf("%-5d", p->value);
159     }
160     printf("\n");
161 }
162 //查(按位)
163 Node* List_GetElem(List* pList, int i)
164 {
165     Node* q;
166     if(i<1 || i>pList->size)
167         q = NULL;
168     else
169     {
170         Node* p = pList->head;
171         int j = 1;
172         while(j<i)
173         {
174             p = p->next;
175             j++;
176         }
177         q = p;
178     }
179 
180     return q;
181 }
182 //查(按值)
183 bool List_Search(List* pList, int number)
184 {
185     bool isFound = false;
186     Node* p;
187     for(p=pList->head; p; p=p->next)
188     {
189         if(p->value == number)
190         {
191             isFound = true;
192             break;
193         }
194     }
195     return isFound;
196 }
197 //按值删除元素(仅删除第一个)
198 void List_DeleteByValue(List* pList, int number)
199 {
200     Node* prev;
201     Node* p;
202     Node* q;
203     for(p=pList->head,q=NULL; p; q=p,p=p->next)
204     {
205         if(number == p->value)
206         {
207             if(q)
208             {
209                 q->next = p->next;
210             }
211             else
212             {
213                 pList->head = p->next;
214             }
215         free(p);
216         break;
217         }
218     }
219 }
220 //更改指定元素
221 void List_Change(List* pList, int a, int b)
222 {
223     Node* p;
224     for(p=pList->head; p; p=p->next)
225     {
226         if(p->value == a)
227         {
228             p->value = b;
229         }
230     }
231 }
232 //在指定位置添加元素,引入链表长度(pList->size)
233 bool List_Insert(List* pList, int i, int elem)
234 {
235     bool sign = true;
236     if(i<1 || i>pList->size+1)
237         sign = false;
238     else if(i == 1)
239     {
240         Node* s = (Node*)malloc(sizeof(Node));
241         s->value = elem;
242         s->next = pList->head;
243         pList->head = s;
244     }
245     //找到第i-1个结点
246     else
247     {
248         Node* p = List_GetElem(pList, i-1);//封装 找到第i-1个结点,注意这里传入的参数是List*类型
249         sign = InsertNextNode(p,elem);//封装 在第i-1个结点之后插入新结点
250     }
251     return sign;
252 }
253 //按位序删除元素
254 bool List_DeleteByOrder(List* pList, int i, int* elem)
255 {
256     bool sign = true;
257     if(i<1 || i>pList->size+1)
258         sign = false;
259     else if(i == 1)
260     {
261         Node* p = pList->head;
262         pList->head = p->next;
263         free(p);
264     }
265     //找到第i-1个结点
266     else
267     {
268         Node* p = List_GetElem(pList, i-1);//简单的封装  注意这里传入的参数是List*类型
269         if(p==NULL || p->next==NULL)//i值越界或者第i-1个结点没有后继结点
270         {
271             sign = false;
272         }
273         Node* q = p->next;
274         *elem = q->value;
275         p->next = q->next;
276         free(q);
277     }
278     return sign;
279 }
280 //清除链表
281 bool List_Clear(List* pList)
282 {
283     Node* p;
284     Node* q;
285     bool sign = true;
286     if(pList->head == NULL)
287         sign = false;
288     p = pList->head->next;
289     while(p)
290     {
291         q = p->next;
292         free(p);
293         p = q;
294     }
295     pList->head->next = NULL;//注意!!!不能少
296     return sign;
297 }
298 
299 int main(void)
300 {
301 //创建并初始化,输入元素
302     List list;
303     InitList(&list);
304     int number;
305     printf("请输入整数(输入-1结束):\n");
306     do
307     {
308         scanf("%d", &number);
309         if(number != -1)
310         {
311             list.head = List_AddOnTail(&list, number);//注意这里要传入head的地址
312             //list.head = List_AddOnHead(&list, number);
313         }
314     }while(number != -1);
315 //遍历并输出链表
316     printf("链表中的元素为:");
317     List_Print(&list);
318 //查(按值)
319     printf("\n请输入您要查找的元素:");
320     scanf("%d", &number);
321     if(List_Search(&list, number) == true)
322     {
323         printf("找到了!\n");
324     }
325     else
326     {
327         printf("没找到!\n");
328     }
329 //查(按位)
330     printf("请输入您要查找的位序:");
331     int i, elem;
332     scanf("%d", &i);
333     if(List_GetElem(&list, i) != NULL)
334     {
335         printf("找到了!该元素是%d\n", List_GetElem(&list, i)->value);//这个地方的写法有问题吗?
336     }
337     else
338     {
339         printf("位序越界!\n");
340     }
341 //删除,按元素值
342     printf("\n请输入您要删除的元素:");
343     scanf("%d", &number);
344     if(List_Search(&list, number) == true)
345     {
346         List_DeleteByValue(&list, number);
347         printf("删除成功!当前链表中的元素为:");
348         List_Print(&list);
349     }
350     else
351     {
352         printf("删除失败!您要删除的元素不存在!\n");
353     }
354 
355 //更改链表元素
356     int a, b;
357     printf("\n请输入旧元素:");
358     scanf("%d", &a);
359     if(List_Search(&list, a))
360     {
361         printf("请输入新元素:");
362         scanf("%d", &b);
363         List_Change(&list, a, b);
364         printf("更改成功!当前链表元素为:");
365         List_Print(&list);
366     }
367     else
368     {
369         printf("未找到!\n");
370     }
371 //插入元素
372     printf("\n请输入您要插入的位置和数字:");
373     scanf("%d%d", &i, &elem);
374     if(List_Insert(&list, i, elem))
375     {
376         printf("插入成功!当前链表元素为:");
377         List_Print(&list);
378     }
379     else
380     {
381         printf("插入失败!\n");
382     }
383 //按位序删除元素
384     printf("\n请输入您要删除的结点的位序:");
385     scanf("%d", &i);
386     if(List_DeleteByOrder(&list, i, &elem))
387     {
388         printf("删除成功!删除的元素为:%d\n当前链表元素为:", elem);
389         List_Print(&list);
390     }
391     else
392     {
393         printf("删除失败!\n");
394     }
395 
396 //链表清除
397     if(List_Clear(&list))
398     {
399         printf("\n链表已清空!\n");
400     }
401     else
402     {
403         printf("\n清空失败,链表为空\n");
404     }
405 
406     return 0;
407 }