给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点
思路:如果要用常规方法,找到被删除节点的前一节点,则需要顺序查找,时间复杂度是O(n) 所以要换一种方式 我们可以很方便地得到要删除的节点的下一节点,如果我们把下一节点的内容复制到需要删除的节点上,覆盖原有的内容,再把下一节点删除,就相当于删除所要删除的节点了
时间复杂度:对于n-1个非尾节点而言我们可以在O(1)时间实现操作,但对于尾节点而言,仍然需要顺序查找时间复杂度是O(n),所以平均复杂度是[(n-1)*O(1)+O(n)]/n,结果还是O(1),符合要求
注意:上述情况基于一个假设:要删除的节点的确在链表中,正常情况下我们需要O(n)的时间才能判断链表中是否包含某一节点,受到O(1)的限制,我们必须确保要删除节点在链表中
#include <stdio.h>
#include <iostream>
using namespace std;
struct ListNode
{
int _value;
struct ListNode* next;
};
ListNode* createList()
{
ListNode* head = new ListNode;
head->next = NULL;
return head;
}
void insert(ListNode* head,int value)
{
ListNode* cur = new ListNode;
cur->_value = value;
cur->next = head->next;
head->next = cur;
}
void TraversalList(ListNode* head)
{
if (head == NULL)
return;
ListNode* tmp= head->next;
while (tmp != NULL)
{
cout << tmp->_value<<endl;
tmp = tmp->next;
}
}
//只给一个链表的头指针和一个节点指针 这个head类型设置为**简直太特么重要了
void deleteList(ListNode** head, ListNode*cur)
{
if (head==NULL || cur==NULL) //节点不存在
return;
if (cur->next != NULL) //要删除的节点不是尾节点(中间节点)
{
ListNode* curNext = cur->next; //保存当前节点的下一节点
cur->_value = curNext->_value; //将下一节点的值赋值当前节点
cur->next = curNext->next; //将当前节点连接到下一个节点的下一个节点
delete curNext; //释放下一个节点
curNext = NULL; //将指针置为NULL
}
else if (*head == cur) //只有一个节点 头结点和尾节点相同
{
delete *head;
*head = NULL;
cur = NULL;
}
else //删除尾节点情况
{
ListNode* tmp = *head; //利用头指针的副本来移动
while (tmp->next != cur) //找到cur前一节点的位置
{
tmp = tmp->next;
}
tmp->next= NULL;
delete cur;
cur = NULL;
}
}
int main(int argc,char *argv[])
{
ListNode* head = createList();
ListNode* head1 = createList();
for (int i = 0; i < 4; i++)
{
insert(head,i);
}
TraversalList(head);
cout << "------------------" << endl;
//ListNode* cur = head->next; //中间节点
ListNode* cur = head->next->next->next->next; //尾节点
//deleteList(&head, head); //删除头节点
deleteList(&head, cur); //删除尾节点或中间节点
//deleteList(&head1, head1); //删除只有一个节点的情况
TraversalList(head);
return 0;
}