1. 在O(1)时间内删除链表节点
给定一个单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。
- 首先定义一个结构体表示链表元素
typedef struct ListNode* Link;
//写一个包括链表结构的结构体
struct ListNode
{
int val;
struct ListNode* next;
};
- 将链表元素存储在数组中,使用头插法创建链表
//创建链表
Link CreatLink(int a[],int length)
{
Link head;
//malloc和new的用法区别
//这样是有头节点的链表
// struct ListNode 和*Link的区别
head=(Link)malloc(sizeof(struct ListNode));
head->next=NULL;
Link phead;
phead=head;
for(int i=0;i<length;i++)
{
Link t;
t=(Link)malloc(sizeof(struct ListNode));
t->val=a[i];
phead->next=t;
phead=t;
//phead建立前一个节点的位置
//只是一个指针 没有分配实际的内存空间
t->next=NULL;
}
//head指向下一个表示跳过头节点
//head=head->next;
return head;
}
- 分析需要删除的节点在哪个位置?
平常需要删除一个节点,需要遍历链表找到对应的节点,需要 O ( n ) O(n) O(n)。
需要删除的节点无非三个地方:1.头节点 2.中间节点 3.尾节点
如果是头节点,则说明这个链表只有一个元素。因为对于待删除的节点来说,指出的是指针。如果两个指针相等,那么则表示是一个元素。所以返回NULL。如果是中间节点,我们其实不必去找该节点的前一个节点,可以用该节点的下一个节点去覆盖当前节点,然后删除其后续节点,代价为 O ( 1 ) O(1) O(1)。如果是尾节点,就没有办法,因为不知道前一个节点是什么,需要遍历链表,将前一个节点指向NULL,代价为 O ( N ) O(N) O(N)。综合来说, O ( 1 ) ∗ n − 1 + O ( n ) = O ( 1 ) O(1)*n-1+O(n)=O(1) O(1)∗n−1+O(n)=O(1),代价仍然是 O ( 1 ) O(1) O(1).
//指向指针的指针表示什么 应该是一个指向头节点的指针
//.和->的区别
void DeleteNode(ListNode** pListNode,ListNode* pToBeDeleted)
{
//判断是否为空链表 如果头节点为空则为空
if(pListNode==NULL)
return;
if(pToBeDeleted==NULL)
return;
//讨论被删除的这个节点是哪里的
//1.头节点 相等表示只有一个节点 那么删除之后就为空
if(*pListNode==pToBeDeleted)
{
delete pToBeDeleted;
pToBeDeleted=NULL;
*pListNode=NULL;
}
//2.不是尾节点 采用覆盖的办法
else if(pToBeDeleted->next!=NULL)
{
//p指向链表
ListNode* p=pToBeDeleted->next;
pToBeDeleted->val=p->val;
pToBeDeleted->next=p->next;
p->next=NULL;
//delete的作用?
delete p;
}
//3.是尾节点 没有办法覆盖 需要知道上一个
//不知道把哪个指向null
else
{
ListNode* p=*pListNode;
while(p->next->next!=NULL)
{
p=p->next;
}
p->next=NULL;
delete pToBeDeleted;
}
}
2. 知识点温习
malloc与new,delete
十点区别,来源网上(malloc与new的区别)
.与->
点运算符的左操作数是结构体。
箭头运算符的左操作数是指向结构体的指针。