鍊錶(linked list)即使是一些包含資料的獨立資料結構的(node)集合.
鍊錶中的每個節點通過鏈或指標鏈結在一起.
程式通過指標訪問鍊錶中的節點.
節點通常是動態分配的,但也有由節點陣列構建的鍊錶(即使這樣,程式也是通過指標來遍歷鍊錶).
單鏈表中,每個節點包含乙個指向鍊錶下一節點的指標.鍊錶最後乙個節點的指標欄位的值為null.提示鍊錶後面不再有其他節點.
根指標,根指標指向鍊錶的第乙個節點,根指標只是乙個指標,不包含任何資料.
//但鍊錶節點的結構
typedef struct node node;
單鏈表的一些性質
鍊錶不一定是順序儲存的,它的節點可能分部於記憶體的各個地方.
單鏈表可以通過鍊錶從開始遍歷鍊錶知道結束位置,但無法從相反方向進行遍歷.
我們怎麼才能把乙個新節點插入到有序單鏈表中呢?加入要把12插入到單鏈表.(如果鍊錶中的值為 5, 10, 15)
思路:從鍊錶的起始位置開始,跟隨指標直到找到第乙個值大於7的節點,然後把這個新值插入到那個節點之前的位置.
有乙個問題,當我們找到第乙個大於12的節點時,指標可能指向了15,我們無法直到已經遍歷過的指標了,我們也無法返回.解決這個問題的方法就是始終儲存乙個指向鍊錶當前節點之前的那個節點指標.
//插入到乙個有序的單鏈表,函式的引數是乙個指向鍊錶第乙個節點的指標以及需要插入的值.
#include #include #include "ssl_node.h"
#define false 0
#define true 1
int ssl_insert( node *current, int new_value )
//為新節點分配記憶體,並把新值儲存到新節點中,如果記憶體分配失敗,函式返回false
new = (node *)malloc( sizeof( node ) );
if( new == null )
return false;
new->value = new_value;
//把新節點插入到鍊錶中,並返回ture
new->link = current;
previous->link = new;
return ture;
}//呼叫
result = ssl_insert( root, 12 );
以上函式是存在問題的
插入20時,while 會越過鍊錶的尾部.並對乙個null指標執行間接訪問操作. 我們沒有對current 指標判空,在while語句中直接對current取value是不對的.對空指標間接引用是非法的.
所以 while( current != null & current->value < value ) 時繼續迴圈
插入3時, 為了在鍊錶的起始位置插入乙個節點,函式必須修改指標.但是,函式不能反問變數root. 修正這個問題最容易的方法是把 root 宣告為全域性變數,這樣插入函式就能修改它.不幸的是,這是最壞的一種方法.因為這樣一來函式只對這個鍊錶起作用了
稍好的解決方法是把乙個指向root的指標作為引數傳遞給函式.然後使用間接訪問. 函式不僅可以獲得 root (指向鍊錶第乙個節點的指標,也就是根指標)的值,也可以向它儲存乙個新的指標值. 這個引數的型別是什麼呢? root 是乙個指向 node 的指標, 所以引數的型別應該是node **, 也就是乙個指向node 的指標的指標.
#include #include #include "ssl_node.h"
#define false 0
#define true 1
//插入到乙個有序鍊錶,函式的引數是乙個指向鍊錶根指標的指標,以及乙個需要插入的新值
int ssl_insert( node **rootp, int new_value)
//為新節點分配記憶體,並把新值儲存到新的節點,如果記憶體分配失敗.函式返回false
new = (node *)malloc( sizeof( node ));
if (new == null)
new->value = new_value;
//把新節點插入到鍊錶中,並返回 ture
new->link = current;
if ( previous == null) else
return true;
}
終極優化
把乙個節點插入到鍊錶的起始位置必須作為特殊情況進行處理嗎?畢竟我們此時插入新節點需要修改的指標是根指標,對於任何其他節點,對指標進行修改時實際修改的是前乙個節點的link 欄位. 這兩個看上去不同的操作實際上是一樣的.
消除特殊情況的關鍵在於:鍊錶中的每個節點都有乙個指向它的指標. 對於第乙個節點,這個指標是根指標,對於其他節點,這個指標是前乙個節點的link欄位.重點在於每個節點都有乙個指標指向它.至於指標是否位於某個節點之內是無關緊要的.
取得當前節點內部的link欄位的位址也是很方便的: ¤t->link
#include #include #include "ssl_node.h"
#define false 0
#define true 1
/** 把頭指標和節點內指標同樣對待,就不用對插入第乙個節點之前的情況特殊對待了
@param linkp 指向頭指標的指標
@param new_value 新值
@return 插入結構 1成功,0失敗
*/int ssl_insert_1( register node **linkp, int new_value)
//為新節點分配記憶體,並把新值儲存到新節點中,如果記憶體分配失敗,函式返回false
new = (node *)malloc( sizeof( node) );
if (new == null)
new->value = new_value;
//在鍊錶中插入新節點
new->link = current;
*linkp = new;
return true
}
C 結構 和指標
定義新的結構後會有新的結構成員,然後再建立給結構變數 struct可以省缺 其中結構變數可以是基本型別也可是指標,陣列等。include includeusing namespace std struct infltable 定義新結構指出了新型別的特徵 結構定義 不能省 void main inf...
C和C指標小記 十一 遞迴和迭代優化
c通過執行時堆疊支援遞迴函式的實現.遞迴函式就是直接或間接呼叫自身的函式.乙個小例子 使用遞迴將整型轉換為ascii字元 param value 整型數 void binary2ascii unsigned int value putchar value 10 0 尾遞迴 遞迴呼叫出現在函式的尾部,...
C和指標 第12章 使用結構和指標
2.單列表插入函式示例 include include typedef struct nodenode int sll insert register node rootp,int new value 以上 為最終修改和簡化後 修改和簡化有如下幾點 1.函式不能越過鍊錶尾部,所以採用判斷curren...