優雅的寫出鍊錶**(6大學習技巧)
2020.9.22
一、理解指標或引用的含義
示例:p -> next = q;表示p節點的後繼指標儲存了q節點的記憶體位址。
p -> next = p -> next ->next;表示p節點的後繼指標儲存了p節點的下下個節點的記憶體位址。
二、警惕指標丟失和記憶體洩漏(單鏈表)
插入節點
在節點a和節點b之間插入節點x,b是a的下一節點,p指標指向節點a,則造成指標丟失和記憶體洩漏的**:
p—>next = x;
x—>next = p—>next;
顯然這會導致x節點的後繼指標指向自身。
正確的寫法是這兩句**交換順序,即:
x—>next = p—>next;
p—>next = x;
三、利用「哨兵」簡化實現難度
什麼是「哨兵」?
鍊錶中的「哨兵」節點是解決邊界問題的,不參與業務邏輯。如果我們引入「哨兵」節點,則不管鍊錶是否為空。head指標都會指向這個「哨兵」節點。我們把這種有「哨兵」節點的鍊錶稱為帶頭鍊錶,相反,沒有「哨兵」節點的鍊錶就成為不帶頭鍊錶。
未引入「哨兵」的情況
如果在p節點後插入乙個節點,只需2行**即可搞定:
new_node—>next = p—>next;
p—>next = new_node;
但,若向空煉表中插入乙個節點,則**如下:
if(head == null)
如果要刪除節點p的後繼節點,只需1行**即可搞定:
p—>next = p—>next—>next;
但,若是刪除鍊錶的最有乙個節點(鍊錶中只剩下這個節點),則**如下:
if(head—>next == null)
從上面的情況可以看出,針對鍊錶的插入、刪除操作,需要對插入第乙個節點和刪除最後乙個節點的情況進行特殊處理。這樣**就會顯得很繁瑣,所以引入「哨兵」節點來解決這個問題。
引入「哨兵」的情況
「哨兵」節點不儲存資料,無論鍊錶是否為空,head指標都會指向它,作為鍊錶的頭結點始終存在。這樣,插入第乙個節點和插入其他節點,刪除最後乙個節點和刪除其他節點都可以統一為相同的**實現邏輯了。
「哨兵」還有哪些應用場景?
四、重點留意邊界條件處理
經常用來檢查鍊錶是否正確的邊界4個邊界條件:
1.如果鍊錶為空時,**是否能正常工作?
2.如果鍊錶只包含乙個節點時,**是否能正常工作?
3.如果鍊錶只包含兩個節點時,**是否能正常工作?
4.**邏輯在處理頭尾節點時是否能正常工作?
五、舉例畫圖,輔助思考
六、多寫多練,沒有捷徑
節點的定義:
typedef struct singlylinkednode singlylinkednode;
5個常見的鍊錶操作:
1.單鏈表反轉
2.鍊錶中環的檢測
3.兩個有序鍊錶合併
4.刪除鍊錶倒數第n個節點
5.求鍊錶的中間節點
鍊錶 鍊錶環問題總結
給定乙個單鏈表,只給出頭指標h 1 如何判斷是否存在環?2 如何知道環的長度?3 如何找出環的連線點在 4 帶環鍊錶的長度是多少?1 如何判斷是否存在環?對於問題1,使用追趕的方法,設定兩個指標slow fast,從頭指標開始,每次分別前進1步 2步。如存在環,則兩者相遇 如不存在環,fast遇到n...
靜態鍊錶的總結
1.靜態鍊錶的定義 用陣列描述的鍊錶就叫做靜態鍊錶 2.為什麼有靜態鍊錶 因為有些高階語言沒有向c語言的指標,有人想出來用陣列來代替指標,來描述單鏈表。3.怎樣定義靜態鍊錶 typedef struct componet,staticlinklist maxsize 靜態鍊錶最基本的兩部分就是 第一...
l鍊錶的總結
就快要參加考核了,總結一下學的鍊錶內容,加深記憶,啊啊啊,為什麼考核呢,我還是個寶寶。靜態鍊錶 把線性表的元素存放在陣列中,這些元素通過邏輯關係來進行連線。陣列單元存放鍊錶結點,結點的鏈域 鏈就是代表指標,是下一元素的位址,鍊錶中乙個結點可以分為兩個部分,乙個指標域用來存放指標,另乙個資料域用來存放...