Java 数据结构
在CS界有一个著名的公式: 数据结构 + 算法 = 程序设计,可见Data Structures和 Algorithm在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
|
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; } 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
和 next
。val
是当前节点的值,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]
|
提示:
- 链表中节点的数目范围是
[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
|
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
|
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:
示例 3:
提示:
链表中节点的数目在范围 [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
|
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) { 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
.