鍊錶是由一系列連線在一起的結點構成,其中的每個結點都是乙個資料結構。
鍊錶的結點通常是動態分配、使用和刪除的,允許鍊錶在程式執行時增大或縮小。如果需要將新資訊新增到鍊錶中,則程式只需分配另乙個結點並將其插入到系列中。如果需要從鍊錶中刪除特定的資訊塊,則程式將刪除包含該資訊的結點。
儘管鍊錶的編碼和管理比陣列更複雜,但它們有一些明顯的優勢。首先,鍊錶可以容易地擴大或縮小。實際上,程式設計師並不需要知道鍊錶中有多少個結點。它們只是根據需要在記憶體中建立。
**鍊錶對於陣列的優勢是結點可以插入鍊錶或從鍊錶中刪除的速度。**要將值插入陣列的中間,需要將插入點之後的所有元素朝陣列的末尾移動乙個位置,從而為新值騰出空間。同樣,從陣列中刪除乙個值需要將刪除點之後的所有元素都朝陣列的開始方向移動乙個位置。而當乙個結點插入鍊錶或從鍊錶中刪除結點時,其他結點都不必移動。
鍊錶中的每個結點都包含乙個或多個儲存資料的成員。例如,儲存在結點中的資料可以是庫存記錄;或者它可以是由客戶的姓名、位址和**號碼等組成的客戶資訊記錄。
除了資料之外,每個結點還包含乙個後繼指標指向鍊錶中的下乙個結點。圖 1 給出了單個結點的組成。
非空鍊錶的第乙個結點稱為鍊錶的頭。要訪問鍊錶中的結點,需要有乙個指向煉表頭的指標。從煉表頭開始,可以按照儲存在每個結點中的後繼指標訪問鍊錶中的其餘結點。最後乙個結點中的後繼指標被設定為 nullptr 以指示鍊錶的結束。
因為指向煉表頭的指標用於定位鍊錶的頭部,所以也可以認為它代表了煉表頭。同樣的指標也可以用來定位整個鍊錶,從頭開始,後面跟著後續指標,所以也可以很自然地把它看作是代表了整個鍊錶。
圖 2 給出了乙個由 3 個結點組成的鍊錶,其中顯示了指向頭部的指標,鍊錶的 3 個結點以及表示鍊錶末尾的 nullptr 指標。
注意,圖 2 中繪製的鍊錶結點彼此非常接近,排列整齊。實際上,鍊錶結點可能散布在記憶體的各個部分。
為了在 c++ 中表示鍊錶,需要有乙個表示鍊錶中單個結點的資料型別。通過圖 1 可以很自然地發現,這樣乙個資料型別不但需要包含要儲存的資料結構,還要有乙個指向另乙個相同型別結點的指標。
假設每個結點將儲存乙個型別為 double 的資料項,則可以宣告以下型別來存放結點:
struct listnode
;
在以上**中,listnode 就是要儲存在鍊錶中的結點的型別,結構成員 value 是結點的資料部分,而另乙個結構成員 next 則被宣告為 listnode 的指標,它是指向下乙個結點的後繼指標。
listnode 結構有乙個有趣的屬性,它包含乙個指向相同型別資料結構的指標,因此可以說是乙個包含對自身引用的型別。像這樣的型別稱為自引用資料型別或自引用資料結構。
在已經宣告了乙個資料型別來表示結點之後,即可定義乙個初始為空的鍊錶,方法是定義乙個用作煉表頭的指標並將其初始化為 nullptr,示例如下:
listnode *head =
nullptr
;
現在可以建立乙個鍊錶,其中包含乙個結點,儲存值為 12.5,如下所示:
head =
new listnode;
//分配新結點
head-
>value =
12.5
;//儲存值
head-
>next =
nullptr
;//表示鍊錶的結尾
接下來再看一看如何建立乙個新結點,在其中儲存 13.5 的值,並將其作為鍊錶中的第二個結點。可以使用第二個指標來指向新分配的結點(其中將儲存 13.5 的值),示例如下:
listnode *secondptr =
new listnode;
secondptr-
>value =
13.5
;secondptr-
>next =
nullptr
;//第二個結點是鍊錶的結尾
head-
>next = secondptr;
//第乙個結點指向第二個
請注意,以上語句通過將其後繼指標 secondptr->next 設定為 nullptr,可以使第二個結點成為鍊錶的結尾,通過 head->next = secondptr; 語句將煉表頭的後繼指標改為指向第二個結點。
下面的程式說明了如何建立乙個簡單的鍊錶:
// this program illustrates the creation || of linked lists.
#include
using
namespace std;
struct listnode
;int
main()
我們知道,c++ 結構體可以有建構函式。對於定義鍊錶結點型別的結構來說,如果能給它提供乙個或多個建構函式,那將會帶來很大的方便,因為這樣將使得結點在建立時即可初始化。前文還曾經提到過,建構函式可以像常規函式一樣,使用預設形參來定義,而為結點的後繼指標提供乙個預設的 nullptr 形參是很常見的。
以下是 listnode 結構的另乙個定義:
struct listnode
};
通過該宣告,即可使用以下兩種不同的方式建立乙個結點:
listnode *secondptr =
newlistnode
(13.5);
listnode *head =
newlistnode
(12.5
, secondptr)
;
使用 listnode 的建構函式版本,可以很輕鬆地建立乙個鍊錶,方法是讀取檔案中的值並將每個新讀取的值新增到已經累積的值鍊錶的開頭。
listnode *numberlist =
nullptr
;double number;
while
(numberfile >> number)
從煉表頭開始,涉及整個鍊錶,並在每個結點上執行一些處理操作的過程被稱為遍歷鍊錶。
例如,如果需要列印某個鍊錶中每個結點的內容,則必須遍歷該鍊錶。假設某個鍊錶的煉表頭指標是 numberlist,要遍歷該鍊錶,則需要使用另乙個指標 ptr 指向鍊錶的開頭:
listnode *ptr = numberlist;
然後就可以通過使用表示式 *ptr 或者使用結構指標操作符 -> 來處理由 ptr 指向的結點。例如,如果需要列印在結點上的值,則可以編寫以下**:
cout << ptr-
>value;
ptr = ptr-
>next;
以上語句使用指向結點後繼的指標來替換了指向該結點的指標,實現了結點之間的移動。因此,要列印整個鍊錶,可以使用如下**:
listnode *ptr = numberlist;
while
(ptr !=
nullptr
)
鍊錶建立及其相關功能
1.編寫函式,完成在第 n個節點的後增加節點的功能,n值由鍵盤輸入。注意健壯性,要求能夠對不同的 n值做出恰當的處理 2.編寫函式,完成在第 n個節點的後刪除節點的功能,n值由鍵盤輸入。注意健壯性,要求能夠對不同的 n值做出恰當的處理 3.編寫函式,刪除所有資料值為奇數的節點。注意健壯性,奇數節點可...
鍊錶及其C 實現
鍊錶實現 鍊錶和陣列一樣也是一種線性資料結構。鍊錶一般以鏈式儲存結構實現,適合需要頻繁增刪資料的需求,但是不支援隨機訪問。鍊錶一般包括單鏈表和雙鏈表以及迴圈鍊錶,單鏈表和雙鏈表以及迴圈鍊錶的實現一般使用虛擬頭結點的形式可以簡化實現細節。在c stl標準庫中,標頭檔案實現的為雙鏈表,標頭檔案實現的為單...
C 建立鍊錶
自己儲存一下,建立鍊錶的程式,省的以後每次建立鍊錶的時候,還需要重新在寫。通過下面的 建立的鍊錶節點數為10,每個節點儲存的數為其下標即 0 9 這裡要注意一點,在void createlist listnode phead 的時候,用的是指標引用,因為在main中head並沒有開闢空間,如果在cr...