题目:以O(1)的时间复杂度删除单链表中的某个节点
自己所写代码如下:
//以O(1)时间删除链表节点 //要求:单向链表,头指针,待删节点指针//链表节点 struct ListNode {int m_nValue;ListNode* m_pNext; }; //O(n)的解法:从头遍历,找到pToBeDeleted所指节点的前一个节点再进行删除 void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {if(pListHead == NULL || *pListHead == NULL || pToBeDeleted == NULL)return;ListNode* pNode = *pListHead;if(pNode == pToBeDeleted) //对pToBeDeleted指向头结点情况的处理{*pListHead = (*pListHead)->m_pNext;delete pToBeDeleted;pToBeDeleted = NULL;}else{while(pNode->m_pNext != NULL && pNode->m_pNext != pToBeDeleted)pNode = pNode->m_pNext ;if(pNode->m_pNext == NULL){cout<<"pToBeDeleted不在链表中!"<<endl;return;}pNode->m_pNext = pToBeDeleted->m_pNext;delete pToBeDeleted;pToBeDeleted = NULL;}}//O(1)的解法:复制后一个节点以覆盖待删节点,再删除重复的后一个节点 void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {if(pListHead == NULL || *pListHead == NULL || pToBeDeleted == NULL)return;ListNode* pNode = *pListHead;if(pNode == pToBeDeleted){*pListHead = (*pListHead)->m_pNext;delete pToBeDeleted;pToBeDeleted = NULL;}else{pNode = pToBeDeleted->m_pNext;//排除pToBeDeleted指向尾节点的情形if(pNode == NULL){pNode = *pListHead;while(pNode->m_pNext != pToBeDeleted)pNode = pNode->m_pNext ;pNode->m_pNext = NULL;delete pToBeDeleted;pToBeDeleted = NULL;}else{pToBeDeleted->m_nValue = pNode->m_nValue;pToBeDeleted->m_pNext = pNode->m_pNext;delete pNode;pNode = NULL;}} }
在以上O(1)的代码中,自己的想法有些呆板,具体来说:采用复制覆盖的方法则应考虑的是pToBeDeleted指向尾节点的特殊情况(此时,无法复制!)
而非pToBeDeleted指向头结点的情况(这是O(n)的特殊情况!)!!!
O(n)的方法:需要找前驱节点,所以考虑头结点的特殊情况;
O(1)的方法:需要找后继节点,所以考虑尾节点的特殊情况。
代码修改如下:
//O(1)的解法:复制后一个节点以覆盖待删节点,再删除重复的后一个节点 void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {if(pListHead == NULL || *pListHead == NULL || pToBeDeleted == NULL)return;ListNode* pNode = pToBeDeleted->m_pNext;//排除pToBeDeleted指向尾节点的情形if(pNode == NULL){pNode = *pListHead;if(pNode == pToBeDeleted){delete pToBeDeleted;*pListHead = pToBeDeleted = NULL;}else{while(pNode->m_pNext != pToBeDeleted)pNode = pNode->m_pNext;pNode->m_pNext = NULL;delete pToBeDeleted;pToBeDeleted = NULL;}}else{pToBeDeleted->m_nValue = pNode->m_nValue;pToBeDeleted->m_pNext = pNode->m_pNext;delete pNode;pNode = NULL;}}
和参考代码相一致!赞一个!
总结:1、突破常规思维,删除节点不一定需要从头遍历链表,可以用下一结点复制并覆盖待删节点,最后再删除重复的下一结点。
2、考虑问题全面性:若待删节点为尾节点,则下一个节点为空;若整个链表仅一个节点,删除后,头结点同时设为NULL。
这些都需要特殊对待!!!