單鏈表的插入(頭插、尾插、固定點插)刪除(頭刪、尾刪、按值刪一個,按值刪所有)
阿新 • • 發佈:2018-12-14
連結串列的插入:主要包含三種,頭插、尾插、固定位置插。
頭插:首先建立新的結點,然後修改指標。讓新結點的pNext = 頭結點,再讓頭結點->新結點
尾插:先找到最後一個結點,並把它記錄下來,再把最後一個結點的pNext域指向新的結點
固定位置插: 給定結點插入,插入到結點前(建立新結點,找到給定結點pPos的前一個結點cur,使得結點cur的pNext = 新結點;新結點的pNext = 該結點的pNext->pNext
主要的程式碼如下所示:
// 頭部插入(先建立新結點,然後修改指標.新結點的pNext = 頭結點,再讓頭結點->新結點) void SListPushFront(SListNode **ppFirst, DataType data) { SListNode *p;//新結點p SListNode *p1;//用來遍歷連結串列(開始位於頭結點處) p = _CreateNode(data); p1 = *ppFirst;//空連結串列的話,直接讓新結點做頭結點;有一個結點的話,和正常情況相同 p ->pNext = p1; *ppFirst = p; } // 尾部插入(先找到最後一個結點,並把它記錄下來,再把最後一個結點的pNext域指向新的結點) void SListPushBack(SListNode** ppFirst, DataType data) { SListNode *p;//新結點p SListNode *p1; p = _CreateNode(data); p1 = *ppFirst;//用來遍歷連結串列(開始位於頭結點處) //空連結串列 if( (*ppFirst) == NULL ){ *ppFirst = p; return; } else{ for(p1 = *ppFirst;p1->pNext != NULL;p1 = p1->pNext) { } p1 ->pNext = p;//此時p1為最後一個結點 } } // 給定結點插入,插入到結點前(建立新結點,找到給定結點pPos的前一個結點cur,使得結點cur的pNext = 新結點; //新結點的pNext = 該結點的pNext->pNext) void SListInsert(SListNode **ppFirst,SListNode *pPos, DataType data) { SListNode *cur;//宣告結點p,用來記錄頭結點 SListNode *p1; assert(&pPos); assert(*ppFirst); cur = *ppFirst; //在結點前做插入(結點pos肯定在連結串列中&&pos不是空) if(pPos == NULL&&(*ppFirst) == NULL) {//非法 return; } //若考慮pPos是第一個結點的情況下,無法找到前一個結點,陷入死迴圈.此時應該直接頭插 else if(pPos == *ppFirst) { SListPushFront(&ppFirst,data); return;//記得return 否則下邊加上else } //怎麼找pos的前一個結點(cur->next==pos就找到了) else{ while(cur ->pNext != pPos) { cur = cur ->pNext; } p1 = _CreateNode(data);//建立新結點 p1 ->pNext = pPos; cur ->pNext = p1; } }
連結串列的刪除:主要包含三種,頭刪、尾刪、按結點刪、按值刪(刪第一個、刪所有)。
頭刪:(先free掉第一個結點,再將頭結點後移一位)
尾刪:先尾部刪除(先找到倒數第二個結點,並記錄倒數第一個結點,再把倒數第二個結點的pNext域指向NULL;釋放掉最後一個結點
按結點刪 : 給定結點刪除(找到給定結點pPos的前一個結點cur,令cur->pNext = pPos->pNext,再free掉pPos
按值刪(刪第一個): 按值刪除,只刪遇到的第一個(查詢得到該位置cur,將cur->pNext = cur->pNext->pNext; 再free掉cur)
按值刪(刪所有):若只有一個結點,和正常情況刪除相同。只有一個結點並且第一個結點的值就是要刪除的值.將*ppFirst=NULL,再free(*ppFirst);多個結點,迴圈進行刪除。
主要的程式碼如下所示:
// 頭部刪除(先free掉第一個結點,再將頭結點後移一位) void SListPopFront(SListNode **ppFirst) { SListNode *p;//宣告結點p,用來記錄頭結點 assert(*ppFirst); p = *ppFirst;//用來遍歷連結串列(開始位於頭結點處) //直接後移頭指標.再釋放掉頭結點, *ppFirst = (*ppFirst)->pNext; free(p); } // 尾部刪除(先找到倒數第二個結點,並記錄倒數第一個結點, //再把倒數第二個結點的pNext域指向NULL;釋放掉最後一個結點) void SListPopBack(SListNode **ppFirst) { SListNode *p;//宣告結點p SListNode *p1; //記錄最後一個結點 assert(*ppFirst); p = *ppFirst;//用來遍歷連結串列(開始位於頭結點處) //只有一個結點,直接釋放掉該結點,頭指標指向NULL. if(p ->pNext == NULL) { free(p); *ppFirst = NULL; return; } for(p = *ppFirst;p->pNext->pNext != NULL;p = p->pNext) { }//此時p為倒數第二個結點 p1 = p->pNext;//p1為最後一個結點 free(p1); p->pNext = NULL; } // 給定結點刪除(找到給定結點pPos的前一個結點cur,令cur->pNext = pPos->pNext,再free掉pPos) void SListErase(SListNode **ppFirst, SListNode *pPos) { SListNode *cur; if(pPos == *ppFirst) { SListPopFront(&ppFirst); return;//記得return 否則下邊加上else } cur = *ppFirst; //找pos的前一個結點 while(cur ->pNext != pPos) { cur = cur ->pNext; } cur ->pNext = pPos->pNext; free(pPos); } // 按值刪除,只刪遇到的第一個(查詢得到該位置cur,將 //cur->pNext = cur->pNext->pNext; 再free掉cur) void SListRemove(SListNode **ppFirst, DataType data) { SListNode *cur ; SListNode *q ; SListNode *temp = *ppFirst; if((*ppFirst)->data == data) { *ppFirst =(*ppFirst)->pNext; free(temp); return; } if((*ppFirst)->pNext->data == data) { temp = (*ppFirst)->pNext; (*ppFirst) ->pNext = temp->pNext; free(temp); return; } for(cur = *ppFirst; cur ->pNext->data != data; cur = cur->pNext) { } q = cur->pNext; cur->pNext = q->pNext; free(q); return; } // 按值刪除,刪除所有的 //只有一個結點的情況和其他正常情況 void SListRemoveAll(SListNode **ppFirst, DataType data) { SListNode *cur; SListNode *pre; if(*ppFirst == NULL) { printf("連結串列無元素可刪除\n"); return -1; } pre = *ppFirst; cur = *ppFirst; //只有一個結點並且第一個結點的值就是要刪除的值.將*ppFirst=NULL,再free(*ppFirst) if((*ppFirst)->data==data&&(*ppFirst)->pNext==NULL) { *ppFirst=NULL; free(cur); return; } while(cur != NULL) { if(cur ->data == data) { pre->pNext = cur ->pNext; free(cur); cur=pre->pNext; continue;//如果找到了,釋放cur之後,此時應該cur = pre->pNext,繼續迴圈 } pre = cur; cur = cur ->pNext;//沒找到的情況,迴圈後移 } }
上述程式碼所包含的建立結點函式如下所示:
//建立新結點,結點的資料域為data,pNext域設定為空
SListNode *_CreateNode(DataType data)
{
SListNode *NewNode; //宣告新結點
NewNode = (SListNode *)malloc(sizeof(SListNode));//建立新結點
if(NewNode == NULL)
{
return;
}//建立失敗
NewNode ->data = data;
NewNode ->pNext = NULL;//建立成功
}
上述單鏈表插入與刪除的操作中的測試程式碼如下所示:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
SListNode *result;
SListNode *p1;
SListInit(&p1);
SListPushBack(&p1,1);
SListPushBack(&p1,2);
SListPushBack(&p1,3);
SListPushBack(&p1,2);
SListPushBack(&p1,5);
SListPushBack(&p1,2);
SListPushBack(&p1,6);
SListPushBack(&p1,1);
SListPushBack(&p1,2);
SListPushBack(&p1,3);
SListPushFront(&p1, 0);
SListPushFront(&p1,-1);
result = SListFind(p1,5);
SListInsert(&p1, result, 4);
SListPopBack(&p1);
SListPopFront(&p1);
result = SListFind(p1,3);
SListErase(&p1,result);
SListRemove(&p1, 4);
SListRemoveAll(&p1,2);
SListprint(p1);
SListDestroy(&p1);
SListprint(p1);
system("pause");
return 0;
}