三、函數定義
查找節點
//查找結點
SLTNode* SLTNodeFind(SLTNode* phead, SLTDataType x)
{assert(phead);SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}
查找節點我們是通過看數據域來查找的,查找節點函數的返回值類型是SLTNode* 因為不涉及到鏈表的修改,我們只需要傳值;同樣地,首=首先要斷言看鏈表是否為空;為了方便遍歷鏈表,我們定義一個節點pcur,在循環中沒經歷一個節點時,就拿這個節點地數據域的值和傳入的數據進行比較,直到最后一個幾點,如果某個節點的數據域的值和傳入的值相同,就返回這個節點,若是遍歷完鏈表還是找不到,說明這個鏈表沒有要查找的節點,那么就返回NULL。
相關測試:
?
指定位置之前插入數據
//在指定位置之前插入數據
void SLTInsertFront(SLTNode** pphead,SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* newnode = SLTBuyNode(x);SLTNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = newnode;newnode->next = pos;}
}
?需要配合SLNodeFind一起使用。鏈表不能為空,指定的位置處的節點也不能為空;先看到else中的內容,若是指定的位置不是頭節點,為傳入的數據申請一個新節點,循環找到pos前的節點,讓pre的next指針指向newnode,newnode的next指針指向pos,這樣就讓鏈表多了一個指定位置之前的節點;若是pos就是頭節點此時不能直接走else里面的內容,因為pre找不到,最終會是空,此時直接引用頭插方法。
相關測試:
??指定位置之后插入數據
//在指定位置之后插入數據
void SLTInsertBack(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);SLTNode* next = pos->next;pos->next = newnode;newnode->next = next;
}
不需要傳頭節點,因為不需要找到指定位置之前的節點,只需要pos和pos之后的節點,先把pos之后的節點給存起來,再讓pos的next指向newnode,再讓newnode的next指向原鏈表pos之后的節點。
刪除指定位置的節點
//刪除指定位置的數據
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);SLTNode* pre = *pphead;SLTNode* next = pos->next;if (pos == *pphead){SLTPopFront(pphead);}else{while (pre->next != pos){pre = pre->next;}free(pos);pos = NULL;pre->next = next;}
}
?同樣地,如果pos就等于*pphead那么直接循環則找不到pre,這個時候直接調用頭刪的函數;若是正常情況下,則先找到pos之前的節點,再釋放pos處的節點,最后讓pre的next指向next的節點(也就是原鏈表中pro的next節點)。
?刪除指定位置之后的節點
//刪除指定位置之后的數據
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
?我們需要找到pos下一個和pos下下個的節點,因為刪除了pos之后的節點之后要讓pos的next指向pos的下下個節點;若是直接先 (pos->next=pos->next->next)再(free(pos->next)),這樣會錯誤地刪除原本鏈表中pos的下下個節點;
為了避免這種錯誤,我們先定義一個del節點存放要刪除的節點,再讓pos的next指向pos的下下個節點,最后刪除del節點,因為此時的del的定義是在改變pos地next之前進行的,所以del代表的就是原鏈表pos的下一個節點并且不會改變,我們此時直接刪除del不會對新鏈表造成破壞,這樣就實現了該函數功能。
銷毀單鏈表
//銷毀單鏈表
void SLTDestroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;//SLTNode* next = NULL;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}
?銷毀單鏈表需要對其節點一個一個釋放;我們對下面這個鏈表進行銷毀并且調試觀察;
?在鏈表尾插完之后在內存中是這樣的:
在進行銷毀的前一刻內存中是這樣的:
銷毀了三次之后:
銷毀完節點并且讓*pphead置為空之后:
?如此就完成了單鏈表的銷毀。