首页 技术 正文
技术 2022年11月9日
0 收藏 455 点赞 3,787 浏览 3117 个字

一、题目:在O(1)时间删除链表结点

题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

  原文采用的是C/C++,这里采用C#,节点定义如下:

    public class Node<T>
{
// 数据域
public T Item { get; set; }
// 指针域
public Node<T> Next { get; set; } public Node()
{
} public Node(T item)
{
this.Item = item;
}
}

  要实现的DeleteNode方法定义如下:

    public static void DeleteNode(Node<int> headNode, Node<int> deleteNode)
{
}

二、解题思路

2.1 常规思路

  在单向链表中删除一个结点,最常规的做法无疑是从链表的头结点开始,顺序遍历查找要删除的结点,并在链表中删除该结点。这种思路由于需要顺序查找,时间复杂度自然就是O(n)

剑指Offer面试题:12.在O(1)时间删除链表结点

2.2 正确思路

  是不是一定需要得到被删除的结点的前一个结点呢?答案是否定的。

  我们可以很方便地得到要删除的结点的一下结点。因此,我们可以把下一个结点的内容复制到需要删除的结点上覆盖原有的内容,再把下一个结点删除,就相当于把当前需要删除的结点删除了

剑指Offer面试题:12.在O(1)时间删除链表结点

  但是,还有两个特殊情况需要进行考虑:

  (1)如果要删除的结点位于链表的尾部,那么它就没有下一个结点:

  此时我们仍然从链表的头结点开始,顺序遍历得到该结点的前序结点,并完成删除操作,这仍然属于O(n)时间的操作。

  (2)如果链表中只有一个结点,而我们又要删除链表的头结点(也是尾结点):

  此时我们在删除结点之后,还需要把链表的头结点设置为NULL。

  最后,通过综合最坏情况(尾节点需要顺序查找,1次)和最好情况(n-1次),因此平均时间复杂度为:

剑指Offer面试题:12.在O(1)时间删除链表结点

  需要注意的是:受到O(1)时间的限制,我们不得不把确保结点在链表中的责任推给了函数DeleteNode的调用者

三、解决问题

3.1 代码实现

    public static void DeleteNode(Node<int> headNode, Node<int> deleteNode)
{
if (headNode == null || deleteNode == null)
{
return;
} if (deleteNode.Next != null) // 链表有多个节点,要删除的不是尾节点:O(1)时间
{
Node<int> tempNode = deleteNode.Next;
deleteNode.Item = tempNode.Item;
deleteNode.Next = tempNode.Next; tempNode = null;
}
else if (headNode == deleteNode) // 链表只有一个结点,删除头结点(也是尾结点):O(1)时间
{
deleteNode = null;
headNode = null;
}
else // 链表有多个节点,要删除的是尾节点:O(n)时间
{
Node<int> tempNode = headNode;
while(tempNode.Next != deleteNode)
{
tempNode = tempNode.Next;
} tempNode.Next = null;
deleteNode = null;
}
}

3.2 单元测试

  (1)封装返回结果

  该方法作为单元测试的对比方法,主要用来对比实际值与期望值是否一致:

    public static string GetPrintNodes(Node<int> headNode)
{
if (headNode == null)
{
return string.Empty;
} StringBuilder sbNodes = new StringBuilder();
while(headNode != null)
{
sbNodes.Append(headNode.Item);
headNode = headNode.Next;
} return sbNodes.ToString();
}

  (2)测试用例

    // 链表中有多个结点,删除中间的结点
[TestMethod]
public void DeleteNodeTest1()
{
Node<int> head1 = new Node<int>();
Node<int> head2 = new Node<int>();
Node<int> head3 = new Node<int>();
Node<int> head4 = new Node<int>();
Node<int> head5 = new Node<int>(); head1.Next = head2;
head2.Next = head3;
head3.Next = head4;
head4.Next = head5; Program.DeleteNode(head1, head3);
Assert.AreEqual(Program.GetPrintNodes(head1),"");
} // 链表中有多个结点,删除尾结点
[TestMethod]
public void DeleteNodeTest2()
{
Node<int> head1 = new Node<int>();
Node<int> head2 = new Node<int>();
Node<int> head3 = new Node<int>();
Node<int> head4 = new Node<int>();
Node<int> head5 = new Node<int>(); head1.Next = head2;
head2.Next = head3;
head3.Next = head4;
head4.Next = head5; Program.DeleteNode(head1, head5);
Assert.AreEqual(Program.GetPrintNodes(head1), "");
} // 链表中有多个结点,删除头结点
[TestMethod]
public void DeleteNodeTest3()
{
Node<int> head1 = new Node<int>();
Node<int> head2 = new Node<int>();
Node<int> head3 = new Node<int>();
Node<int> head4 = new Node<int>();
Node<int> head5 = new Node<int>(); head1.Next = head2;
head2.Next = head3;
head3.Next = head4;
head4.Next = head5; Program.DeleteNode(head1, head1);
Assert.AreEqual(Program.GetPrintNodes(head1), "");
} // 链表中只有一个结点,删除头结点
[TestMethod]
public void DeleteNodeTest4()
{
Node<int> head1 = new Node<int>(); Program.DeleteNode(head1, head1);
head1 = null;
Assert.AreEqual(Program.GetPrintNodes(head1), "");
} // 链表为空
[TestMethod]
public void DeleteNodeTest5()
{
Program.DeleteNode(null, null);
Assert.AreEqual(Program.GetPrintNodes(null), "");
}

  测试通过结果:

剑指Offer面试题:12.在O(1)时间删除链表结点

  (3)代码覆盖率

剑指Offer面试题:12.在O(1)时间删除链表结点

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,494
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,133
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,297