版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/82423334
面试题18:删除链表的结点
在O(1)时间内删除链表结点
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
如果从表头开始找到这个结点(指针一样就是找到),需要O(n)的时间,但能确保这个结点就是在这个链表里。可以考虑将下一结点复制到该结点,再将下一结点删除,除了删除末尾结点不能这样做之外,其他情况都是O(1),平均也是O(1),不过需要调用者能确保这个结点就是在这个链表中。
#include<bits/stdc++.h>
#include "../Utilities/List.h"
using namespace std;
// 参数:
// pListHead: 指向头结点指针的指针
// pToBeDeleted: 指向要删除的结点的指针
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {
if(!pListHead || !pToBeDeleted)//输入非空检验
return;
//next非空,说明要删除的结点不是尾结点
if(pToBeDeleted->m_pNext != nullptr) {
ListNode* pNext = pToBeDeleted->m_pNext;//记录下一结点地址
pToBeDeleted->m_nValue = pNext->m_nValue;//将其值覆盖到当前结点
pToBeDeleted->m_pNext = pNext->m_pNext;//将当前结点的next指向原下一结点的next,绕过原下一结点
delete pNext;//删除刚刚抽出链表的原下一结点即可
pNext = nullptr;
}
//没满足上个if就说明是尾结点,如果同时还是头结点
else if(*pListHead == pToBeDeleted) {
delete pToBeDeleted;//也就说明只有这一个结点,直接将它删除即可
pToBeDeleted = nullptr;
*pListHead = nullptr;
}
//最后一种情况是,在链表中不止一个结点的情形下删除尾结点
else {
ListNode* pNode = *pListHead;//从头结点开始
//不断向下走,直到走到要删除的结点的前一个结点
while(pNode->m_pNext != pToBeDeleted) {
pNode = pNode->m_pNext;
}
//将该结点next指向空,成为尾结点
pNode->m_pNext = nullptr;
delete pToBeDeleted;//然后删除这个尾结点
pToBeDeleted = nullptr;
}
}
删除链表中重复的结点
在一个排序的链表中,删除重复出现的结点(一个不留)。
两个相邻的结点指针一起走,当走在前面的指针探测到前面有和自己值一样的结点时,让走在后面的结点指针所指向的结点的next指向后面比前面的指针所指向的结点的值大的结点,如此往复。
#include<bits/stdc++.h>
#include "../Utilities/List.h"
using namespace std;
//要删除的结点可能是头结点,所以要传入头结点地址的指针
//否则当删除头结点时,只改形参指针的地址值无法影响到调用者知道的头结点地址
void DeleteDuplication(ListNode** pHead) {
//输入非空校验
if(pHead == nullptr || *pHead == nullptr)
return;
//双指针初始化:第二个从头结点开始,第一个指向它前面的结点(一开始没有)
ListNode* pPreNode = nullptr;//前一结点
ListNode* pNode = *pHead;//[当前结点]
//遍历整个链表
while(pNode != nullptr) {
ListNode *pNext = pNode->m_pNext;//探测[当前结点]的下一结点
bool needDelete = false;//[当前结点]是否要被删除
//如果下一结点存在,且和[当前结点]值相同
if(pNext != nullptr && pNext->m_nValue == pNode->m_nValue)
needDelete = true;//那么[当前结点]是要删除的
//如果探测结果表明[当前结点]不需要删除
if(!needDelete) {
//那么双指针向后走一步
pPreNode = pNode;
pNode = pNode->m_pNext;
} else {//如果探测结果表明[当前结点]需要被删除,这时要向后找到下一类结点
int value = pNode->m_nValue;//记录要删除的这一串结点的共同值
ListNode* pToBeDel = pNode;//要被删除的结点从[当前结点]开始
//往后走,只要没到结尾,而且值和要删除的结点一致
while(pToBeDel != nullptr && pToBeDel->m_nValue == value) {
pNext = pToBeDel->m_pNext;//先获取下一结点,防止后续链表丢失
delete pToBeDel;//删除当前要删除的结点
pToBeDel = nullptr;
pToBeDel = pNext;//要删除的结点再指向原下一结点
}
//至此,这一串结点已经删除结束
if(pPreNode == nullptr)//如果前一结点为空,即不存在前置结点
*pHead = pNext;//说明刚刚删了开头的一串,要把头结点指向新发现的这类结点的第一个
else//否则,删除的不是开头的一串
pPreNode->m_pNext = pNext;//把前置结点的next指向新发现的结点,维持链表完整
pNode = pNext;//将[当前结点]指向新发现的结点
}
}
}