算法9-12链表-堆栈诠释
按值传递、按引用传递
//从堆栈角度解释链表节点
//以堆栈视角来看链表反转
public class ListReverse {
public static void main(String[] args) {
// int、long、byte、short
// char、float、double、boolean
// 还有String
// 都是按值传递
int a = 10;
f(a);
System.out.println(a);
// 其他类型按引用传递
// 比如下面的Number是自定义的类
Number b = new Number(5);
g1(b);
System.out.println(b.val);//5
g2(b);
System.out.println(b.val);//6
// 比如下面的一维数组
int[] c = { 1, 2, 3, 4 };
g3(c);
System.out.println(c[0]);//1
g4(c);
System.out.println(c[0]);//100
}
public static void f(int a) {
a = 0;
}
public static class Number {
public int val;
public Number(int v) {
val = v;
}
}
public static void g1(Number b) {
b = null;
}
public static void g2(Number b) {
b.val = 6;
}
public static void g3(int[] c) {
c = null;
}
public static void g4(int[] c) {
c[0] = 100;
}
g2的更改才是真正更改了堆中的值
g1的更改只是把栈中的新的b’的指向null了
单链表节点
// 单链表节点
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
反转单链表
// 反转单链表测试链接 : https://leetcode.cn/problems/reverse-linked-list/
class Solution {
public static ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
}
第一轮while循环结束时
第二轮while结束时
双链表节点
// 双链表节点
public static class DoubleListNode {
public int value;
public DoubleListNode last;
public DoubleListNode next;
public DoubleListNode(int v) {
value = v;
}
}
合并两个有序链表
// 新链表是通过拼接给定的两个链表的所有节点组成的
// 测试链接 : https://leetcode.cn/problems/merge-two-sorted-lists/
public class MergeTwoLists {
// 不要提交这个类
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public static ListNode mergeTwoLists(ListNode head1, ListNode head2) {
if (head1 == null || head2 == null) {
return head1 == null ? head2 : head1;
}
ListNode head = head1.val <= head2.val ? head1 : head2;
ListNode cur1 = head.next;
ListNode cur2 = head == head1 ? head2 : head1;
ListNode pre = head;
while (cur1 != null && cur2 != null) {
if (cur1.val <= cur2.val) {
pre.next = cur1;
cur1 = cur1.next;
} else {
pre.next = cur2;
cur2 = cur2.next;
}
pre = pre.next;
}
pre.next = cur1 != null ? cur1 : cur2;
return head;
}
}
}
相加两个链表
// 它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字
// 请你将两个数相加,并以相同形式返回一个表示和的链表。
// 你可以假设除了数字 0 之外,这两个数都不会以 0 开头
// 测试链接:https://leetcode.cn/problems/add-two-numbers/
public class AddTwoNumbers {
// 不要提交这个类
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
// 也可以复用老链表
// 不过这个实现没有这么做,都是生成的新节点(为了教学好懂)
public static ListNode addTwoNumbers(ListNode h1, ListNode h2) {
ListNode ans = null, cur = null;
int carry = 0;
for (int sum, val; // 声明变量
h1 != null || h2 != null; // 终止条件
h1 = h1 == null ? null : h1.next, // 每一步h1的跳转
h2 = h2 == null ? null : h2.next // 每一步h2的跳转
) {
sum = (h1 == null ? 0 : h1.val)
+ (h2 == null ? 0 : h2.val)
+ carry;
val = sum % 10;
carry = sum / 10;
if (ans == null) {
ans = new ListNode(val);
cur = ans;
} else {
cur.next = new ListNode(val);
cur = cur.next;
}
}
if (carry == 1) {
cur.next = new ListNode(1);
}
return ans;
}
}
}
为什么使用l1 = l1 == null ? null : l1.next; 而不使用l1=l1.next;
在这段代码中,l1
是一个链表节点的引用。这段代码的目的是将 l1
移动到链表中的下一个节点。这里使用了条件运算符(ternary operator)来检查 l1
是否为 null
。
如果 l1
是 null
,那么说明已经到达了链表的末尾,没有下一个节点了。在这种情况下,将 l1
设置为 null
。
如果 l1
不是 null
,那么可以安全地访问 l1.next
,并将 l1
移动到下一个节点。
这种写法是为了处理链表末尾的情况,以避免在 l1
为 null
时访问 l1.next
。如果直接使用 l1 = l1.next
,那么在 l1
为 null
时会引发空指针异常。通过使用条件运算符,可以先检查 l1
是否为 null
,从而避免这个问题,并确保代码的健壮性。
分隔链表
// 请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
// 你应当 保留 两个分区中每个节点的初始相对位置
// 测试链接 : https://leetcode.cn/problems/partition-list/
public class PartitionList {
// 不要提交这个类
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public static ListNode partition(ListNode head, int x) {
ListNode leftHead = null, leftTail = null; // < x的区域
ListNode rightHead = null, rightTail = null; // >=x的区域
ListNode next = null;
while (head != null) {
next = head.next;
head.next = null;
if (head.val < x) {
if (leftHead == null) {
leftHead = head;
} else {
leftTail.next = head;
}
leftTail = head;
} else {
if (rightHead == null) {
rightHead = head;
} else {
rightTail.next = head;
}
rightTail = head;
}
head = next;
}
if (leftHead == null) {
return rightHead;
}
// < x的区域有内容!
leftTail.next = rightHead;
return leftHead;
}
}
}