程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 單鏈表中一個插入操作的分析

單鏈表中一個插入操作的分析

編輯:關於C
首先看鏈表的結構:p- >節點->節點....(單向),結點包括兩部分,值value和指向下一節點的指針link,p為根節點,只有指針域,其類型為指向節點的指針,如要對其進行修改,調用函數時就要將其地址傳給函數當實參,及函數的形參類型應為指向指針的指針。
 當在進行一些鏈表的操作時,如節點的插入,把一個節點插入到鏈表的起始位置必須作為一種特殊情況進行處理,因為我們要修改的是指向指針的指針,對於其他位置,我們需要修改的是節點的link字段,似乎我們在寫對鏈表的操作時都要為此多寫一段代碼,但這兩個看上去不同的操作實際上時一樣的。
 消除特殊的關鍵在於:我們必須認識到,鏈表的每個節點都有一個指向它的指針。對於第一個節點,這個指針就是根指針!對於其他節點,這個指針是前一個節點的link字段。重點在於每個節點都有一個指針指向它。至於該節點是不是位於一個節點的內部則無關緊要。
 捋清思路之後給出解決方案:我們用一種和修改節點link字段完全一樣的方式修改head變量,最後,在函數的指針變量中增加register聲明,用於提高結果代碼的效率。
 附上《c和指針》中鏈表的插入操作,並簡要解析一下,主要是指針的問題。
#include<stdio.h>
#include<stdlib.h>
#define FALSE 0
#define TRUE 1
typedef struct NODE//定義鏈表結構體
{
 struct NODE *link;
 int value;
}Node;
int insert(register Node **linkp,int new_value)
{
 register Node *current;
 register Node *new_node;
 /*尋找插入位置,方法遍歷鏈表,直到到達一個值大於或等於新值的節點*/
 while((current=*linkp)!=NULL&&current->value<new_value)
  linkp=&current->link;
 /*為節點分配內存*/
 new_node=(Node *)malloc(sizeof(Node));
 if(new_node==NULL)
  return FALSE;
 new_node->value=new_value;
 /*插入結點,返回true*/
 new_node->link=current;
 *linkp=new_node;
 return TRUE;
}
/*以下是測試程序*/
main()
{
 Node *head=NULL;//定義一個指向節點的指針,作為根節點
 Node one,second;//初始化兩個節點
 head=&one;//使頭指針指向首節點
 if (head != NULL)
 head->value=5;
 head->link=&second;
 (&second)->value=10;
 // 顯示鏈表
 printf("第一節點:%5d,地址:%10d/n",head->value,&one);
 printf("第二節點:%5d,地址:%10d/n",(head->link)->value,head->link);
 printf("執行插入操作後:/n");
 insert(&head,3);//調用insert函數
 printf("第一節點:%5d,地址:%10d/n",head->value,&one);
 printf("第二節點:%5d,地址:%10d/n",(head->link)->value,head->link->link);
 printf("第三節點:%5d,地址:%10d/n",head->link->link->value,head->link->link->link);
 printf("good~/n");
}
 調試程序比較簡單,下面分析一下insert()函數的執行過程。函數參數是一個指向節點的指針,和待插入的值,第一個參數之所以射出指向指針的指針,是為了采用傳地址傳值,這樣才能返回鏈表的修改,實參用的是&head,即根節點的地址。執行插入操作時,先將指向根節點的指針的一份拷貝(不是指向根節點的指針!)和待插入數傳給insert();遍歷鏈表時先將head的值,即根節點的值也就是首節點的地址賦給current,此時curren和head同時指向首節點,緊接著開始判斷,linkp隨之後移動,current指針也移動(因為每次循環都執行current=*linkp)。完成查找後動態分配內存,生產新節點,將其指向current節點,*linkp指向它。
 這裡有一個小問題讓我想了差不多two days,首先看insert函數,它執行時,將&head賦給linkp,采用的是地址傳值,而函數的最後改變了*linkp(當插入的地方不是首節點),即改變了head 的值,這樣返回後根節點也隨之改變,這樣鏈表結構不是被破壞了麼?還是書有誤?但事實證明,鏈表並沒有破壞(見測試程序)。
 最後經高人指點,上網各種查,問題解決,關鍵在於”linkp=&current->link;“,即當遍歷鏈表的時候,linkp以隨之改變(當插入的地方不是首節點),指向的不再是根節點,最後的賦值時改變的也不是head的值,改變的是此時linkp指向的節點的link值,所以最終程序是正確的 這裡謝謝聆雨軒★小潘,大奎 /ty 。
 程序關鍵是指針的操作,指針弄明白了這個理解起來也比較容易。指針確實是c的一大難點,但也是c的一大特色。
 寫前面的文字和寫調試後的文字中間差不多隔了一周,中間斷斷續續的調了一下,都有點想放棄這個程序了,《c和指針》也沒往下看,進天終於通過了調試,心情比較舒暢,希望對學c的同學有用。   
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved