您的位置:首页 > 编程语言 > C语言/C++

C语言实现链表结构(二)链表的优化

2019-04-24 12:19 113 查看

版权声明:本文为转载文章,转载请务必注明出处和作者,谢谢合作! https://blog.csdn.net/zhanshen112/article/details/80721827



上一篇文章,已经初步会构造“链表”这种数据数据结构,本文主要讲一下构造的链表如何进行优化。

链表代码如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include “node.h”
  4. /* run this program using the console pauser or add your own getch, system(“pause”) or input loop */
  5. int main(int argc, char *argv[]) {
  6. Node *head=NULL;
  7. int number;
  8. do{
  9. scanf("%d",number);
  10. if(number!=-1){
  11. //add to linked-list
  12. Node p=(Node)malloc(sizeof(Node));
  13. p->value=number;
  14. p->next=NULL;
  15. //Find the last
  16. Node last=head;
  17. if(last){
  18. while(last->next){
  19. last=last->next;
  20. }
  21. //attach
  22. last->next=p;
  23. } else{
  24. head=p;
  25. }
  26. }
  27. }while(number!=-1);
  28. return 0;
  29. }
首先,链表结点已经在“node.h”的头文件中,通过对主函数的分析,我们可以看到,可以将在链表中增加结点这一行为提取出来,作为一个函数,命名为add()。要在一个链表中增加结点,因此add函数传入的参数就应该包含两个部分:链表的头结点和插入链表的数字。当然,如果改成“链表的头结点和新插入的结点”也是可以的,只不过需要将创建新结点单独拿出去在作为一个函数。因此修改之后的函数如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include “node.h”
  4. / run this program using the console pauser or add your own getch, system(“pause”) or input loop */
  5. void add(Node *head,int number);
  6. int main(int argc, char *argv[]) {
  7. Node *head=NULL;
  8. int number;
  9. do{
  10. scanf("%d",number);
  11. if(number!=-1){
  12. add(head,number);
  13. }while(number!=-1);
  14. return 0;
  15. }
  16. }
  17. void add(Node *head,int number)
  18. {
  19. //add to linked-list
  20. Node p=(Node)malloc(sizeof(Node));
  21. p->value=number;
  22. p->next=NULL;
  23. //Find the last
  24. Node last=head;
  25. if(last){
  26. while(last->next){
  27. last=last->next;
  28. }
  29. //attach
  30. last->next=p;
  31. } else{
  32. head=p;
  33. }
  34. }
红色部分是修改的程序。这里要注意每次传进去的head仍然是一个null,add程序无法修改head。

这里,有些教科书会说到用全局变量head,将head定义在主函数外面。有两个原因导致我们不愿意这样使用:1、要尽可能避免使用全局变量,全局变量是有害的,很可能在程序的某个地方就会修改全局变量;2、全局变量head我们现在设想的是只在这个链表中使用,如果存在多个链表,那多个链表的head就无法使用这个全局变量。

另外一个方法是可以在add函数里面将head作为返回值,然后将add函数定义为一个结点型指针(Node add(Node head,int number)),并将函数返回值赋给head。

程序修改如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include “node.h”
  4. / run this program using the console pauser or add your own getch, system(“pause”) or input loop */
  5. void add(Node *head,int number);
  6. int main(int argc, char *argv[]) {
  7. Node head=NULL;
  8. int number;
  9. do{
  10. scanf("%d",number);
  11. if(number!=-1){
  12. head=add(head,number);
  13. }while(number!=-1);
  14. return 0;
  15. }
  16. }
  17. Node add(Node *head,int number)
  18. {
  19. //add to linked-list
  20. Node p=(Node)malloc(sizeof(Node));
  21. p->value=number;
  22. p->next=NULL;
  23. //Find the last
  24. Node last=head;
  25. if(last){
  26. while(last->next){
  27. last=last->next;
  28. }
  29. //attach
  30. last->next=p;
  31. } else{
  32. head=p;
  33. }
  34. return head;
  35. }
由于add函数没有使用全局变量,因此add函数可以针对不同的链表,是一个应用范围变广的函数,这看起来像是一个进步。但是这里存在一个接口函数设计的问题。这个函数最终要给其他程序员使用,程序员很难注意到

head=add(head,number);
程序员使用add函数只是在链表上增加一个结点而已,实在是很难想到竟然通过add函数的返回值去修改head。因此,站在接口设计的角度,依然是存在问题。如果程序员忘了这个add赋给head的操作,那么对于空链表的add操作就是错的。

第三种方案:在add函数的输入参数中不再传入head结点,而是传入头结点的指针。即add(&head,number)。程序的其他部分也需要进行修改。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include “node.h”
  4. / run this program using the console pauser or add your own getch, system(“pause”) or input loop */
  5. void add(Node *head,int number);
  6. int main(int argc, char *argv[]) {
  7. Node head=NULL;
  8. int number;
  9. do{
  10. scanf("%d",number);
  11. if(number!=-1){
  12. add(&head,number);
  13. }while(number!=-1);
  14. return 0;
  15. }
  16. }
  17. Node add(Node **pHead,int number)
  18. {
  19. //add to linked-list
  20. Node p=(Node)malloc(sizeof(Node));
  21. p->value=number;
  22. p->next=NULL;
  23. //Find the last
  24. Node *last=*pHead;
  25. if(last){
  26. while(last->next){
  27. last=last->next;
  28. }
  29. //attach
  30. last->next=p;
  31. } else{
  32. pHead=p;
  33. }
  34. }
这里有一个比较高级的方法:先定义一个结构体,这个结构体包含Node的指针head
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include “node.h”
  4. / run this program using the console pauser or add your own getch, system(“pause”) or input loop /
  5. typedef struct _list{
  6. Node head;
  7. }List;
  8. void add(Node *head,int number);
  9. int main(int argc, char *argv[]) {
  10. int number;
  11. List list;
  12. list.head=NULL;
  13. do{
  14. scanf("%d",number);
  15. if(number!=-1){
  16. add(&list,number);
  17. }while(number!=-1);
  18. return 0;
  19. }
  20. }
  21. void add(List *pList,int number)
  22. {
  23. //add to linked-list
  24. Node p=(Node)malloc(sizeof(Node));
  25. p->value=number;
  26. p->next=NULL;
  27. //Find the last
  28. Node *last=pList->head;
  29. if(last){
  30. while(last->next){
  31. last=last->next;
  32. }
  33. //attach
  34. last->next=p;
  35. } else{
  36. pList->head=p;
  37. }
  38. }
这个改进的好处是用了一个自己定义的结构体代表整个链表,而不再是之前仅有节点的概念。从结点层次的操作提升到链表层次的操作,很多事情就会变得简单。比如链表结构体中不仅可以包含结构体头结点,还可以包含尾结点,节点数量等等。





















内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: