数据结构——链表的c优化(2)

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

链表代码如下:

    #include <stdio.h>  
    #include <stdlib.h>  
    #include "node.h"  
      
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */  
      
    int main(int argc, char *argv[]) {  
        Node *head=NULL;  
        int number;  
    do{  
            scanf("%d",number);  
            if(number!=-1){  
                //add to linked-list  
                Node *p=(Node*)malloc(sizeof(Node));  
                p->value=number;  
                p->next=NULL;  
                //Find the last  
                Node *last=head;  
                if(last){  
                    while(last->next){  
                        last=last->next;  
                    }  
                    //attach  
                    last->next=p;  
                } else{  
                    head=p;  
                }  
            }  
        }while(number!=-1);  
      return 0;  
    }  

首先,链表结点已经在“node.h”的头文件中,通过对主函数的分析,我们可以看到,可以将在链表中增加结点这一行为提取出来,作为一个函数,命名为add()。要在一个链表中增加结点,因此add函数传入的参数就应该包含两个部分:链表的头结点和插入链表的数字。当然,如果改成“链表的头结点和新插入的结点”也是可以的,只不过需要将创建新结点单独拿出去在作为一个函数。因此修改之后的函数如下:

    #include <stdio.h>  
    #include <stdlib.h>  
    #include "node.h"  
      
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */  
    
	void add(Node *head,int number);
	  
    int main(int argc, char *argv[]) {  
        Node *head=NULL;  
        int number;  
    do{  
            scanf("%d",number);  
            if(number!=-1){  
               add(head,number);
        }while(number!=-1);  
      return 0;  
    } 
	}
	
	void add(Node *head,int number)
	{
	 //add to linked-list  
                Node *p=(Node*)malloc(sizeof(Node));  
                p->value=number;  
                p->next=NULL;  
                //Find the last  
                Node *last=head;  
                if(last){  
                    while(last->next){  
                        last=last->next;  
                    }  
                    //attach  
                    last->next=p;  
                } else{  
                    head=p;  
                }  
    }   

红色部分是修改的程序。这里要注意每次传进去的head仍然是一个null,add程序无法修改head。

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

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

程序修改如下:

    #include <stdio.h>  
    #include <stdlib.h>  
    #include "node.h"  
      
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */  
    
	void add(Node *head,int number);
	  
    int main(int argc, char *argv[]) {  
        Node *head=NULL;  
        int number;  
    do{  
            scanf("%d",number);  
            if(number!=-1){  
               head=add(head,number);
        }while(number!=-1);  
      return 0;  
    } 
	}
	
	Node* add(Node *head,int number)
	{
	 //add to linked-list  
                Node *p=(Node*)malloc(sizeof(Node));  
                p->value=number;  
                p->next=NULL;  
                //Find the last  
                Node *last=head;  
                if(last){  
                    while(last->next){  
                        last=last->next;  
                    }  
                    //attach  
                    last->next=p;  
                } else{  
                    head=p;  
                }  
                return head;
    }   

由于add函数没有使用全局变量,因此add函数可以针对不同的链表,是一个应用范围变广的函数,这看起来像是一个进步。但是这里存在一个接口函数设计的问题。这个函数最终要给其他程序员使用,程序员很难注意到

   head=add(head,number);

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

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

    #include <stdio.h>  
    #include <stdlib.h>  
    #include "node.h"  
      
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */  
    
	void add(Node *head,int number);
	  
    int main(int argc, char *argv[]) {  
        Node *head=NULL;  
        int number;  
    do{  
            scanf("%d",number);  
            if(number!=-1){  
               add(&head,number);
        }while(number!=-1);  
      return 0;  
    } 
	}
	
	Node* add(Node **pHead,int number)
	{
	 //add to linked-list  
                Node *p=(Node*)malloc(sizeof(Node));  
                p->value=number;  
                p->next=NULL;  
                //Find the last  
                Node *last=*pHead;  
                if(last){  
                    while(last->next){  
                        last=last->next;  
                    }  
                    //attach  
                    last->next=p;  
                } else{  
                    *pHead=p;  
                }  
    }   

这里有一个比较高级的方法:先定义一个结构体,这个结构体包含Node的指针head

    #include <stdio.h>  
    #include <stdlib.h>  
    #include "node.h"  
      
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */  
    typedef struct _list{
    	Node* head;
    }List;
    
	void add(Node *head,int number);
	  
    int main(int argc, char *argv[]) {  
        int number;  
        List list;
        list.head=NULL;
    
    do{  
            scanf("%d",number);  
            if(number!=-1){  
               add(&list,number);
        }while(number!=-1);  
      return 0;  
    } 
	}
	
	void add(List *pList,int number)
	{
	 //add to linked-list  
                Node *p=(Node*)malloc(sizeof(Node));  
                p->value=number;  
                p->next=NULL;  
                //Find the last  
                Node *last=pList->head;  
                if(last){  
                    while(last->next){  
                        last=last->next;  
                    }  
                    //attach  
                    last->next=p;  
                } else{  
                  pList->head=p;  
                }  
              
    }   
这个改进的好处是用了一个自己定义的结构体代表整个链表,而不再是之前仅有节点的概念。从结点层次的操作提升到链表层次的操作,很多事情就会变得简单。比如链表结构体中不仅可以包含结构体头结点,还可以包含尾结点,节点数量等等。





















猜你喜欢

转载自blog.csdn.net/zhanshen112/article/details/80721827
今日推荐