单向链表在O(1)时间内删除一个节点
说删链表节点,第一时间想到就是遍历整个链表,找到删除节点的前驱,改变节点指向,删除节点,但是,这样删除单链表的某一节点,时间复杂度就是O(n),不符合要求;
时间复杂度是O(n)的做法就不说了,看看O(1)的写法,看图:
删除节点,需要找到被删节点的前驱,上面的说明,交换数据后,要删的节点转换为被删节点的后一个节点,此时被删节点前驱可以知道,删除就很简单了
给出被删节点指针,O(1)时间内就可以有此方法删除节点,但是,如果,被删节点是链表最后一个节点,以上方法明显不在适用,不得不从头遍历:
这时就得从头遍历,只为找最后一个节点的前驱,就这唯一一个节点,找它的时间复杂度就是O(n),但平均时间复杂度为:
((n-1)*O(1)+O(n))/n
结果还是O(1),复合要求的,又但是,这里没有考虑要删除的节点是否在链表中,如果要判断有没有在链表中,又得遍历,结果时间复杂度有不在是O(1),
为了保证时间,被删的节点有没有在链表中,只能由人为的去控制;以下是代码段:
//在O(1)时间内,删除一个节点,函数如下
void DeleteNodeNumone(ListNode** phead,ListNode* pToBeDelete)
{
if (*phead == nullptr || pToBeDelete == nullptr)
return; //删除非尾节点
if (pToBeDelete->_next != nullptr)
{
ListNode* temp = pToBeDelete->_next;
pToBeDelete->_data = temp->_data;
pToBeDelete->_next = temp->_next; delete temp;
temp = nullptr;
} //只有一个节点
else if (*phead == pToBeDelete)
{
delete pToBeDelete;
pToBeDelete = nullptr;
*phead = nullptr;
} //最后一种,删除节点是尾节点
else
{
ListNode* cur = *phead;
while (cur->_next != pToBeDelete)
{
cur = cur->_next;
}
delete pToBeDelete;
pToBeDelete = nullptr;
cur->_next = nullptr;
}
}
完整测试代码:
#pragma once
typedef int DataType; class ListNode
{
public:
ListNode(const DataType& x)
:_data(x)
, _next(NULL)
{} public:
DataType _data;
ListNode* _next;
}; class Slist
{
public:
Slist()
:_head(NULL)
, _tail(NULL)
{}
~Slist()
{
//析构函数,删除节点,删除全部
Destory();
} void Destory()
{
ListNode* begin = _head;
while (begin)
{
ListNode* del = begin;
begin = begin->_next;
delete del;
}
} public:
//尾插
void PushBack(const DataType& x)
{
if (_head == NULL)
{
_head = new ListNode(x); _tail = _head;
}
else
{
_tail->_next = new ListNode(x);
_tail = _tail->_next;
}
} //查找
ListNode* Find(const DataType& x)
{
ListNode* tmp = _head;
while (tmp)
{
if (tmp->_data == x)
return tmp;
else
{
tmp = tmp->_next;
}
}
return NULL;
} // //在O(1)时间内,删除一个节点,函数如下
void DeleteNodeNumone(ListNode** phead,ListNode* pToBeDelete)
{
if (*phead == nullptr || pToBeDelete == nullptr)
return; //删除非尾节点
if (pToBeDelete->_next != nullptr)
{
ListNode* temp = pToBeDelete->_next;
pToBeDelete->_data = temp->_data;
pToBeDelete->_next = temp->_next; delete temp;
temp = nullptr;
} //只有一个节点
else if (*phead == pToBeDelete)
{
delete pToBeDelete;
pToBeDelete = nullptr;
*phead = nullptr;
} //最后一种,删除节点是尾节点
else
{
ListNode* cur = *phead;
while (cur->_next != pToBeDelete)
{
cur = cur->_next;
}
delete pToBeDelete;
pToBeDelete = nullptr;
cur->_next = nullptr;
}
} void print()
{
ListNode* begin = _head;
while (begin)
{
cout << begin->_data << "->";
begin = begin->_next;
}
cout << "NULL" << endl;
} public:
ListNode* _head;
ListNode* _tail;
};
void Test()
{
Slist s1;
s1.PushBack(5);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(2);
s1.PushBack(1);
s1.PushBack(6);
s1.PushBack(7);
s1.PushBack(9);
s1.print(); ListNode* num =s1.Find(9); s1.DeleteNodeNumone(&s1._head, num); s1.print();
}
测试结果:
赐教!
单向链表在O(1)时间内删除一个节点的更多相关文章
- LeetCode-450 二叉搜索树删除一个节点
二叉搜索树 建树 删除节点,三种情况,递归处理.左右子树都存在,两种方法,一种找到左子树最大节点,赋值后递归删除.找右子树最小同理 class Solution { public: TreeNode* ...
- Linus:利用二级指针删除单向链表
Linus大神在slashdot上回答一些编程爱好者的提问,其中一个人问他什么样的代码是他所喜好的,大婶表述了自己一些观点之后,举了一个指针的例子,解释了什么才是core low-level codi ...
- 【转】Linus:利用二级指针删除单向链表
原文作者:陈皓 原文链接:http://coolshell.cn/articles/8990.html 感谢网友full_of_bull投递此文(注:此文最初发表在这个这里,我对原文后半段修改了许多, ...
- 转:Linus:利用二级指针删除单向链表
感谢网友full_of_bull投递此文(注:此文最初发表在这个这里,我对原文后半段修改了许多,并加入了插图) Linus大婶在slashdot上回答一些编程爱好者的提问,其中一个人问他什么样的代码是 ...
- 在O(1)的时间内删除链表节点
题目: 在O(1)的时间内删除链表节点.给定链表的头指针和待删除的节点指针,定义一个函数在O(1)的时间内删除该节点. 剑指offer的思路,顿时觉得极妙.删除节点node1,先把其下一个节点node ...
- 用Python写单向链表和双向链表
链表是一种数据结构,链表在循环遍历的时候效率不高,但是在插入和删除时优势比较大. 链表由一个个节点组成. 单向链表的节点分为两个部分:存储的对象和对下一个节点的引用.注意是指向下一个节点. 而双向链表 ...
- Reverse Linked List II 单向链表逆序(部分逆序)
0 问题描述 原题点击这里. 将单向链表第m个位置到第n个位置倒序连接.例如, 原链表:1->2->3->4->5, m=2, n =4 新链表:1->4->3-& ...
- 数据结构——求单向链表的倒数第K个节点
首先,对于链表来说,我们不能像数组一样直接访问,所以我们想到要求倒数第K个节点首先要知道最后一个节点. 然后从最后一个节点往前数K个. 最后得到想要的值. 但是这是不对的,为什么呢?因为题目给出的是单 ...
- 剑指offer25:复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),结果返回复制后复杂链表的head。
1 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数中的节点引用 ...
随机推荐
- each遍历的用法
- 【BZOJ1857】传送带(三分)
[BZOJ1857]传送带(三分) 题面 Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P, ...
- APIO2010特别行动队
斜率优化 # include <stdio.h> # include <stdlib.h> # include <iostream> # include <s ...
- 使用 vscode将本地项目上传到github以及删除github上的某个文件夹
安装Git后,可以看到windows环境下有两个命令输入窗口Git CMD 和Git Bash Git GUI是可视化图形界面 Git中的Bash是基于CMD的,在CMD的基础上增添一些新的命令与功能 ...
- 为eclipse安装subclipse(SVN插件)
1.打开eclipse,点击菜单Help->Install New Software 2.进入安装窗体后,点击安装窗体的右侧的Add按钮,然后在弹出的窗体中输入名称:Subclipse 1.12 ...
- python-kafka实现produce与consumer
1.python-kafka: api送上:https://kafka-python.readthedocs.io/en/latest/apidoc/KafkaConsumer.html 2.实现一个 ...
- C#多线程编程(7)--锁
一提到线程同步,就会提到锁,作为线程同步的手段之一,锁总是饱受质疑.一方面锁的使用很简单,只要在代码不想被重入的地方(多个线程同时执行的地方)加上锁,就可以保证无论何时,该段代码最多有一个线程在执行: ...
- 本地安装plsql和instantclient连接linux服务器端的oracle
当虚拟机里面的linux服务器安装好oracle之后(具体安装方法在之前的博客有说到),如何连接使用呢?连接过程中会出现什么问题呢? 1.首先我们下载instantclient的压缩包,直接解压就好, ...
- canvas 绘制图形
canvas 绘制图形: 注意: canvas 的宽高设置在行内,否则会使画布(canvas)产生扭曲,绘图变形: <!DOCTYPE html> <html lang=" ...
- FineReport破解心得
注:写文档目的主要用于技术学习,了解技术帆软公司技术大牛是怎么设计系统,请勿用于商用. 一. 工具准备 1. javassist:class代码修改工具 2. ...