Java 数据结构

算法

本文最后更新于 <span id="expire-date"></span> 天前,文中部分描述可能已经过时。

Java 数据结构

​ 在CS界有一个著名的公式: 数据结构 + 算法 = 程序设计,可见Data StructuresAlgorithm在CS中的重要地位了。虽然我曾经学习过数据结构,但非常遗憾的是,当初学习的数据结构是以C语言描述的,当时主要参考了两本书:一本是严蔚敏教授的数据结构(C语言版),这本书的代码主要是以伪代码形式呈现,奈何本人水平太差,难以领会到算法的精妙思想;另一本书——数据结构教程,这本书所有代码都是用真实的C语言写的,作者自称这本书的所有代码都能够运行,与严教授的书相比,这本书内容要详细太多了,如果有充分的时间,我相信这本书可以是一本非常好的自学教材,但奈何学时和课业压力,至今尚未较为全面仔细地翻阅此书。

​ 最近在学习CS 61B,学习这门课的主要目的是为了掌握一些基本的算法方便刷 LeetCode,次要的目的才是复习数据结构。这次的学习既可以说是复习,也可以说是学习新的知识,因为我并未掌握如何用Java语言描述基本的数据结构,因此才有了这篇文章。关于Java 我并不是十分精通,所以在学习Java数据结构的同时,我或许还会学到新的语法,是为序。

链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ListNode{
//节点的值
int val;

//下一个节点
ListNode next;

//节点的构造函数(无参)
public ListNode(){
}

//节点的构造函数(有一个参数)
public ListNode(int val){
this.val = val;
}
//节点的构造函数(有两个参数)
public ListNode(int val, ListNode next){
this.val = val;
this.next = next;
}
}

LeetCode - 203.移除链表元素

力扣链接
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点

示例 1:

1
2
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

1
2
输入:head = [], val = 1
输出:[]

示例 3:

1
2
输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

无虚拟节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public Listnode removeElements(ListNode head, int val){
while(head != null && head.val == val){
head = head.next;
}
if(head == null){
return head;
}
ListNode pre = head;
ListNode cur = head.next;
while(cur != null){
if(cur.val == val){
pre.next = cur.next;
}else{
pre = cur;
}
cur = cur.next;
}
return head;
}
}

有虚拟节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public ListNode removeElements(ListNode head, int val) {
if (head == null) {
return head;
}
// 因为删除可能涉及到头节点,所以设置dummy节点,统一操作
ListNode dummy = new ListNode(-1, head);
ListNode pre = dummy;
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return dummy.next;
}

LeetCode - 707.设计链表

力扣链接

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val nextval 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1
  • addAtHead (val):在链表的第一个元素之前添加一个值为 val的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表最后一个元素。
  • addAtIndex(index, val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果index大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

示例:

1
2
3
4
5
6
7
8
MyLinkedList linkedList = new MyLinkedList();

linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3

提示:

  • 所有val值都在 [1, 1000] 之内。
  • 操作次数将在 [1, 1000] 之内。
  • 请不要使用内置的 LinkedList 库。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class ListNode{
int val;
ListNode next;
ListNode(){
}
ListNode(int val){
this.val = val;
}
}
class MyLinkedList{
int size;
ListNode head;
public MyLinkedList(){
size = 0;
head = new ListNode(0);
}
public int get(int index){
if(index < 0|| index >= size){
return -1;
}
ListNode currentNode = head;
for(int i = 0; i <= index; i++){
currentNode = currentNode.next;
}
return currentNode.val;
}
public void addAtHead(int val){
addAtIndex(0, val);
}
public void addAtTail(int val){
addAtIndex(size, val);
}
public void addAtIndex(int index, int val){
ListNode pre = head;
ListNode toAdd = new ListNode (val);
if(index > size){
return;
}
if(index < 0){
index = 0;
}
size++;
for(int i = 0; i < index; i++){
pre = pre.next;
}
toAdd.next = pre.next;
pre.next = toAdd;
}
public void deleteAtIndex(int index){
if(index < 0||index >= size){
return;
}
size--;
ListNode pre = head;
for(int i = 0; i < index ; i++){
pre = pre.next;
}
pre.next = pre.next.next;
}
}

LeetCode - 206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

1
2
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
1
2
输入:head = [1,2]
输出:[2,1]
1
2
输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

双指针法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution{
public ListNode reverseList(ListNode head){
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur != null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}

递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur != null){
temp = cur.next;
cur.next =pre;
pre = cur;
cur = temp;
}
return pre;
}
}

LeetCode - 24.两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

1
2
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

1
2
输入:head = []
输出:[]

示例 3:

1
2
输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100]

  • 0 <= Node.val <= 100

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
while(pre.next != null && pre.next.next != null){
ListNode temp = head.next.next;
pre.next = head.next;
head.next.next = head;
head.next = temp;
pre = head;
head = head.next;
}
return dummy.next;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 递归版本
class Solution {
public ListNode swapPairs(ListNode head) {
// base case 退出提交
if(head == null || head.next == null) return head;
// 获取当前节点的下一个节点
ListNode next = head.next;
// 进行递归
ListNode newNode = swapPairs(next.next);
// 这里进行交换
next.next = head;
head.next = newNode;

return next;
}
}

二叉树

Java语言描述二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(){}
TreeNode(int val){
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right){
this.val = val;
this.left = left;
this.right = right;
}
}

前序遍历

递归方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution{
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preorder(root, result);
return result;
}
private void preorder(TreeNode root, List<Integer> result){
if(root == null)
return;
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}

迭代方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution{
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> result = new ArrayList<>();
if(root == null)
return result;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if(node.right != null)
stack.push(node.right);
if(node.left != null)
stack.push(node.left);
}
return result;
}
}

中序遍历

递归方式

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution{
public List<Integer> inorderTraversal(TreeNode root){
List<Integer> result = new ArrayList<>();
inorder(root, result);
return result;
}
private void inorder(TreeNode root, List<Integer> result){
if(root == null) return;
inorder(root.left, result);
result.add(root.val);
inorder(root.right, result);
}
}

迭代方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution{
public List<Integer> inorderTraversal(TreeNode root){
List<Integer> result = new ArrayList<>();
if(root == null) return result;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
if(cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}

后序遍历

递归方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postorder(root, result);
return result;

}
private void postorder(TreeNode root, List<Integer> result){
if(root == null) return;
postorder(root.left, result);
postorder(root.right, result);
result.add(root.val);
}
}

迭代方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public List<Integer> postorderTraversal(TreeNode root){
List<Integer> result = new ArrayList<>();
if(root == null) return result;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if(node.left != null) stack.push(node.left);
if(node.right != null) stack.push(node.right);
}
Collections.reverse(result);
return result;
}
}

Red-black Tree

The red-black tree can be implemented with TreeMsp in Java or HashMAp in Java 8.

本文作者:Mosquito

本文链接: http://example.com/2022/01/29/Java-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/

Mosquito 天使之吻手打

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。