单向链表在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.(注意,输出结果中请不要返回参数中的节点引用 ...
随机推荐
- 【转载】Java并发编程:volatile关键字解析(写的非常好的一篇文章)
原文出处: 海子 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volat ...
- spring整合JMS
浏览博客时看到大神写的,直接转载过来收藏了.原文地址:http://elim.iteye.com/blog/1893038
- 【洛谷1131】【ZJOI2007】时态同步
题面 题目描述 小Q在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3-.进行标号.电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两 ...
- [HDU2296]Ring
vjudge Description For the hope of a forever love, Steven is planning to send a ring to Jane with a ...
- [HAOI2010]软件安装
简单的tarjan+(本蒟蒻刚刚接触不久)恶心的树形DP 题面 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为 ...
- 使用Ant打包Java后台程序
概述 本文通过一个简单的Java Application例子描述如何用ANT完成基本的程序打包工作.包含文件拷贝.编译.打包三部分:完成这三部就可以得到一个可运行的程序包了. ANT的安装,环境变量的 ...
- oracle 裸设备划分 --centos6.5
主题思想:物理卷PV->卷组VG->逻辑卷LV(类型:raw)->添加表空间 操作过程 vg_orcl 8g 一:划分 二:创建裸设备 方法1:目前最常用的方法 #c ...
- clientTop,scrollTop,兼容
在开发中常见的额兼容性问题: scrollTop问题: function scroll() { // 开始封装自己的scrollTop if(window.pageYOffset != null) { ...
- 【MyBatis】MyBatis自动生成代码查询之爬坑记
前言 项目使用SSM框架搭建Web后台服务,前台后使用restful api,后台使用MyBatisGenerator自动生成代码,在前台使用关键字进行查询时,遇到了一些很宝贵的坑,现记录如下.为展示 ...
- node,cnpm安装和配置
作为一个前端人员,node已经是必备. 1.下载 下载地址:https://nodejs.org/zh-cn/download/ 选择相应的版本下载 2.解压缩 将文件解压到要安装的位置,并新建两个目 ...