最近研究算法,遇到的一道颇有意思的问题——怎么把一个链表反转?
很容易想到一个方法:遍历链表,数组做栈存储路径,元素逐个出栈获得的就是反转后的链表!查找资料发现,有更好的方式实现。java
仔细研究后,终于明白了其中的奥妙。小僧掌握了两种方法,如下分别进行说明。node
首先给出链表结构:git
public class LinkedNode { Integer id ; LinkedNode next; public LinkedNode(Integer id) { this.id = id; } }
下一步构造出上图的链表结构:github
LinkedNode node1 = new LinkedNode(1); LinkedNode node2 = new LinkedNode(2); LinkedNode node3 = new LinkedNode(3); LinkedNode node4 = new LinkedNode(4); node1.next = node2; node2.next = node3; node3.next = node4;
先给出代码实现:算法
/** * 链表翻转,循环 + 双指针(pre、next)实现 * @param cur * @return */ public LinkedNode reverse(LinkedNode cur){ LinkedNode pre = null; while (cur!=null){ LinkedNode next = cur.next; // 1. cur.next = pre; // 2. pre = cur; // 3. cur = next; // 4. } return pre; }
循环体以前,链表示意图:数组
以后进入while
循环,注释标注的四个步骤会产生以下变化(图中编号与注释编号一一对应):this
第一次循环后,链表变成这样:spa
以后的遍历,链表的变化示意:指针
可见,while
循环执行完,pre
指向的节点,已是最新的头节点了!code
递归的实现方式,彷佛更容易理解。
/** * 链表反转,递归实现 * @param node * @return */ public LinkedNode reverse2(LinkedNode node){ if(node.next==null){ return node; } LinkedNode newHead = reverse2(node.next); node.next.next = node; //node.next.next 换成 newHead.next 不行,由于node在递归中在追溯上一个节点,仔细体会下 node.next = null; return newHead; }
首先会经过递归调用找到尾节点,以后作了两件事:
node.next.next = node;
)node.next = null;
)rentun newHead
后,回溯到节点2(此时node就是节点2),再次重复以前的两件事——节点反指和当前节点指向null节点。
再次回溯,获得最终的结果。
老规矩,完整代码见git:暗夜君王的demo练习——链表反转
Done !