日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

删除单链表中的重复节点(c语言版本)

發布時間:2023/11/27 生活经验 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 删除单链表中的重复节点(c语言版本) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這是一道經典的面試題,下面是我的研究和舉一反三,特整理如下:

分為三種情形:

(1)刪除有序鏈表的重復節點,重復節點一個都不留

(2)刪除有序鏈表的重復節點,重復節點只留一個

(3)刪除無序鏈表的重復節點,重復節點只留一個

下面是相關節點的定義:

typedef struct ListNode {int val;struct ListNode *next;                                                      
} ListNode;ListNode* CreateListNode(int value){ListNode* pNode = (ListNode*)malloc(sizeof(ListNode));if(pNode == NULL){printf("failed to create ListNode\n");exit(-1);}   pNode->val = value;pNode->next = NULL;return pNode;
}      void ConnectListNodes(ListNode* pCurrent, ListNode* pNext){if(pCurrent == NULL || pNext == NULL){printf("Error to connect two nodes\n");exit(-1);}   pCurrent->next = pNext;
}      void DestroyListNode(ListNode* pNode){if(pNode != NULL){printf("-----delete list node [%d]-----\n", pNode->val);free(pNode);}   
}

下面給出解讀:

1)下面的代碼針對刪除有序單鏈表的重復節點,重復節點都刪除。

?

ListNode* DeleteDuplication(ListNode* pHead){if(pHead == NULL)return NULL;//指向當前節點前最晚訪問過的不重復節點;                                    ListNode* pPre = NULL;//指向當前正在處理的節點;ListNode* pCur = pHead;//指向當前節點后面的值相同的節點;ListNode* pNext = NULL;//臨時存放節點ListNode* pNode = NULL;while(pCur != NULL){//下一個節點與當前節點相同if(pCur->next != NULL && pCur->next->val == pCur->val){pNext = pCur->next;//找出所有與當前節點值相同的節點,因為是排序過的鏈表,它們都在一切while(pNext != NULL && pNext->val == pCur->val){pNode = pNext->next;DestroyListNode(pNext);pNext = pNode;}   //現在要刪除pCur->...->pNext->之間的所有節點//如果pCur是鏈表頭,要更新鏈表頭的位置if(pCur == pHead)pHead = pNext;elsepPre->next = pNext;DestroyListNode(pCur);pCur = pNext;}else{pPre = pCur;pCur = pCur->next;}   }   return pHead;
}

?2)下面是有序鏈表,只留一個的

//刪除有序鏈表中的重復節點,僅保留一個,使用2指針定位
//考慮到這里需要用到測試框架,這里必須使用二級指針
ListNode* DeleteDuplication(ListNode** pHead){if(pHead == NULL || *pHead == NULL)                                         return NULL;//指向當前正在處理的節點;ListNode* pCur = *pHead;//指向當前節點后面的值相同的節點;ListNode* pNext = NULL;//臨時存放節點ListNode* pNode = NULL;while(pCur != NULL){//下一個節點與當前節點相同if(pCur->next != NULL && pCur->next->val == pCur->val){pNext = pCur->next;//找出所有與當前節點值相同的節點,因為是排序過的鏈表,它們都在一切while(pNext != NULL && pNext->val == pCur->val){pNode = pNext->next;DestroyListNode(pNext);pNext = pNode;}   //將當前節點指向后續不同值的首個節點pCur->next = pNext;}   pCur = pCur->next;}       return *pHead;
} 

3)下面是無序鏈表,只留一個的(注意:這里會兼容前面的兩種情況)

//刪除無序鏈表中的重復節點,僅保留一個,使用2指針定位                           
//考慮到這里需要用到測試框架,這里必須使用二級指針
ListNode* DeleteDuplication(ListNode** pHead){if(pHead == NULL || *pHead == NULL)return NULL; //指向當前正在處理的節點;ListNode* p = *pHead;//用于遍歷p之后的節點;ListNode* q = NULL;ListNode* r = NULL;while(p != NULL){q = p;       //若后面有節點與當前節點相同,將其統統刪除while(q->next != NULL){if(q->next->val == p->val){//保存需要刪掉的節點r = q->next;//需要刪掉的節點的前后節點相接q->next = r->next;DestroyListNode(r);}        else{    q = q->next;}        }            p = p->next; }                return *pHead;   
}

下面是針對第三種情況編寫的用戶測試的截圖:

下面是我針對第三種情況的源碼實現:

//description: 描述刪除單鏈表的重復節點
//date: 2019-03-20#include <stdio.h>
#include <stdlib.h>
#include <time.h>typedef struct ListNode {int val;struct ListNode *next;
} ListNode;ListNode* CreateListNode(int value){ListNode* pNode = (ListNode*)malloc(sizeof(ListNode));if(pNode == NULL){printf("failed to create ListNode\n");exit(-1);}pNode->val = value;pNode->next = NULL;return pNode;
}void ConnectListNodes(ListNode* pCurrent, ListNode* pNext){if(pCurrent == NULL || pNext == NULL){printf("No necessary to connect two nodes\n");return;}pCurrent->next = pNext;
}void DestroyListNode(ListNode* pNode){if(pNode != NULL){printf("-----delete list node [%d]-----\n", pNode->val);free(pNode);}
}//在表頭節點后面拼接n個隨機元素的單鏈表
void CreateList(ListNode **pHead, int n){if(pHead == NULL || *pHead == NULL){printf("Invalid List header ptr\n");exit(-1);}int i;srand(time(0));ListNode *pNew, *pNode = *pHead;for(i=0; i<n; i++){pNew = (ListNode*)malloc(sizeof(ListNode));pNew->val = rand()%100 + 1;pNode->next = pNew;pNode = pNew;}pNode->next = NULL;
}void DestroyList(ListNode* pHead){ListNode *pNode = pHead;while(pNode != NULL){pHead = pNode->next;free(pNode);pNode = pHead;}
}void PrintList(ListNode* pHead){printf("------------print list begin-----------");ListNode* pNode = pHead;while(pNode != NULL){printf("%d ", pNode->val);pNode = pNode->next;}printf("------------print list end-------------");
}//==================業務函數定義到這里=============//刪除無序鏈表中的重復節點,僅保留一個,使用2指針定位
//考慮到這里需要用到測試框架,這里必須使用二級指針
ListNode* DeleteDuplication(ListNode** pHead){if(pHead == NULL || *pHead == NULL)return NULL;//指向當前正在處理的節點;ListNode* p = *pHead;//用于遍歷p之后的節點;ListNode* q = NULL;ListNode* r = NULL;while(p != NULL){q = p;//若后面有節點與當前節點相同,將其統統刪除while(q->next != NULL){if(q->next->val == p->val){//保存需要刪掉的節點r = q->next;//需要刪掉的節點的前后節點相接q->next = r->next;DestroyListNode(r);}else{q = q->next;}}p = p->next;}return *pHead;
}//==================測試代碼=======================
void Test(char* testName, ListNode** pHead, int* expectedValues, int expectedLength){if(testName != NULL)printf("%s begins:\n", testName);//======真正要干的活兒==========ListNode* pNode = DeleteDuplication(pHead);int idx = 0;while(pNode !=NULL && idx < expectedLength){if(pNode->val != expectedValues[idx])break;pNode = pNode->next;idx++;}if(pNode == NULL && idx == expectedLength)printf("%s Passed.\n", testName);elseprintf("%s FAILED.\n", testName);
}//--------------下面測試一些特例情況--------------//某些節點是重復的
void Test1(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(2);ListNode* pNode3 = CreateListNode(3);ListNode* pNode4 = CreateListNode(3);ListNode* pNode5 = CreateListNode(4);ListNode* pNode6 = CreateListNode(4);ListNode* pNode7 = CreateListNode(5);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ListNode* pHead = pNode1;int expectedValues[] = {1, 2, 3, 4, 5};Test("Test1", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//沒有節點重復
void Test2(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(2);ListNode* pNode3 = CreateListNode(3);ListNode* pNode4 = CreateListNode(4);ListNode* pNode5 = CreateListNode(5);ListNode* pNode6 = CreateListNode(6);ListNode* pNode7 = CreateListNode(7);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ListNode* pHead = pNode1;int expectedValues[] = {1, 2, 3, 4, 5, 6, 7};Test("Test2", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//除了一個節點之外其它所有節點的值都相同
void Test3(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(1);ListNode* pNode3 = CreateListNode(1);ListNode* pNode4 = CreateListNode(1);ListNode* pNode5 = CreateListNode(1);ListNode* pNode6 = CreateListNode(1);ListNode* pNode7 = CreateListNode(2);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ListNode* pHead = pNode1;int expectedValues[] = {1, 2};Test("Test3", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//所有節點的值都是相同的
void Test4(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(1);ListNode* pNode3 = CreateListNode(1);ListNode* pNode4 = CreateListNode(1);ListNode* pNode5 = CreateListNode(1);ListNode* pNode6 = CreateListNode(1);ListNode* pNode7 = CreateListNode(1);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ListNode* pHead = pNode1;int expectedValues[] = {1};Test("Test4", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//所有節點都成對出現
void Test5(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(1);ListNode* pNode3 = CreateListNode(2);ListNode* pNode4 = CreateListNode(2);ListNode* pNode5 = CreateListNode(3);ListNode* pNode6 = CreateListNode(3);ListNode* pNode7 = CreateListNode(4);ListNode* pNode8 = CreateListNode(4);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ConnectListNodes(pNode7, pNode8);ListNode* pHead = pNode1;int expectedValues[] = {1, 2, 3, 4};Test("Test5", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//除了兩個節點之外其它所有節點都成對出現
void Test6(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(1);ListNode* pNode3 = CreateListNode(2);ListNode* pNode4 = CreateListNode(3);ListNode* pNode5 = CreateListNode(3);ListNode* pNode6 = CreateListNode(4);ListNode* pNode7 = CreateListNode(5);ListNode* pNode8 = CreateListNode(5);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ConnectListNodes(pNode7, pNode8);ListNode* pHead = pNode1;int expectedValues[] = {1, 2, 3, 4, 5};Test("Test6", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//鏈表中只有兩個不重復的節點
void Test7(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(2);ConnectListNodes(pNode1, pNode2);ListNode* pHead = pNode1;int expectedValues[] = {1, 2};Test("Test7", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//鏈表中只有兩個重復的節點
void Test8(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(1);ConnectListNodes(pNode1, pNode2);ListNode* pHead = pNode1;int expectedValues[] = {1};Test("Test8", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//無序鏈表中某些節點是重復的
void Test9(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(11);ListNode* pNode2 = CreateListNode(2);ListNode* pNode3 = CreateListNode(3);ListNode* pNode4 = CreateListNode(3);ListNode* pNode5 = CreateListNode(9);ListNode* pNode6 = CreateListNode(4);ListNode* pNode7 = CreateListNode(5);ListNode* pNode8 = CreateListNode(5);ListNode* pNode9 = CreateListNode(3);ConnectListNodes(pNode1, pNode2);ConnectListNodes(pNode2, pNode3);ConnectListNodes(pNode3, pNode4);ConnectListNodes(pNode4, pNode5);ConnectListNodes(pNode5, pNode6);ConnectListNodes(pNode6, pNode7);ConnectListNodes(pNode7, pNode8);ConnectListNodes(pNode8, pNode9);ListNode* pHead = pNode1;int expectedValues[] = {11, 2, 3, 9, 4, 5};Test("Test9", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//鏈表中只有一個節點
void Test10(){//構建一個單鏈表ListNode* pNode1 = CreateListNode(1);ConnectListNodes(pNode1, NULL);ListNode* pHead = pNode1;int expectedValues[] = {1};Test("Test10", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));//刪除該單鏈表DestroyList(pHead);
}//空鏈表
void Test11(){ListNode* pHead = NULL;Test("Test11", &pHead, NULL, 0);
}int main(int argc, char** argv){Test1();Test2();Test3();Test4();Test5();Test6();Test7();Test8();Test9();Test10();Test11();return 0;
}

參考文獻

[1].《劍指Offer名企面試官精講典型編程題》第2版 面試題18-2

?

?

?

總結

以上是生活随笔為你收集整理的删除单链表中的重复节点(c语言版本)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。