- 问题描述:
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode{ int m_nValue; ListNode* m_pNext; };
-
分析:
老规矩,先考虑最简单粗暴的方法,既然是要删除结点,那么按照之前在数据结构中总结过的单链表节点的添加和删除中的思路,首先要找到要删除的结点的前一个结点,然后执行删除,简化版代码如下:
// 假设已找到要删除结点的前一个结点指针p ListNode* q = p->m_pNext; p->m_pNext = p->m_pNext->m_pNext; delete q; q = NULL;
显然这个题没这么简单,要求在O(1)时间删除结点,也就是说不能直接遍历链表去寻找要删除结点的点一个结点了。那么在给定要删除结点的指针的情况下,怎么才能直接删除掉它而不需要找到它的前一个结点呢?
于是我们想到,既然给定了一个指针,虽然我们没办法找到它的前一个结点,但是我们能够直接利用它删除它的下一个结点!只要我们把下一个结点的内容覆盖给定结点的内容,再删除下一个结点就可以了。
还有一个问题:如果要删除结点位于链表的尾部,那我们就不能删除它的后一个结点了,这个时候只能遍历链表,找到该结点的前一个结点,然后再删除。代码如下:void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) { if (!pListHead || !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 (*pListHead == pToBeDeleted) { // 链表中只有一个结点,删除头结点,令指针为NULL delete pToBeDeleted; pToBeDeleted = NULL; *pListHead = NULL; } else { // 要删除的结点是尾结点,没办法使用删除其下一个结点的方式,必须遍历链表 ListNode* pNode = *pListHead; while (pNode->m_pNext != pToBeDeleted) pNode = pNode->m_pNext; pNode->m_pNext = NULL; delete pToBeDeleted; pToBeDeleted = NULL; } }
以上我们默认的是要删除的结点存在的情况,并且要注意的是第15行,链表中只有一个结点的时候,删除后要令头指针为NULL。
晚来天欲雪,能饮一杯无?