-
單鏈表的節點定義
struct ListNode{ int m_nValue; ListNode* m_pNext; };
-
在單鏈表的末尾添加結點
void AddToTail(LIstNode** pHead,int value) { ListNode* pNew = new ListNode(); pNew->m_nValue = value; pNew->m_pNext = NULL; if(*pHead == NULL) *pHead = pNew; else { ListNode* pNode = *pHead; while(pNode->m_pNext != NULL) pNode=pNode->m_pNext; pNode->m_pNext = pNew; } }
-
在單鏈表中找到第一個含有某個值的結點並刪除
void RemoveNode(ListNode** pHead,int value) { if(pHead == NULL || *pHead == NULL) return; //定義一個ListNode指針,用於釋放要刪除的結點 ListNode* pToBeDeleted = NULL; if((*pHead)->m_nValue == value) { pToBeDeleted = *pHead; *pHead = *pHead->m_pNext; } else { // 定義一個臨時的指針,用於遍歷鏈表以找到要刪除的結點(如果存在的話)的前一個結點 ListNode* pNode = *pHead; while(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue != value) pNode = pNode->m_pNext; if(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value) { pToBeDeleted = pNode->m_pNext; pNode->m_pNext = pNode->m_pNext->m_pNext; } if(pToBeDeleted != NULL) { delete pToBeDeleted; pToBeDeleted = NULL; } } }
重點問題:
-
為什么在添加和刪除函數參數中要用二級指針?
首先要說的是,函數的參數在傳遞的過程中,傳遞的是實參的一個拷貝
。在搜索別人的解釋的過程中,也有人反復強調的另一點是:指針也是有地址的
。ok,那么如果函數的參數是一級指針ListNode* pHead
,那么函數中使用的pHead是什么?答案是,指向頭結點的指針的副本,也就是另一個指向頭結點的指針。
好了,也就是說接下來在函數中所有的操作都是從這個臨時的pHead開始的。從我們的函數名來看,AddToTail
也就是從尾部插入,那這么看來,我只是從尾部插入新的結點,看起來並不影響頭指針。
那么問題來了,函數中的第七行的判斷,如果頭指針為空,也就是鏈表為空的時候,如果要新插入結點,那么從函數看來我們會改變頭指針pHead另其指向新結點。但是! 前邊我們說了,這個pHead只是函數中的一個 臨時變量,這個指針本身的地址不同於函數外實參指針的地址,而它雖然指向了新結點,但函數外本身傳入的頭指針仍然為 NULL!同理,在刪除結點的時候,如果要刪除的結點即第一個結點,使用一級指針也會出錯,此時會導致原頭指針指向的鏈表為空。最后是一個網上借來的圖:出自使用雙重指針實現鏈表結點的插入與刪除