数据结构之链表:彻底搞懂单链表反转
1、代码实现
ListNode是一个链表类,维护了头节点、节点数,内部类实现Node节点类。
public class ListNode<Integer> {
//头部节点
Node<Integer> head;
//节点数
int size=0;
public static class Node<T> {
//data值
T vaule;
//指向下一个节点
Node<T> next;
//构造方法
public Node(T vaule, Node<T> next) {
this.vaule = vaule;
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"vaule=" + vaule +
", next=" + next +
};
}
}
/**
* 链表添加方法
* @param data
*/
public void add(Integer data){
if(head==null){
head= new Node<>(data, null);
size++;
}else{
Node<Integer> temp=head;
while(temp.next!=null){
temp=temp.next;
}
temp.next= new Node<>(data, null);
size++;
}
}
/**
* 反转链表
*/
public Node reverseNode() {
Node pre = null;
Node next;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
}
2、图文解析
重点解析:
next = head.next;
head.next = pre;
pre = head;
head = next;
链表的反转关键就在于这四行代码,一步步解析。
这是反转前链表。 这是反转后链表。 第一步: next = head.next;即用next保存头节点的下一个节点(节点2)。 第二步: head.next = pre;将pre(null)赋值给head.next。 第三步: pre = head;将head赋值给pre,即head指向节点1,将节点1设置为pre节点。 第四步: head = next;将next赋值给head,即head指向节点2,将节点2设置为头节点。 一次循环结束,此时链表被分成2段。继续下一轮循环: 第一步: next = head.next;即用next保存头节点的下一个节点(节点3)。 第二步: head.next = pre;将pre(节点1)赋值给head.next。即节点2的后继为节点1,完成一次反转。 第三步: pre = head;将head赋值给pre,即head指向节点2,将节点2设置为pre节点。 第四步: head = next;将next赋值给head,即head指向节点3,将节点3设置为头节点。 继续第三轮、第四轮循环,链表反转完成,我们看到第二步是一次关键的反转操作,在第一次循环中,head.next = pre;将pre(null)赋值给head.next。相当于将尾节点tail完成反转。
3、测试验证
public class ListNodeTest {
public static void main(String[] args) {
ListNode<Integer> listNode = new ListNode<>();
listNode.add(1);
listNode.add(2);
listNode.add(3);
listNode.add(4);
System.out.println(listNode.reverseNode());
}
}
运行结果:
下一篇:
C语言排序算法总结——希尔排序
