一、题目:反转链表

题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

  链表结点定义如下,这里使用的是C#描述:

    public class Node
{
public int Data { get; set; }
// 指向后一个节点
public Node Next { get; set; } public Node(int data)
{
this.Data = data;
} public Node(int data, Node next)
{
this.Data = data;
this.Next = next;
}
}

二、解题思路

2.1 借助外部空间的解法一

  由于题目并没有要求必须原地反转,因此可以借助外部空间实现。这里可以将单链表储存为数组,然后按照数组的索引逆序进行反转。但是,此方式比较浪费空间,而且需要两次遍历,效率不占优势

  依据上面的思路,我们可以写出以下代码:

    public static Node ReverseList1(Node head)
{
if(head == null)
{
return null;
} List<Node> nodeList = new List<Node>();
while (head != null)
{
nodeList.Add(head);
head = head.Next;
} int startIndex = nodeList.Count - ;
for (int i = startIndex; i >= ; i--)
{
Node node = nodeList[i];
if (i == )
{
node.Next = null;
}
else
{
node.Next = nodeList[i - ];
}
}
// 现在头结点是原来的尾节点
head = nodeList[startIndex];
return head;
}

2.2 逐节点插入到头结点之后的解法二

  从第2个节点到第n个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪栋到新链表的尾部。该思路避免了两次遍历链表,效率上有所提升。

    public static Node ReverseList2(Node head)
{
if (head == null)
{
return null;
} if(head.Next == null)
{
return head;
} Node start = head.Next;
head.Next = null;
Node temp = null;
while(start != null)
{
temp = start;
start = start.Next;
// 将第2到第N个节点指向头结点
temp.Next = head;
// 移动头节点指向下一个节点
head = temp;
}
return head;
}

-->

2.2 使用三个指针的高效解法二

  定义3个指针,分别指向当前遍历到的结点、它的前一个结点及后一个结点。在遍历过程中,首先记录当前节点的后一个节点,然后将当前节点的后一个节点指向前一个节点,其次前一个节点再指向当前节点,最后再将当前节点指向最初记录的后一个节点,如此反复,直到当前节点的后一个节点为NULL时,则代表当前节点时反转后的头结点了。

  整个过程只需遍历链表一次,效率提高不少,且需要的外部空间也较第一种方法要少很多,实现代码如下:

    public static Node ReverseList2(Node head)
{
if (head == null)
{
return null;
} Node reverseHead = null;
// 指针1:当前节点
Node currentNode = head;
// 指针2:当前节点的前一个节点
Node prevNode = null; while(currentNode != null)
{
// 指针3:当前节点的后一个节点
Node nextNode = currentNode.Next;
if(nextNode == null)
{
reverseHead = currentNode;
}
// 将当前节点的后一个节点指向前一个节点
currentNode.Next = prevNode;
// 将前一个节点指向当前节点
prevNode = currentNode;
// 将当前节点指向后一个节点
currentNode = nextNode;
} return reverseHead;
}

三、单元测试

3.1 测试用例

  (1)为了方便对比,封装了一个用于将链表所有元素输出为字符串的方法GetNodeString()

    // 辅助方法:生成链表元素的字符串用于对比
public string GetNodeString(Node head)
{
if (head == null)
{
return null;
} StringBuilder sbResult = new StringBuilder();
Node temp = head;
while (temp != null)
{
sbResult.Append(temp.Data.ToString());
temp = temp.Next;
} return sbResult.ToString();
}

  (2)功能测试、特殊输入测试

    // 01.输入的链表有多个结点
[TestMethod]
public void ReverseTest1()
{
Node node1 = new Node();
Node node2 = new Node();
Node node3 = new Node();
Node node4 = new Node();
Node node5 = new Node(); node1.Next = node2;
node2.Next = node3;
node3.Next = node4;
node4.Next = node5; Node newHead = ListHelper.ReverseList2(node1);
Assert.AreEqual(GetNodeString(newHead), "");
} // 02.输入的链表只有一个结点
[TestMethod]
public void ReverseTest2()
{
Node node1 = new Node(); Node newHead = ListHelper.ReverseList2(node1);
Assert.AreEqual(GetNodeString(newHead), "");
} // 03.输入NULL
[TestMethod]
public void ReverseTest3()
{
Node newHead = ListHelper.ReverseList2(null);
Assert.AreEqual(GetNodeString(newHead), null);
}

3.2 测试结果

  (1)测试通过情况

  (2)代码覆盖率

作者:周旭龙

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

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

剑指Offer面试题:15.反转链表的更多相关文章

  1. 剑指Offer:面试题16——反转链表(java实现)

    问题描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的链表的头结点.链表结点如下: public class ListNode { int val; ListNode next = n ...

  2. 【剑指offer 面试题15】链表中倒数第K个结点

    思路: 定义两个指针同时指向head,第一个指针先走K-1步,随后二个指针同时移动,当第一个指针到末尾处时,第二个指针所指向的即为倒数第K个结点. #include <iostream> ...

  3. 剑指offer面试题15:链表中倒数第K个节点

    题目:输入一个链表,输出该链表的倒数第K个节点.为了符合大多数人的习惯,本题从1开始计数,即链表尾节点是倒数第一个节点. 解题思路: 解法一:一般情况下,单向链表无法从后一个节点获取到它前面的节点,可 ...

  4. 剑指Offer:面试题15——链表中倒数第k个结点(java实现)

    问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...

  5. 剑指Offer - 九度1518 - 反转链表

    剑指Offer - 九度1518 - 反转链表2013-11-30 03:09 题目描述: 输入一个链表,反转链表后,输出链表的所有元素.(hint : 请务必使用链表) 输入: 输入可能包含多个测试 ...

  6. 剑指Offer面试题:14.链表的倒数第k个节点

    PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...

  7. 剑指offer 面试题35.复杂链表的复制

    时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...

  8. 剑指offer十五之反转链表

    一.题目 输入一个链表,反转链表后,输出链表的所有元素. 二.思路 详细分析见代码注释 三.代码 public class Solution {     public ListNode Reverse ...

  9. 剑指offer——面试题15:二进制中 1的个数

    // 面试题15:二进制中1的个数 // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如 // 把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. #inc ...

  10. 剑指Offer面试题15(Java版):链表中倒数第K个结点

    题目: 输入一个链表.输出该链表中倒数第k哥结点.  为了符合大多数人的习惯,本题从1開始计数.即链表的尾结点是倒数第1个结点. 比如一个链表有6个结点.从头结点開始它们的值依次是1.2.3,4,5, ...

随机推荐

  1. Entity Framework 6 Database-first连接Oracle11g

    Entity Framework 6 Database-first连接Oracle11g(图文细说) 本文发布地址:http://www.cnblogs.com/likeli/p/5577264.ht ...

  2. Winform窗体最大化的时候,如何指定窗体的位置、大小

    一.重写窗体的SizeChanged事件不能改变窗体最大化的位置和大小. public partial class Form2 : Form { public Form2() { Initialize ...

  3. 学习微信小程序之css12设置盒子内容的宽高

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 使用手机展示axure

    UC浏览器全屏,去地址栏 发布axure选项设置一下:参考http://sowm.cn/yixieshi/article/A752C3309457FBE32A99CA3A6A50B993.html 启 ...

  5. npm 基础

    npm账户 npm adduser npm whoami 初始化项目: npm init --scope=<username> 项目必要文件 README.md pageage.json: ...

  6. 64位主机64位oracle下装32位客户端ODAC(NFPACS版)

    64位主机64位oracle下装32位客户端ODAC(NFPACS版) by dd 1.下载Oracle Data Access Components(ODAC) Xcopy的两个版本: x86:(我 ...

  7. 通过 listboxitem 查找属于listbox第几条数据

    public override System.Windows.Style SelectStyle(object item, System.Windows.DependencyObject contai ...

  8. Python网络数据采集系列-------概述

    这是一个正在准备中的系列文章,主要参考的是<Web Scraping with Python_Collecting Data from the Modern Web-O'Reilly(2015) ...

  9. Unity5中WebGL平台封装的一些技巧

    最近在接触unity的WebGL平台,其实这个平台作为Web Player的替代品,已经能满足大部分的开发需求,而且不需要额外的插件支持,确实方便了不少,但开发中依旧遇到了不少问题,在这里记录和共享一 ...

  10. BZOJ2498 : Xavier is Learning to Count

    考虑容斥,通过$Bell(p)$的时间枚举所有等价情况. 对于一种情况,强制了一个等价类里面的数都要相同,其它的可以相同也可以不同. 这方案数显然可以通过多项式乘法求得,乘上容斥系数$(-1)^{p- ...