从单链表操作分析代码质量

本文不单单只是讲单链表的操作,更重要的是通过写一个简单的有序单链表操作,来分析如何写出体积更小,效率高的代码。优化代码,本来就是有能正确解释问题的能力,通常来说,对认识一个问题都有比较深入的了解。否则,只能写出一些额外的代码。
在一个单链表中,每个节点包含指向链表下一个节点的指针,链表最后一个节点的指针值为NULL,表示链表后面不在有其它节点。根据单链表的特点,从链表中,找到第一个节点后,就可以访问剩下的节点。可以设置一个头节点,作为链表的头部,找到头结点可以访问该链表,除头结点以外的所有节点,也可以设置一个根指针,指向该链表的第一个节点。注意,该根指针不包含任何数据。因为单链表只能前一个节点指向后一个节点,所以操作单链表时候,一般需要两个指针配合。
下面结合例子说明。
在这里插入图片描述例1:实现一个有序(降序)单链表。
思路分析:
算法实现还是比较简单。按顺序逐一访问链表节点,新值与当前的点比较,如果比当前的点的值大,则停下来,比如新值为11 ,当前点10,停下来时候,当前点已经移到15.单链表又不能倒退,所以解决方法就是保存一个当前节点的前一个节点的指针。一前一后两个指针移动。
第一次写的代码:
//有序单链表插入

int ListOrderInsert(NODE *pRoot,int lNewValue)
{
     NODE *pstCurrent = NULL;
     NODE *pstPreviours = NULL;
     NODE *pstNew = NULL;
     
     if( NULL == pRoot)
     {
          printf("pRoot Null\n");
          return -1;
     }
     pstPreviours = pRoot;
     pstCurrent = pRoot->next;
	//新手容易忽略pstCurrent != NULL判断,会导致循环时候越过链表尾部,pstCurrent = NULL而对NULL访问是非法的。
     while(pstCurrent != NULL && pstCurrent->lvalue > lNewValue )    
 {
          pstPreviours = pstCurrent;
          pstCurrent = pstCurrent->next;
         
     }
     pstNew = (NODE *)malloc(sizeof(NODE)) ;
     if(NULL == pstNew)
     {
          printf("pstnew malloc failed\n");
          return -1;
     }
     pstNew->lvalue = lNewValue;

     pstNew->next = pstCurrent;
     pstPreviours->next = pstNew;
    
     return 0;
}

第二种写法:
保存一个指向下一个节点的指针,修改该节点的指针指向就好了。
//有序单链表插入法2

int ListOrderInsert1(NODE *pRoot,int lNewValue)
{
     NODE *pstCurrent = NULL;
     NODE **pstLink = NULL;
     NODE *pstNew = NULL;
     
     if( NULL == pRoot)
     {
          printf("pRoot Null\n");
          return -1;
     }
     pstLink = &pRoot->next;
     pstCurrent = *pstLink;

     while(pstCurrent != NULL && pstCurrent->lvalue > lNewValue )
     {
          pstLink = &(*pstLink)->next;
          pstCurrent = *pstLink;
         
     }
     pstNew = (NODE *)malloc(sizeof(NODE)) ;
     if(NULL == pstNew)
     {
          printf("pstnew malloc failed\n");
          return -1;
     }
     pstNew->lvalue = lNewValue;

     pstNew->next = pstCurrent;
     *pstLink = pstNew;
    
     return 0;
}

最终优化的版本:
使用一个指针就可以解决该问题。
//有序单链表插入法2简化

int ListOrderInsert2(NODE *pRoot,int lNewValue)
{
     NODE **pstLink = NULL;
     NODE *pstNew = NULL;
     
     if( NULL == pRoot)
     {
          printf("pRoot Null\n");
          return -1;
     }
     pstLink = &pRoot->next;

     while(*pstLink != NULL && (*pstLink)->lvalue > lNewValue )
     {
          pstLink = &(*pstLink)->next;
          
         
     }
     pstNew = (NODE *)malloc(sizeof(NODE)) ;
     if(NULL == pstNew)
     {
          printf("pstnew malloc failed\n");
          return -1;
     }
     pstNew->lvalue = lNewValue;

     pstNew->next = *pstLink;;
     *pstLink = pstNew;
    
     return 0;
}

总结:一、这个改进的函数,之所以能把代码体积变小,依赖于C语言能够取得地址的能力即指针。可见,指针的威力巨大,用指针,可以让代码体积变得更小,效率更高。
二、之所以能优化该函数,让该函数的代码体积更小,有两方面的原因,第一个因素是,能够正确解释问题。除非你能在不同的操作中总结出一些共性,不然,你只能编写额外的代码消除特殊情况。这通常对数据结构了解很清楚的前提下,才能获得这种能力。第二个因素就是C语言提供指针这种便利的工具,让你去随意发挥。
下面补充一些链表操作的程序:

void print(NODE *psthead)
{
     NODE *pstPos = NULL;
     
     if(NULL == psthead)
     {
          printf("psthead NULL\n");
          return ; 
     }
     pstPos = psthead;

     while((pstPos = pstPos->next) != NULL)
     {
          
          printf("%d  ",pstPos->lvalue);
     }
     printf("\n");
     return;
}
NODE *ListFind(NODE *pRoot,int lKeyValue)
{
     NODE **pstLink = NULL;

     if(NULL == pRoot)
     {
          printf("proot null\n");
          return NULL;
     }
     for(pstLink = &pRoot->next; pstLink != NULL;pstLink = &(*pstLink)->next)
     {
          if(lKeyValue == (*pstLink)->lvalue)
          {
               return *pstLink;
          }
     }
     
}
void FreeNode(NODE *psthead)
{
     NODE *pos = NULL;
     if(NULL == psthead)
     {
          printf("psthead null\n");
          return;
     }
     pos = psthead;
     while((pos = pos->next) != NULL)
     {
          //  pos = pos->next;
          free(pos);
     }
     printf("free node suecess\n");
     return;
}
//单链表插入的实现
int ListInsert(NODE *pRoot,int lNewValue)
{
     //NODE *pstCurrent = NULL;
     //NODE *pstPreviours = NULL;
     NODE *pstNew = NULL;
     
     if( NULL == pRoot)
     {
          printf("pRoot Null\n");
          return -1;
     }
     //pstCurrent = pRoot;

     //while(pstCurrent->next != NULL)
     while(pRoot->next != NULL)
     {
        
          //pstCurrent = pstCurrent->next;
          pRoot = pRoot->next;
     }
     pstNew = (NODE *)malloc(sizeof(NODE)) ;
     if(NULL == pstNew)
     {
          printf("pstnew malloc failed\n");
          return -1;
     }
     pstNew->lvalue = lNewValue;

     pstNew->next = NULL;
     // pstCurrent->next = pstNew;
     pRoot->next = pstNew;
     return 0;
}
int ListRemove(NODE *pRoot,NODE *pNode)
{
     NODE **pstLink = NULL;
     NODE *pnext = NULL;
     if(pRoot == NULL || pNode == NULL)
     {
          printf("pRoot or pNode Null\n");
          return -1;
     }
     pstLink = &pRoot->next;
     while(*pstLink != NULL)
     {
          if(pNode == *pstLink)
               break;
          pstLink = &(*pstLink)->next;
     }
     if(pNode == *pstLink)
     {
          pnext = (*pstLink)->next;
          free(*pstLink);
          *pstLink = pnext;
                   
     }
     else
     {
          printf("false\n");
          return -1;
     }
     
     return 0;
}
//移出某个节点,使用OS(1)
int ListRemove1(NODE *pRoot,NODE *pNode)
{
     NODE *pstNext = NULL;
     NODE *pos = NULL;
     if(pRoot == NULL || pNode == NULL)
     {
          printf("pRoot or pNode Null\n");
          return -1;
     }
     if(pNode->next != NULL)  //不是尾节点
     {
          pstNext = pNode->next;
          pNode->next = pstNext->next;
          pNode->lvalue = pstNext->lvalue;
          free(pstNext);
          pstNext = NULL;
     }
     else  //尾节点
     {
          for(pos = pRoot->next;pos != NULL; pos = pos->next)
          {
               if(pos == pNode)
               {
                    free(pos);
                    pos = NULL;
               }
          }
     }
}
int FindListNum(NODE *pRoot,int lk)
{
     NODE *p1 = NULL;
     NODE *p2 = NULL;
     NODE *pos = NULL;

     if(NULL == pRoot)
     {
          printf("proot is null\n");
          return -1;
     }
     if(lk <=0)
     {
          printf("lk <=0 err\n");
          return -1;
     }
     p1 = p2 = pRoot;
     while(lk--)
     {
          p2=p2->next;
     }
     if(p2->next == NULL)
     {
          printf("%d\n",p1->next->lvalue);
          return 0;
     }
     for(pos=pRoot;pos->next != NULL;pos = pos->next)
     {
          p1 = p1->next;
          p2 = p2->next;
          if(NULL == p2)
          {
               printf("%d\n",p1->lvalue);
               return 0;
          }
     }
     return -1;
     
}
//简化
NODE *FindListNum1(NODE *pRoot,int lk)
{
      NODE *p1 = NULL;
     NODE *p2 = NULL;
    

     if(NULL == pRoot)
     {
          printf("proot is null\n");
          return NULL;
     }
     if(lk <=0 )
     {
          printf("lk <=0 err\n");
          return NULL;
     }
     p1 = p2 = pRoot;
     while(lk--)
     {
          p2=p2->next;
     }
     while(p2->next != NULL)
     {
          p1 = p1->next;
          p2 = p2->next;
     }
          
    
     
     return p1->next;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//定义单链表节点
typedef struct list{
     int lvalue;
     struct list *next;
}NODE;
NODE stRoot = {0,NULL};
void print(NODE *psthead);
void FreeNode(NODE *psthead);
int ListInsert(NODE *pRoot,int lNewValue);
int ListOrderInsert(NODE *pRoot,int lNewValue);
int ListOrderInsert1(NODE *pRoot,int lNewValue);
//有序单链表插入法2简化
int ListOrderInsert2(NODE *pRoot,int lNewValue);
int ListRemove(NODE *pRoot,NODE *pNode);
int ListRemove1(NODE *pRoot,NODE *pNode);
NODE *ListFind(NODE *pRoot,int lKeyValue);
int FindListNum(NODE *pRoot,int lk);
NODE *FindListNum1(NODE *pRoot,int lk);
int main()
{
     NODE *pstNode = NULL;
     NODE *pstFind = NULL;
     NODE *result = NULL;
     int i = 0;
     int j;
     for(i = 0; i < 10; i++)
     {
          
           j = i*2;
           // ListInsert(&stRoot,j);
           ListOrderInsert(&stRoot,j);
     }
     ListOrderInsert2(&stRoot,7);
     print(&stRoot);
     pstFind = ListFind(&stRoot,7);
     // ListRemove(&stRoot,pstFind);
      ListRemove1(&stRoot,pstFind);
     print(&stRoot);
   result =  FindListNum1(&stRoot,2);
   printf("%d\n",result->lvalue);
  
     FreeNode(&stRoot);
     return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值