剑指Offer面试题:15.反转链表
一、题目:反转链表
题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

链表结点定义如下,这里使用的是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)代码覆盖率

剑指Offer面试题:15.反转链表的更多相关文章
- 剑指Offer:面试题16——反转链表(java实现)
问题描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的链表的头结点.链表结点如下: public class ListNode { int val; ListNode next = n ...
- 【剑指offer 面试题15】链表中倒数第K个结点
思路: 定义两个指针同时指向head,第一个指针先走K-1步,随后二个指针同时移动,当第一个指针到末尾处时,第二个指针所指向的即为倒数第K个结点. #include <iostream> ...
- 剑指offer面试题15:链表中倒数第K个节点
题目:输入一个链表,输出该链表的倒数第K个节点.为了符合大多数人的习惯,本题从1开始计数,即链表尾节点是倒数第一个节点. 解题思路: 解法一:一般情况下,单向链表无法从后一个节点获取到它前面的节点,可 ...
- 剑指Offer:面试题15——链表中倒数第k个结点(java实现)
问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...
- 剑指Offer - 九度1518 - 反转链表
剑指Offer - 九度1518 - 反转链表2013-11-30 03:09 题目描述: 输入一个链表,反转链表后,输出链表的所有元素.(hint : 请务必使用链表) 输入: 输入可能包含多个测试 ...
- 剑指Offer面试题:14.链表的倒数第k个节点
PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...
- 剑指offer 面试题35.复杂链表的复制
时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...
- 剑指offer十五之反转链表
一.题目 输入一个链表,反转链表后,输出链表的所有元素. 二.思路 详细分析见代码注释 三.代码 public class Solution { public ListNode Reverse ...
- 剑指offer——面试题15:二进制中 1的个数
// 面试题15:二进制中1的个数 // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如 // 把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. #inc ...
- 剑指Offer面试题15(Java版):链表中倒数第K个结点
题目: 输入一个链表.输出该链表中倒数第k哥结点. 为了符合大多数人的习惯,本题从1開始计数.即链表的尾结点是倒数第1个结点. 比如一个链表有6个结点.从头结点開始它们的值依次是1.2.3,4,5, ...
随机推荐
- js new
如果一个函数前面带上new来调用该函数,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将被绑定到那个新对象上 即: function B(){} var a=new B( ...
- 为什么说在使用多条件判断时switch case语句比if语句效率高?
在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...
- PLSQL Developer 连接oracle(64) (instantclient)错误及解决方案
安装了PLSQL Developer 64bit,下载地址http://cy1.mqego.com/plsqldeveloperxx.zip. 1.安装完成后,输入数据库连接信息之后,提示如下错误 原 ...
- ring3硬件断点
4个断点寄存器DR0~DR3用来设置断点的线性地址. DR6为状态寄存器,DR7为控制寄存器. DR4和DR5保留.当CR4.DE==1时,访问DR4和DR5产生#UD异常:IF CR4.DE==0, ...
- [原创]Centos7 从零编译配置Redis
序言 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度. Memca ...
- 修改Linux系统日期与时间date clock
先设置日期 date -s 20080103 再设置时间 date -s 18:24:30 为了永久生效,需要将修改的时间写入CMOS. 查看CMOS的时间: #clock -r 将当前系统时间写到C ...
- python 爬虫(五)
下载媒体文件 I 使用urllib.request.urlretrieve方法可以下载文件存为指定文件 from urllib.request import urlretrieve from urll ...
- PHP unset()函数销毁变量 但没有实现释放内存
<?PHP $a = "hello";$b = &$a;unset( $b );echo $a; // 输出 helloecho $b; // 报错$b = &quo ...
- 单片机与控制实验(2)——LED点阵显示屏
一.实验目的和要求 了解LED点阵显示的基本原理和实现方法.掌握点阵汉字库的编码和从标准字库中提取汉字编码的方法. 二.实验设备 单片机测控实验系统 LED点阵显示器实验模块 Keil开发环境 STC ...
- Basic Calculator II
Implement a basic calculator to evaluate a simple expression string. The expression string contains ...