主要思想:把要求删除的节点的下个节点的值赋给待删节点,然后把下一个节点删除。这样时间复杂度是O(1)。之前通过待删除节点和该节点前面的节点,要通过从头节点开始遍历的方式找待删节点前面的节点,时间复杂度是O(n)
知识点:联系面试题5和6,可以看下我的博文
面试题5(基本涵盖下面的知识点1-5) https://blog.csdn.net/qq_34793133/article/details/80590992
面试题6(逆序打印链表)https://blog.csdn.net/qq_34793133/article/details/80571173
1.创建链表(可以同面试题5中尾部添加节点的方式或者本文的CreateNode()和ConnectNode()结合的方式),
2.添加节点,
3.查找节点,
4.删除节点,ToBeDeleteted前面的节点赋nullptr; delete ToBeDeleteted; ToBeDeleteted=nullptr
5.正序打印链表,
6.逆序打印链表
本题我写的代码如下:
#include <iostream>
using namespace std;
struct ListNode
{
ListNode* next;
int value;
};
ListNode* CreateNode(int n_value)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->next = nullptr;
node->value = n_value;
return node;
}
void ConnectNode(ListNode* node1, ListNode* node2)
{
node1->next = node2;
node2->next = nullptr;
}
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
//此处pListHead是指向指针的指针,即传指针:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
//如果是ListNode* pListHead,相当于传值:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,
//下面是有助于理解传值和传指针的简单例子,不懂的同学可以看下,我在本文末尾的注释
{
if (!pListHead || !pToBeDeleted)
return;
// 要删除的结点不是尾结点
if (pToBeDeleted->next != nullptr)
{
ListNode* pNext = pToBeDeleted->next;
pToBeDeleted->value = pNext->value;
pToBeDeleted->next = pNext->next;
delete pNext;
pNext = nullptr;
}
// 链表只有一个结点,删除头结点(也是尾结点),头结点得next指针域也是空
else if (*pListHead == pToBeDeleted)
{
delete pToBeDeleted;
pToBeDeleted = nullptr;
*pListHead = nullptr;
}
// 链表中有多个结点,删除尾结点
else
{
ListNode* pNode = *pListHead;
while (pNode->next != pToBeDeleted)
{
pNode = pNode->next;
}
pNode->next = nullptr;
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
}
void PrintList(ListNode* temp_print)
{
if (temp_print == nullptr)
printf("要打印的链表为空,请检查输入链表\n");
else
{
ListNode* temp2 = temp_print;
while (temp2 != nullptr)
{
printf("%d ", temp2->value);
temp2 = temp2->next;
}
printf("\n");
}
}
void Test1()
{
cout << "Test1 链表有多个节点且不做删除" << ": ";
ListNode* node1 = CreateNode(1);
ListNode* node2 = CreateNode(2);
ListNode* node3 = CreateNode(3);
ListNode* node4 = CreateNode(4);
ListNode* node5 = CreateNode(5);
ConnectNode(node1, node2);
ConnectNode(node2, node3);
ConnectNode(node3, node4);
ConnectNode(node4, node5);
ListNode* pHead = nullptr;
pHead = node1;
PrintList(pHead);
}
void Test2()
{
cout << "Test2 删除中间节点" << ": ";
ListNode* node1=CreateNode(1);
ListNode* node2=CreateNode(2);
ListNode* node3=CreateNode(3);
ListNode* node4=CreateNode(4);
ListNode* node5=CreateNode(5);
ConnectNode(node1, node2);
ConnectNode(node2, node3);
ConnectNode(node3, node4);
ConnectNode(node4, node5);
ListNode* pHead = nullptr;
pHead= node1;
DeleteNode(&pHead, node3);
PrintList(pHead);
}
void Test3()
{
cout << "Test3 链表中只有一个节点的情况" << ": ";
ListNode* node1 = CreateNode(1);
ListNode* pHead = nullptr;
pHead = node1;
DeleteNode(&pHead, node1);
PrintList(pHead);
}
void Test4()
{
cout <<"Test4 链表不止一个节点且删除尾节点" << ": ";
ListNode* node1 = CreateNode(1);
ListNode* node2 = CreateNode(2);
ListNode* node3 = CreateNode(3);
ListNode* node4 = CreateNode(4);
ListNode* node5 = CreateNode(5);
ConnectNode(node1, node2);
ConnectNode(node2, node3);
ConnectNode(node3, node4);
ConnectNode(node4, node5);
ListNode* pHead = nullptr;
pHead = node1;
DeleteNode(&pHead, node5);
PrintList(pHead);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
return 0;
}
运行结果
注释:关于形参实参之间传值和传指针的问题
有时间可以看我的这篇博客:https://blog.csdn.net/qq_34793133/article/details/80819690
没有时间可以简单看下这个小例子
#include <iostream>
using namespace std;
void fun1(int* a, int* b) //传指针,会因为形参的改变而改变对应的会改变实参a,b
{
//*a--;*b++;
(*a)--; (*b)++;
}
void fun2(int c, int d) // //传指针,不会因为形参的改变而改变对应的会改变实参a,b
{
c--; d++;
}
int main()
{
int a = 5; int b = 10;
int c = 5; int d = 10;
fun1(&a, &b);
fun2(c, d);
cout << a << " " << b << endl; //4 11
cout << c << " " << d << endl; //5 10
return 0;
}
本文是博主原创文章,未经博主允许不得转载