如何在O(1)的时间里删除单链表的结点
生活随笔
收集整理的這篇文章主要介紹了
如何在O(1)的时间里删除单链表的结点
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目是這樣的:給你一個單鏈表的表頭,再給你其中某個結點的指針,要你刪除這個結點,條件是你的程序必須在O(1)的時間內完成刪除。
由于有的同學對鏈表還不是很熟悉,本文盡量描述的通俗易懂,老鳥請直接跳過前面一大段。
鏈表結構如下:
struct node {int val;node* next; };題目不是很難,很快就能想到好辦法:)
首先回顧一下普通的刪除方法,首先通過表頭,找到待刪除結點(設為B)的前一個結點(設為A),將A的指向改一下就行,然后刪除掉B結點就行了。要刪除的結點一定要delete掉,這不僅是個好習慣,而且能避免將來項目中可能造成的內存泄露的嚴重問題。
void DeleteNode_On(node *LinkList, node *p) {printf("delete:%d\n", p->val);node *s = LinkList;while(s->next != p)s = s->next;s->next = s->next->next;delete(p); }這個算法主要耗時在于查找前一個結點,所以是O(n)的算法。
那么既然要求是O(1),顯然不能再去for一遍了,聯想到數組的刪除,這個問題就比較好解決了。
首先我們很容易就能得到待刪除結點,即B結點的后一個結點C,然后將C的值賦值給B結點的值,相當于數組刪除時候的覆蓋,現在B結點和C結點一模一樣了,接下來就相當簡單了吧,我們不刪B,直接利用B刪掉C就行了,方法簡單,時間O(1)。
但是仔細想想這個算法有個很明顯的缺陷,如果待刪除結點是最后一個結點呢?這個時候似乎沒有什么好的解決辦法,只能老老實實的O(n)了。現在我們來看看平均時間復雜度:
符合題目要求。
void DeleteNode_O1(node *LinkList, node *p) {printf("delete:%d\n", p->val);if(p->next != NULL) //如果p不是末尾結點, 則讓后一個結點覆蓋掉p, 然后刪除后一個結點{p->val = p->next->val;node *tmp = p->next;p->next = p->next->next;delete(tmp);}else // 如果p是末尾結點, 則找到p的前一個結點然后正常刪除{node *s = LinkList;while(s->next != p)s = s->next;s->next = s->next->next;delete(p);} }最后附上完整測試代碼: #include<iostream>using namespace std;struct node {int val;node* next; };void CreateLinkList(node *LinkList) {node *s = LinkList;for(int i = 0; i < 10; i++){node *t = new node;t->val = i;t->next = NULL;s = s->next = t;} }void ShowLinkList(node * LinkList) {node *s = LinkList->next;while(s = s->next)printf("%d ", s->val);putchar(10); }void DeleteNode_On(node *LinkList, node *p) {printf("delete:%d\n", p->val);node *s = LinkList;while(s->next != p)s = s->next;s->next = s->next->next;delete(p); }void DeleteNode_O1(node *LinkList, node *p) {printf("delete:%d\n", p->val);if(p->next != NULL) //如果p不是末尾結點, 則讓后一個結點覆蓋掉p, 然后刪除后一個結點{p->val = p->next->val;node *tmp = p->next;p->next = p->next->next;delete(tmp);}else // 如果p是末尾結點, 則找到p的前一個結點然后正常刪除{node *s = LinkList;while(s->next != p)s = s->next;s->next = s->next->next;delete(p);} }int main() {node *LinkList = new node;CreateLinkList(LinkList);ShowLinkList(LinkList);node *p = LinkList->next;for(int i = 0; i < 3; i++)p = p->next;DeleteNode_On(LinkList, p);ShowLinkList(LinkList);p = LinkList->next;for(int i = 0; i < 8; i++)p = p->next;DeleteNode_O1(LinkList, p);ShowLinkList(LinkList);p = LinkList->next;for(int i = 0; i < 4; i++)p = p->next;DeleteNode_O1(LinkList, p);ShowLinkList(LinkList);getchar();return 0; } void DeleteNode(ListNode** pHead, ListNode* pToBeDeleted){//刪除鏈接節點算法 時間復雜度為O(1);if (!pHead || !pToBeDeleted){return;}if (pToBeDeleted->m_pNext != NULL){ListNode* pNext = pToBeDeleted->m_pNext;pToBeDeleted->m_nValue = pNext->m_nValue;pToBeDeleted->m_pNext = pNext->m_pNext;delete pNext;pNext = NULL;}else if (*pHead ==pToBeDeleted){delete pToBeDeleted;pToBeDeleted = NULL;*pHead = NULL;}else{ListNode* pNode = *pHead;while (pNode->m_pNext != pToBeDeleted){ pNode = pNode->m_pNext;}pNode->m_pNext = NULL;delete pToBeDeleted;pToBeDeleted = NULL;} } void Test(ListNode* pListHead, ListNode* pNode){printf("the original list is:\n");PrintList(pListHead);printf("The node to be deleted is:\n");PrintList(pNode);DeleteNode(&pListHead, pNode);printf("the result list is:\n");PrintList(pListHead); }void Test1(){ListNode* pNode1 = CreateListNode(1);ListNode* pNode2 = CreateListNode(2);ListNode* pNode3 = CreateListNode(3);ListNode* pNode4 = CreateListNode(4);ListNode* pNode5 = CreateListNode(5);CoonnectListNode(pNode1, pNode2);CoonnectListNode(pNode2, pNode3);CoonnectListNode(pNode3, pNode4);CoonnectListNode(pNode4, pNode5);Test(pNode1, pNode5);DestroyList(pNode1);}
總結
以上是生活随笔為你收集整理的如何在O(1)的时间里删除单链表的结点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于双向链表的增删改查和排序(C++实现
- 下一篇: 关于整型数据符号位扩展的问题