剑指offer--在O(1)时间内删除链表结点
記錄來自《劍指offer》上的算法題。
題目如下:
給定單向鏈表的頭指針和一個結(jié)點(diǎn)指針,定義一個函數(shù)在O(1)時間刪除該結(jié)點(diǎn)。
結(jié)點(diǎn)定義如下:
struct ListNode{int m_nValue;ListNode* m_pNext; };最常規(guī)的刪除鏈表結(jié)點(diǎn)方法是從頭結(jié)點(diǎn)開始遍歷,然后找到要刪除結(jié)點(diǎn)的前一個結(jié)點(diǎn),讓它指向要刪除結(jié)點(diǎn)的下一個結(jié)點(diǎn),但是這種做法的時間是O(n),而現(xiàn)在要求時間是O(1),所以就必須換一種方法,解法如下:
// 在O(1)時間內(nèi)刪除給定結(jié)點(diǎn)void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted){if (!pListHead || !pToBeDeleted)return;if (pToBeDeleted->m_pNext != NULL){// 要刪除的結(jié)點(diǎn)不是尾結(jié)點(diǎn)ListNode* pNext = pToBeDeleted->m_pNext;pToBeDeleted->m_nValue = pNext->m_nValue;pToBeDeleted->m_pNext = pNext->m_pNext;delete pNext;pNext = NULL;}else if (*pListHead == pToBeDeleted){// 鏈表只有一個結(jié)點(diǎn),刪除頭結(jié)點(diǎn),也就是尾結(jié)點(diǎn)delete pToBeDeleted;pToBeDeleted = NULL;*pListHead = NULL;}else{// 鏈表有多個結(jié)點(diǎn),刪除尾結(jié)點(diǎn),采取從頭開始遍歷ListNode* pNode = *pListHead;while (pNode->m_pNext != pToBeDeleted){pNode = pNode->m_pNext;}pNode->m_pNext = NULL;delete pToBeDeleted;pToBeDeleted = NULL;}}新解法的思路是將待刪除結(jié)點(diǎn)i的下一個結(jié)點(diǎn)j直接覆蓋在要刪除的結(jié)點(diǎn)上,然后再將結(jié)點(diǎn)j刪除,這樣就不需要找到結(jié)點(diǎn)i的前一個結(jié)點(diǎn)了。當(dāng)然,這是一般情況,如果待刪除結(jié)點(diǎn)是一個尾結(jié)點(diǎn),是有多個結(jié)點(diǎn)的鏈表的尾結(jié)點(diǎn),那么就只能采用最常規(guī)的辦法,從頭開始遍歷,但是前面n-1個非尾結(jié)點(diǎn)的時間復(fù)雜度是O(1),所以總的平均時間復(fù)雜度是[(n-1)*O(1) + O(n)]/n,結(jié)果還是O(1)。
測試代碼如下:
// 在鏈表結(jié)尾插入一個結(jié)點(diǎn)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 printList(ListNode* pHead){ListNode* p = pHead;if (!p)cout << "List is empty!\n";while (p != NULL){cout << p->m_nValue;if (p->m_pNext == NULL)cout << "\n";else{cout << ", ";}p = p->m_pNext;}}// 測試int main(void){ListNode* t = NULL;for (int i = 0; i < 10; i++)AddToTail(&t, i);cout << "List1:\n";printList(t);// 刪除多個結(jié)點(diǎn)鏈表中的一個結(jié)點(diǎn)ListNode* pNode1 = t->m_pNext;DeleteNode(&t, pNode1);printList(t);// 刪除多個結(jié)點(diǎn)鏈表中的頭結(jié)點(diǎn)ListNode* pNode2 = t;DeleteNode(&t, pNode2);printList(t);// 刪除多個結(jié)點(diǎn)鏈表中的尾結(jié)點(diǎn)ListNode* pNode3 = t;while (pNode3->m_pNext != NULL)pNode3 = pNode3->m_pNext;DeleteNode(&t, pNode3);printList(t);// 從只有一個結(jié)點(diǎn)的鏈表中刪除唯一的結(jié)點(diǎn)ListNode* t2 = NULL;AddToTail(&t2, 2);cout << "List2:";printList(t2);DeleteNode(&t2, t2);printList(t2);// 指向鏈表頭結(jié)點(diǎn)指針的是NULL指針DeleteNode(&t2, t2);// 指向要刪除結(jié)點(diǎn)的是NULL指針pNode3 = NULL;DeleteNode(&t, pNode3);system("pause");return 0;}更完整的例子可以查看我的Github。
總結(jié)
以上是生活随笔為你收集整理的剑指offer--在O(1)时间内删除链表结点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库:30种SQL语句优化,进阶必备!
- 下一篇: P2422 良好的感觉