介绍单链表和双链表
一、单链表和双链表的定义
单链表:值,一条next指针
双链表:值,一条last指针,一条next指针
玩出无尽的花样!
二、单双链表的反转
经典题目:
给定一个单链表的头head,完成链表的逆序调整。
给定一个双链表的头head,完成链表的逆序调整。
单链表的反转
单向链表示意图:

给定头节点head,指向a,head指向a这边内存区域,然后通过内存区域里面可以一直串,串完所有的节点。

反转指的是什么意思?你能不能把这个链表逆序了。a的next指针指向null,b的next指向a,c的next指向b,d的next指向c。这样链表就反转了。完成这样逆序的工作之后,如果head还指向a,a的next指向null,谁去找bcd呢?没有,所以jvm会把bcd释放,因为没有任何东西能找到bcd,会被认为是垃圾空间。怎么样才能让bcd不垃圾?
head = f(head),让head等于逆序之后的头节点,也就是head = d节点。
所以干的事情就是,f(H)将所有指针逆序,同时f(H)返回头节点。


简单介绍jvm知识,内存中abcde 指向关系如图,程序中只有H能找到b,如果jvm去释放空间的话,它一定会把a、c、d释放的,因为H指向b,b往下能指向e,所以相当于在程序中我能找到b、e,jvm会认为你们是有用的,如果任何一个引用都找不到剩下的空间,例如找不到a,c,d,jvm会认为他们是无用的,会释放。


同理,如果是下图这样的,H头节点指向a,a->b->c....d,可达性,既然都可达,JVM绝对不会回收的。但是如果f(H)只管逆序,但是不返回值,是void类型,H指向a不变,可达性来讲,只有a可达,bcd不可达了,所以jvm会将bcd释放掉,所以不能写成返回void类型的反转方法。所以应该是:
H = f(H),反转函数返回新的头,赋值给原来的H。


单链表的逆序方法怎么写?

有个小事情需要注意一下:问大家一个问题,在reverseLinkedList方法里面折腾head,将n1的引用传进reverseLinedList方法里面了:
Node n1 = new Node(1);
n1.next = new Node(2);
n1.next.next = new Node(3);
reverseLinkedList(n1);
在reverseLinkedList里面,n1就是head,head不停的在动,经历过这个过程之后,请问:n1变不变?
答案: 上游的n1是不变的。模拟小程序见:
JustTest1.java
查看代码
package com.model;
/**
*
*/
public class JustTest1 {
public static void m(Student t) {
t = new Student("xiao", 1, "class1");
t.setAge(20);
t.setName("niubi");
}
public static void main(String[] args) {
Student s = new Student("cy", 2, "c1");
System.out.println(s); //Student(name=cy, age=2, classroom=c1)
m(s);
System.out.println(s); //Student(name=cy, age=2, classroom=c1)
}
}
在java中这叫引用的传递。
上游函数中有个n1,你调用了f(n1),在f里面改了n1的东西,n1可能到处指,但是上游的n1其实是一直不变的。你看着f(n1),n1进去了,这个行为其实是n1拷贝出了n1',是一个别的指针,是一个别的引用,f你看似是对n1操作,实际上是对n1'操作,上游的n1该指谁还指谁。进到f()里面的n1和上游的n1不是一个东西。它拷贝了一份内存地址传进来你随便玩,上游是一点都不会变的。这就是引用的传递。

继续看代码中reverseLinkedList的写法:


最后,代码如下:
查看代码
package com.cy.class04;
/**
*
*/
public class Code01_ReverseList {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
/**
* 单链表的逆序
*/
public static Node reverseLinkedList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static void main(String[] args) {
Node n1 = new Node(1);
n1.next = new Node(2);
n1.next.next = new Node(3);
n1 = reverseLinkedList(n1);
// while(n1 != null) {
// System.out.print(n1.value + " ");
// n1 = n1.next;
// }
// System.out.println();
}
}
三、双链表的逆序

逆序过程:

链表的调整确实很繁琐,但是只是在于练习,没有什么在算法上精髓的地方。
代码如下:
查看代码
package com.cy.class04;
/**
*
*/
public class Code01_ReverseList {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static class DoubleNode {
public int value;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int data) {
this.value = data;
}
}
/**
* 单链表的逆序
*/
public static Node reverseLinkedList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
/**
* 双链表的逆序
*/
public static DoubleNode reverseDoubleList(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;
}
public static void main(String[] args) {
Node n1 = new Node(1);
n1.next = new Node(2);
n1.next.next = new Node(3);
n1 = reverseLinkedList(n1);
// while(n1 != null) {
// System.out.print(n1.value + " ");
// n1 = n1.next;
// }
// System.out.println();
}
}
--
浙公网安备 33010602011771号