阅读本篇文章大约花费您4~5分钟!
链表是非常重要的一种数据结构,插入和删除的效率都是O(1),但是查找的效率比较低是O(n)。在单链表中,经常会遇到逆序单链表的题目,虽然听起来很简单,但是要想完整无误的写出代码,还是有很多细节要注意的。
今天给大家介绍两个思路来分析这个问题。
首先我们要知道单链表逆序的本质就是将节点的next指针指向它的前一个节点;并且完成逆序操作,至少要知道三个节点才可以。这是我们继续分析的基石。
假设有一个单链表(节点数为4个),三个节点的引用分别为p1,p2,p3;
思路一
思路一的思想是知道三个节点,核心操作为p2.next=p1,然后三个节点依次向后移动,结束后再修改头指针head。
结束的条件是p2==null。
我们可以用图示的形式看一下这个过程:
结束后再将头的next指向p1即可。
这种方法有一个问题,也体现在图中,在头两个节点间存在了环,因此遍历时可能出现死循环,在代码中应该将第一个节点的next置为null。
/*单链表节点类*/
public class SinglyNode<T> {
protected T data;
protected SinglyNode<T> next;
public SinglyNode() {
this(null,null);
}
public SinglyNode(T data) {
this(data,null);
}
public SinglyNode(T data,SinglyNode<T> next) {
this.data=data;
this.next=next;
}
@Override
public String toString() {
return data.toString();
}
}
/*单链表逆序*/
public SinglyList reverse(SinglyList<T> list) {
//保证只有>=2个节点时才做逆序操作
if(list.head.next==null||list.head.next.next==null) {
return list;
}
SinglyNode<T> p1=list.head.next;
SinglyNode<T> p2=list.head.next.next;
SinglyNode<T> p3=null;
while(p2!=null) { //结束条件
p3=p2.next;
p2.next=p1;
//放在出现环,可以这样写是因为环只可能出现在第一个和第二个节点之间
if(p1==list.head.next) {
p1.next=null;
}
p1=p2;
p2=p3;
}
list.head.next=p1;
return list;
}
思路二
第二个思路和第一个思路的不同之处在于不改变head和p1的引用,每次都直接将p2插入到head之后,也不会出现环,实现的原理如下图:
这种方法的指针的指向比第一种稍微复杂一点,但是不会出现上面的环,并且head和p1都不会改变,只需要改变p2,p3即可。
这种方法需要注意指针的操作顺序。
代码如下:
/*单链表逆序*/
public SinglyList reverse(SinglyList<T> list) {
//保证只有>=2个节点时才会做逆序操作
if(list.head.next==null||list.head.next.next==null) {
return list;
}
SinglyNode<T> p1=list.head.next;
SinglyNode<T> p2=list.head.next.next;
SinglyNode<T> p3=null;
while(p2!=null) { //结束条件一样
p3=p2.next; //注意每条语句的顺序
p1.next=p3;
p2.next=list.head.next;
list.head.next=p2;
p2=p3;
}
return list;
}
以上就是单链表的逆序的思路,归根到底要记住逆序的本质,以及要充分理解指针指向的顺序和含义。
希望大家面对单链表逆序的问题都能够顺序快速正确的解决!