问题:删除链表节点

要求:以O(1)时间

对于删除指定索引的链表元素大家都很熟悉,思路一般是从头遍历链表直到指定索引位置删除元素,然后维护一下指针即可,时间复杂度O(n)。代码如下:

 // 删除position位置的数据,并返回
int List::erasePosition(int position){
if(position< || position>(List::size()-)){
cout<<"position error, please check."<<endl;
return -;
}
int res = List::getValue(position);
Node *p = head;
int index = ;
cout<<"erase data at position "<<position<<endl;
if(position == ){
head = p->next;
return res;
}
else{
while(index != position-){
p = p->next;
index++;
}
Node *temp = p->next;
p->next = temp->next;
return res;
}
}

上述代码的完整版在这里

但是当删除指定地址的链表元素时,事情变得不太一样了,在这种情况下我们可以实现O(1)时间删除指定地址的数据。当然,以上是基于一个假设:要删除的节点一定在链表里面。

如上图所示,我们打算删除节点e,可以将节点e的后一个节点b的内容复制到节点e,即覆盖原有内容,然后删除后一个节点b。(这里我感觉待删除地址还是有节点的,只是内容变了,与直接删除节点e有相似的效果)

注意点:空指针与尾节点的情况(详见代码)

解题代码:

 void List::erase(Node *pDelete){
if (pDelete == nullptr)
return ;
// 删除的的节点不是尾节点
if(pDelete->next != nullptr){
Node *pNext = pDelete->next;
pDelete->data = pDelete->next->data;
pDelete->next = pNext->next;
delete pNext;
pNext = nullptr;
}
// 链表只有一个节点,删除第一个节点
else if(head == pDelete){
delete pDelete;
pDelete = nullptr;
head = nullptr;
}
// 链表中有多个节点,要删除尾节点
else{
Node *p = head;
while(p->next!= pDelete){
p = p->next;
}
p->next = nullptr;
delete pDelete;
pDelete = nullptr;
}
}

完整版代码:

 #include<iostream>
using namespace std; class Node {
public:
int data;
Node *next;
Node(int da):
data(da), next(NULL){}
}; class List{
public:
Node *head;
List(): head(NULL){}
~List(){
delete head;
cout<<"The list is deleted."<<endl;
};
int size();
int getValue(int position);
void printList(); // 打印链表
void insert(int position, int value); // 指定位置插入
void insertHead(int value); // 插入到最前
void insertTail(int value); // 插入到最后
int erasePosition(int position); // 删除指定位置的节点
void erase(Node *pDelete); }; // 返回position位置的数据
int List::getValue(int position){
if(position< || position>(List::size()-)){
cout<<"position error, please check."<<endl;
return -;
}
Node *p = head;
int index = ;
while(index != position){
p = p->next;
index++;
}
//cout<<"position "<<position<<" is "<<p->data<<endl;
return p->data;
} // 返回链表大小
int List::size(){
Node *p = head;
int index = ;
while(p != NULL){
index++;
p = p->next;
}
return index;
} // 打印链表
void List::printList(){
Node *p = head;
while(p != NULL){
cout<<p->data<<" ";
p = p->next;
}
cout<<endl;
cout<<endl;
} // 在position位置插入value
void List::insert(int position, int value){
if(position< || position>List::size()){
cout<<"position error, please check."<<endl;
return ;
}
Node *s = new Node(value); // new node
Node *p = head;
if(head == NULL){ // isEmpty = true
head = s;
}
else{ // isEmpty = false
if(position == ){
s->next = p;
head = s;
}
else{
int index = ;
while(index != position-){
p = p->next;
index++;
}
s->next = p->next;
p->next = s;
}
}
if (position == )
cout<<"insert "<<value<<" at the first."<<endl;
else if (position == List::size())
cout<<"insert "<<value<<" at the tail."<<endl;
else
cout<<"insert "<<value<<" at position "<<position<<endl;
} // 头部插入
void List::insertHead(int value){
List::insert(, value);
} // 尾部插入
void List::insertTail(int value){
List::insert(List::size(), value);
} // 删除position位置的数据,并返回
int List::erasePosition(int position){
if(position< || position>(List::size()-)){
cout<<"position error, please check."<<endl;
return -;
}
int res = List::getValue(position);
Node *p = head;
int index = ;
cout<<"erase data at position "<<position<<endl;
if(position == ){
head = p->next;
return res;
}
else{
while(index != position-){
p = p->next;
index++;
}
Node *temp = p->next;
p->next = temp->next;
return res;
}
} void List::erase(Node *pDelete){
cout<<"erase data at address "<<pDelete<<endl;
if (pDelete == nullptr)
return ;
// 删除的的节点不是尾节点
if(pDelete->next != nullptr){
Node *pNext = pDelete->next;
pDelete->data = pDelete->next->data;
pDelete->next = pNext->next;
delete pNext;
pNext = nullptr;
}
// 链表只有一个节点,删除第一个节点
else if(head == pDelete){
delete pDelete;
pDelete = nullptr;
head = nullptr;
}
// 链表中有多个节点,要删除尾节点
else{
Node *p = head;
while(p->next!= pDelete){
p = p->next;
}
p->next = nullptr;
delete pDelete;
pDelete = nullptr;
}
} int main() {
List l1;
l1.insertTail();
l1.insertHead();
l1.insert(, );
l1.insert(, );
l1.insert(, );
l1.insert(, );
l1.insert(, );
cout<<endl<<"The list is:"<<endl;
l1.printList();
l1.erasePosition();l1.printList();
l1.erase(l1.head);l1.printList();
return ;
}

运行结果:

 insert  at the first.
insert at the first.
insert at position
insert at the first.
insert at position
insert at the first.
insert at position The list is: erase data at position erase data at address 0x3b1a58 The list is deleted.
[Finished in .3s]

由于主函数传的是 l1.erase(l1.head); 所以应该是删除链表的第一个节点,可见结果正确。

剑指offer---以O(1)时间删除链表节点的更多相关文章

  1. 剑指offer.在O(1)时间内删除链表节点

    给定单向链表的一个节点指针,定义一个函数在O(1)时间删除该结点.假设链表一定存在,并且该节点一定不是尾节点. 样例 输入:链表 1->4->6->8 删掉节点:第2个节点即6(头节 ...

  2. 剑指offer之 O(1)时间删除链表结点

    问题描述:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. package Problem13; /* * 问题描述:给定单向链表的头指针和一个结点指针,定义一个函数在O(1 ...

  3. [剑指offer]Q13:O(1)时间删除链表的结点

    通常我们所说的删除链表的某个结点,是彻底删除该结点的空间.而要这么做就必须知道其前驱结点.这里的想法是,链表中存储的val是同类型的,仅仅要将该结点的val内容删除就能够了. 那么就能够用该结点的后继 ...

  4. [刷题] 剑指offer 面试题18:删除链表节点

    要求 给定单向链表的头指针和一个节点指针,在O(1)时间内删除该节点 常规思路:从头节点a开始顺序遍历,发现p指向要删除的节点i,然后把p的m_pNext指向i的下一个节点j,时间复杂度O(n) O( ...

  5. 【校招面试 之 剑指offer】第18题 删除链表中的节点

    题目一:在O(1)时间内删除链表节点. 给定单项链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点. 思路:(1)如果要删除的节点不是链表的尾节点,则将被删除节点的内容复制到该节点,然 ...

  6. 剑指offer13 在O(1)时间删除链表的结点

    把下一个节点的值直接赋值给要删除的节点,然后删除下一个节点.当这样做会有两个bad case:被删除的链表结点的下一个结点为空指针,如果链表只有一个结点.其实链表只有一个结点应该属于下一个结点为空指针 ...

  7. 剑指Offer(书):删除链表的节点

    题目:在O(1)的时间内删除列表节点. /** * 步骤: * 1.检查head与removeNode节点是否为空 * 2.检查removeNode的后一个节点是否为空,不为空则使用后一个节点的值覆盖 ...

  8. 【剑指offer】面试题 18. 删除链表的节点

    面试题 18. 删除链表的节点

  9. 【剑指Offer】面试题18. 删除链表的节点

    题目 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点. 返回删除后的链表的头节点. 注意:此题对比原题有改动 示例 1: 输入: head = [4,5,1,9], val = 5 ...

  10. [剑指Offer]18-题目一:删除链表的节点 题目二:删除链表中重复节点

    题目一 题目 O(1)时间复杂度删除给定链表节点. 题解 用待删除节点后一个节点的值覆盖待删除节点值,更新链接关系. 注意链表只有一个节点:删除尾结点:删除头节点的处理. 代码 class ListN ...

随机推荐

  1. HDU 5752Sqrt Bo

    Sqrt Bo Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total S ...

  2. 红米note怎么打开USB调试模式

    红米note到货后,打开USB调试模式是一些新手很棘手的问题,所以要手机助手成功识别红米note,你必须打开红米note的USB调试模式.在安卓4.2版本中,系统的USB调试模式不是非常简单地被打开的 ...

  3. luogu 4427 求和

    bjoi 2018 求和 唯一一道可能切的题一个数组还没开long long就成0分了 题目大意: 一棵有根树,并且希望多次询问这棵树上一段路径上所有节点深度的k次方和,而且每次的k可能是不同的 此处 ...

  4. 2017年最新VOS2009/VOS3000最新手机号段导入文件(手机归属地数据)

    VOS2009.vos3000.vos5000最新手机号段归属地数据库导入文件. 基于2017年4月最新版手机号段归属地制作 共360569条记录,兼容所有版本的昆石VOS,包括VOS2009.vos ...

  5. 【168】ENVI入门系列

    参考:ENVI-IDL中国的博客 [ENVI入门系列]01.ENVI产品简介与入门 [ENVI入门系列]02.自定义坐标系(北京54.西安80.2000坐标系) [ENVI入门系列]03.基于自带定位 ...

  6. P2470 [SCOI2007]压缩

    传送门 区间dp,记\(dp(l,r,t)\)表示区间\((l,r)\),\(t\)表示这个区间中能不能放\(M\).如果可以,枚举中间哪里放\(M\)来压缩.也可以不压缩,后面直接跟上去.如果左右重 ...

  7. [Swift]Array(数组)扩展

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  8. Mybatis Generator插件升级版

    一.目的: 1. *mapper.java 文件名称 改为*DAO.java2. mapper以及mapper.xml 重复执行,只会覆盖原模板方法,不会覆盖自定义方法3. 实体类添加中文注释 二.步 ...

  9. linux守护进程的编写

    linux监控一个进程进行 代码如下: #!/bin/sh cd /home/autoprocess/ auto=`pgrep -f autoProcessNew.php | wc -l` if [ ...

  10. mysql-5.7.20基本用法

    第1章 安装mysql-5.7.20 1.1 系统环境 [root@mysql ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (C ...