一、单链表反转
(1)创建单链表结构类
public class Node {
public int value;//当前节点的值
public Node next;//next储存下一个节点地址值
public Node(int value) {
this.value=value;
}
}
不知道有没有小伙伴像我一样的疑惑,为什么单链表结构类中的成员变量有个Node next?后面经常思考我发现next的作用是储存下一个节点的地址值,即通过访问当前节点的next属性即可寻找到下一个节点。它的创建方式可以理解为回调函数的方式,创建一个node类对象时,该对象中的next默认走无参构造进行初始化,因此初始值是null。
(2)创建单链表结构变量
Node head=new Node(1);
head.next=new Node(2);
head.next.next=new Node(3);
(3)反转函数
public static Node reverse(Node head){
Node next=null;
Node pre=null;
//循环步
while(head !=null) {
//next指针移后,保存下一个节点地址,防止由于当前节点的指针更改导致下一个节点地址丢失。
next = head.next;
//反转当前节点指针(原->,更改<-)
head.next=pre;
//指针指向更改完毕,调整当前节点顺序
pre=head;//pre上前
head=next;//head移后
}
return pre;
}
上述代码中,next的作用是保存当前节点的下一个节点地址,而pre的作用是保存当前节点的上一个节点地址。
(4)测试
Node n1=new Node(1);
n1.next=new Node(2);
n1.next.next=new Node(3);
System.out.println("倒序前"+n1);
//调用倒序函数
Node reverse = reverse(n1);
System.out.println("倒序前"+reverse);
(4)倒序流程:
首先三个变量(pre,head,next),循环条件while(head !=null),其中pre和next初始为null,head为传入的参数,也是头节点,pre和next是用于保存节点位置,防止由于当前节点指针的更改而导致当前节点记录的其它节点地址丢失,pre保存head的前一个节点地址,next保存head的下一个节点地址。
循环步:第一步保存当前节点内的下一个节点地址,代码实现为next=head.next;第二步反转当前节点的指向,代码实现为head.next=pre;第三步,调序,head后移,主要表现为pre到达当前head位置,head再到达当前next位置,代码实现为pre=head,head=next。最后重复以上三步直到循环结束。
整体倒序代码流程可见下图:
二、双链表反转
双链表反转和单链表相似,这里就不做详细论述。
(1)创建双链表结构类
public DoubleNode last;
public DoubleNode next;
public int value;
public DoubleNode(int value) {
this.value = value;
}
双链表结构简图如下(为方便只画了两个节点)
(2)倒序函数
public static DoubleNode reverseDoubleNode(DoubleNode head){
DoubleNode pre=null;
DoubleNode next=null;
//循环步
while (head !=null) {
//保存下一个节点地址
next = head.next;
//反转指向
head.next = pre;
head.last = next;
//调整顺序
pre = head;
head = next;
}
return pre;//head=null;head的前一个节点pre的地址即最后一个节点地址,即新的头结点地址
}
具体代码实现流程图:
三、总结
从中可以看出不管是单链表还是双链表,反转的逻辑步骤都一样,首先保存当前节点的下一个节点的地址值,防止因当前节点指向更改而丢失,然后更改当前节点的指向,单链表只更改next,而双链表还要更改last,最后再调整节点顺序(获取下一个节点地址值),pre在前head在中,last在后的结构,最后循环结束返回pre即最后一个节点地址,即新的头节点。