最近与人瞎聊,聊到各大厂的面试题,其中有一个就是用java实现单链表反转。闲来无事,决定就这个问题进行一番尝试。

1.准备链表

准备一个由DataNode组成的单向链表,DataNode如下:

public class DataNode {

    private int data;
private DataNode next;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DataNode getNext() {
return next;
}
public void setNext(DataNode next) {
this.next = next;
}
public DataNode(int data) {
this.data = data;
}
}

构造链表

public class DataChain {

    private  DataNode head;

    public DataChain(int size) {
DataNode head = new DataNode(0);
DataNode cur = head;
for (int i = 1; i < size; i++) {
DataNode tmp = new DataNode(i);
cur.setNext(tmp);
cur = tmp;
}
this.head = head;
} public DataNode getHead() {
return head;
} public void setHead(DataNode head) {
this.head = head;
} public static void printChain(DataNode head) {
StringBuilder sb = new StringBuilder();
DataNode cur = head;
sb.append(cur.getData());
while (null != cur.getNext()) {
sb.append(" -> ");
sb.append(cur.getNext().getData());
cur = cur.getNext();
}
System.out.println(sb.toString());
} public static void main(String... strings) {
DataChain chain = new DataChain(10);
printChain(chain.getHead());
}
}

运行main方法,即构造了一个包含10个node节点的单链表。

#运行结果
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

2.通过递归实现单链表反转

考虑到代码的简洁性,首先考虑的是通过递归实现。

 /**
* 递归实现 当栈深度大于12000 则会出现StakOverflowError
*
* @param head
* @return
*/
public static DataNode reverse1(DataNode head) {
if (null == head || null == head.getNext())
return head;
DataNode revHead = reverse1(head.getNext());
head.getNext().setNext(head);
head.setNext(null);
return revHead;
}

以上即是递归实现的源码,但是需要考虑的问题是递归都在java栈中进行,需要考虑jdk支持的栈的深度。在jdk1.8.0_91版本中,当上述链表长度大于12000则会出现StackOverFlowError错误。说明对于该版本jdk栈的深度不能大于12000。

3.通过遍历实现

最通用的实现方式就是遍历。

/**
* 遍历实现 通用实现方法
*
* @param head
* @return
*/
public static DataNode reverse2(DataNode head) {
if (null == head || null == head.getNext())
return head;
DataNode pre = head;
DataNode cur = head.getNext();
while (null != cur.getNext()) {
DataNode tmp = cur.getNext();
cur.setNext(pre);
pre = cur;
cur = tmp;
}
cur.setNext(pre);
head.setNext(null);
return cur;
}

4.借助stack实现

考虑到stack具有先进后出这一特性,因此可以借助于stack数据结构来实现单向链表的反转。

/**
* 方法3 利用其他数据结构 stack
* @param head
* @return
*/
public static DataNode reverse3(DataNode head) {
Stack<DataNode> stack = new Stack<DataNode>();
for (DataNode node = head; null != node; node = node.getNext()) {
stack.add(node);
}
DataNode reHead = stack.pop();
DataNode cur = reHead;
while(!stack.isEmpty()){
cur.setNext(stack.pop());
cur = cur.getNext();
cur.setNext(null);
}
return reHead;
}

上述实现方法在于操作简单,对于算法并不精通的同学可以尝试。缺点在于需要通过其他数据结构实现,效率会降低,至于效率会降低到什么程度,后面举例说明。

5.三种实现方式效率分析

    public static void main(String... strings) {
int size = 10; DataChain chain1 = new DataChain(size);
printChain(chain1.getHead());
long reverse1_start = System.currentTimeMillis();
DataNode reNode1 = reverse1(chain1.getHead());
long reverse1_cost = System.currentTimeMillis() - reverse1_start;
printChain(reNode1);
System.out.println("reverse1 cost time is ["+reverse1_cost+"]ms"); DataChain chain2 = new DataChain(size);
printChain(chain2.getHead());
long reverse2_start = System.currentTimeMillis();
DataNode reNode2 = reverse2(chain2.getHead());
long reverse2_cost = System.currentTimeMillis() - reverse2_start;
printChain(reNode2);
System.out.println("reverse2 cost time is ["+reverse2_cost+"]ms"); DataChain chain3 = new DataChain(size);
printChain(chain3.getHead());
long reverse3_start = System.currentTimeMillis();
DataNode reNode3 = reverse3(chain3.getHead());
long reverse3_cost = System.currentTimeMillis() - reverse3_start;
printChain(reNode3);
System.out.println("reverse3 cost time is ["+reverse3_cost+"]ms");
}

执行结果:

0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
reverse1 cost time is [0]ms
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
reverse2 cost time is [0]ms
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
reverse3 cost time is [1]ms

在上述代码基础上,去掉打印输出,将size改为10000,结果如下:

reverse1 cost time is [1]ms
reverse2 cost time is [0]ms
reverse3 cost time is [6]ms

可以看出reverse2 明显优于其他两种实现方法。考虑到reverse1最多只支持12000,因此将size改为100000时,再观察reverse2和reverse3之间的执行结果:

reverse2 cost time is [6]ms
reverse3 cost time is [25]ms

因此可以看出,最好的方法是采用遍历的方式进行反转。

java 单链表反转的更多相关文章

  1. Java单链表反转 详细过程

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/guyuealian/article/details/51119499 Java单链表反转 Java实 ...

  2. Java单链表反转图文详解

    Java单链表反转图文详解 最近在回顾链表反转问题中,突然有一些新的发现和收获,特此整理一下,与大家分享 背景回顾 单链表的存储结构如图: 数据域存放数据元素,指针域存放后继结点地址 我们以一条 N1 ...

  3. java单链表反转

    今天做leetcode,遇到了单链表反转.研究了半天还搞的不是太懂,先做个笔记吧 参考:http://blog.csdn.net/guyuealian/article/details/51119499 ...

  4. java单链表反转(花了半个多小时的作品)

    欢迎光临............... 首先我们要搞清楚链表是啥玩意儿?先看看定义: 讲链表之前我们先说说Java内存的分配情况:我们new对象的时候,会在java堆中为对象分配内存,当我们调用方法的 ...

  5. 单链表反转(Singly Linked Lists in Java)

    单链表反转(Singly Linked Lists in Java) 博客分类: 数据结构及算法   package dsa.linkedlist; public class Node<E> ...

  6. Java实现单链表反转操作

    单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据.二是指针域,用于存储下一个节点的地址.在Java中定义如下: public class ...

  7. java实现单链表反转(倒置)

    据说单链表反转问题面试中经常问,而链表这个东西相对于数组的确稍微难想象,因此今天纪录一下单链表反转的代码. 1,先定义一个节点类. 1 public class Node { 2 int index; ...

  8. 单链表反转java代码

    据说单链表反转问题面试中经常问,而链表这个东西相对于数组的确稍微难想象,因此今天纪录一下单链表反转的代码. 1,先定义一个节点类. public class Node { int index; Nod ...

  9. java单链表常用操作

    总结提高,与君共勉 概述. 数据结构与算法亘古不变的主题,链表也是面试常考的问题,特别是手写代码常常出现,将从以下方面做个小结 [链表个数] [反转链表-循环] [反转链表-递归] [查找链表倒数第K ...

随机推荐

  1. JS filter的使用

    定义和用法 filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素. 注意: filter() 不会对空数组进行检测. 注意: filter() 不会改变原始数组 ...

  2. 理解Web路由(浅谈前后端路由与前后端渲染)

    1.什么是路由? 在Web开发过程中,经常会遇到『路由』的概念.那么,到底什么是路由?简单来说,路由就是URL到函数的映射. 路由的概念最开始是由后端提出来的,在以前用模板引擎开发页面的时候,是使用路 ...

  3. 性能优化中CPU、内存、磁盘IO、网络性能的依赖

    系统优化是一项复杂.繁琐.长期的工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采集.评估.监测,而且是一个长期和持续的过程,不 是说现在优化了,测试了,以后就可以一劳永逸了,也不是说书本上 ...

  4. beyond compare解决特殊字符无法输出、多sheet页无法对比以及文件太大超出系统内存问题的Excel转txt脚本

    beyond compare解决特殊字符无法输出.多sheet页无法对比以及文件太大超出系统内存问题的Excel转txt脚本 ' XLS_to_CSV.vbs ' ' Converts an Exce ...

  5. 含有虚拟列的表 怎么用EXP导出?

    最近导一个测试库,报有虚拟列的表不支持,如下: EXP-00107: Feature (VIRTUAL COLUMN) of column CTB_CLIENT_SUBMIT_TIME_MONTH i ...

  6. mysql用户添加执行存储过程权限

  7. RAID技术全解图解-RAID0、RAID1、RAID5、RAID100【转】

    图文并茂 RAID 技术全解 – RAID0.RAID1.RAID5.RAID100…… RAID 技术相信大家都有接触过,尤其是服务器运维人员,RAID 概念很多,有时候会概念混淆.这篇文章为网络转 ...

  8. MySQL数据库事务的四大特性以及事务的隔离级别

    一.事务的四大特性(ACID) 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: 1.原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因 ...

  9. 初进python世界之数据类型

    文章来源: https://www.cnblogs.com/seagullunix/articles/7297946.html 基本运算符 常用数据类型: 字符串(Str) 数字(Digit) 列表( ...

  10. IDEA 开发javafx: error: java:package javafx.application does not exist

    1)jdk使用1.8, 1.7中未包含javafx相关内容. 2)确保classpath中加入了javafx包路径. 在“file” --> "project structure&qu ...