4. 鏈表(下):如何優雅的寫出鏈表代碼?6大學習技巧

一、理解指針或引用的含義
1.含義:將某個變量(對象)賦值給指針(引用),實際上就是就是將這個變量(對象)的地址賦值給指針(引用)。
2.示例:
p—>next = q; 表示p節點的後繼指針存儲了q節點的內存地址。
p—>next = p—>next—>next; 表示p節點的後繼指針存儲了p節點的下下個節點的內存地址。

二、警惕指針丟失和內存泄漏(單鏈表)
1.插入節點
在節點a和節點b之間插入節點x,b是a的下一節點,,p指針指向節點a,則造成指針丟失和內存泄漏的代碼:p—>next = x;x—>next = p—>next; 顯然這會導致x節點的後繼指針指向自身。
正確的寫法是2句代碼交換順序,即:x—>next = p—>next; p—>next = x;
2.刪除節點
在節點a和節點b之間刪除節點b,b是a的下一節點,p指針指向節點a:p—>next = p—>next—>next;

三、利用“哨兵”簡化實現難度
1.什麼是“哨兵”?
鏈表中的“哨兵”節點是解決邊界問題的,不參與業務邏輯。如果我們引入“哨兵”節點,則不管鏈表是否爲空,head指針都會指向這個“哨兵”節點。我們把這種有“哨兵”節點的鏈表稱爲帶頭鏈表,相反,沒有“哨兵”節點的鏈表就稱爲不帶頭鏈表。
2.未引入“哨兵”的情況
如果在p節點後插入一個節點,只需2行代碼即可搞定:
new_node—>next = p—>next;
p—>next = new_node;
但,若向空鏈表中插入一個節點,則代碼如下:
if(head == null){
head = new_node;
}
如果要刪除節點p的後繼節點,只需1行代碼即可搞定:
p—>next = p—>next—>next;
但,若是刪除鏈表的最有一個節點(鏈表中只剩下這個節點),則代碼如下:
if(head—>next == null){
head = null;
}
從上面的情況可以看出,針對鏈表的插入、刪除操作,需要對插入第一個節點和刪除最後一個節點的情況進行特殊處理。這樣代碼就會顯得很繁瑣,所以引入“哨兵”節點來解決這個問題。
3.引入“哨兵”的情況
“哨兵”節點不存儲數據,無論鏈表是否爲空,head指針都會指向它,作爲鏈表的頭結點始終存在。這樣,插入第一個節點和插入其他節點,刪除最後一個節點和刪除其他節點都可以統一爲相同的代碼實現邏輯了。
4.“哨兵”還有哪些應用場景?
這個知識有限,暫時想不出來呀!但總結起來,哨兵最大的作用就是簡化邊界條件的處理。

四、重點留意邊界條件處理
經常用來檢查鏈表是否正確的邊界4個邊界條件:
1.如果鏈表爲空時,代碼是否能正常工作?
2.如果鏈表只包含一個節點時,代碼是否能正常工作?
3.如果鏈表只包含兩個節點時,代碼是否能正常工作?
4.代碼邏輯在處理頭尾節點時是否能正常工作?

五、舉例畫圖,輔助思考
核心思想:釋放腦容量,留更多的給邏輯思考,這樣就會感覺到思路清晰很多。

六、多寫多練,沒有捷徑
5個常見的鏈表操作:
1.單鏈表反轉
2.鏈表中環的檢測
3.兩個有序鏈表合併
4.刪除鏈表倒數第n個節點
5.求鏈表的中間節點

練習題LeetCode對應編號:206,141,21,19,876

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章