漫画算法(3)- 树

深度优先遍历

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
public class BinaryTreeTraversal {

/**
* 构建二叉树
*
* @param inputList 输入序列
*/
public static TreeNode createBinaryTree(LinkedList<Integer> inputList) {
TreeNode node = null;
if (inputList == null || inputList.isEmpty()) {
return null;
}
Integer data = inputList.removeFirst();
// 判空
if (data != null) {
node = new TreeNode(data);
node.leftChild = createBinaryTree(inputList);
node.rightChild = createBinaryTree(inputList);
}
return node;
}

/**
* 二叉树非递归前序遍历
*
* @param root 二叉树根节点
*/
public static void preOrderTraveralWithStack(TreeNode root) {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode treeNode = root;
while (treeNode != null || !stack.isEmpty()) {
// 迭代访问节点的左孩子,并入栈
while (treeNode != null) {
System.out.println(treeNode.data);
stack.push(treeNode);
treeNode = treeNode.leftChild;
}
// 如果节点没有左孩子,则弹出栈顶节点,访问节点右孩子
if (!stack.isEmpty()) {
treeNode = stack.pop();
treeNode = treeNode.rightChild;
}
}
}

/**
* 二叉树前序遍历
*
* @param node 二叉树节点
*/
public static void preOrderTraversal(TreeNode node) {
if (node == null) {
return;
}
System.out.println(node.data);
preOrderTraversal(node.leftChild);
preOrderTraversal(node.rightChild);
}

/**
* 二叉树中序遍历
*
* @param node 二叉树节点
*/
public static void inOrderTraversal(TreeNode node) {
if (node == null) {
return;
}
inOrderTraversal(node.leftChild);
System.out.println(node.data);
inOrderTraversal(node.rightChild);
}


/**
* 二叉树后序遍历
*
* @param node 二叉树节点
*/
public static void postOrderTraversal(TreeNode node) {
if (node == null) {
return;
}
postOrderTraversal(node.leftChild);
postOrderTraversal(node.rightChild);
System.out.println(node.data);
}

/**
* 二叉树节点
*/
private static class TreeNode {
int data;
TreeNode leftChild;
TreeNode rightChild;

TreeNode(int data) {
this.data = data;
}
}

public static void main(String[] args) {
LinkedList<Integer> inputList = new LinkedList<>(Arrays.asList(new Integer[]{3, 2, 9, null, null, 10, null, null, 8, null, 4,}));
TreeNode treeNode = createBinaryTree(inputList);
System.out.println("前序遍历:");
preOrderTraversal(treeNode);
System.out.println("中序遍历:");
inOrderTraversal(treeNode);
System.out.println("后序遍历:");
postOrderTraversal(treeNode);
}
}

广度优先遍历

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 BinaryTreeTraversalLevel {

/**
* 构建二叉树
* @param inputList 输入序列
*/
public static TreeNode createBinaryTree(LinkedList<Integer> inputList){
TreeNode node = null;
if(inputList==null || inputList.isEmpty()){
return null;
}
Integer data = inputList.removeFirst();
// 判空
if(data != null){
node = new TreeNode(data);
node.leftChild = createBinaryTree(inputList);
node.rightChild = createBinaryTree(inputList);
}
return node;
}

/**
* 二叉树层序遍历
* @param root 二叉树根节点
*/
public static void levelOrderTraversal(TreeNode root){
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
System.out.println(node.data);
if(node.leftChild != null){
queue.offer(node.leftChild);
}
if(node.rightChild != null){
queue.offer(node.rightChild);
}
}
}

/**
* 二叉树节点
*/
private static class TreeNode {
int data;
TreeNode leftChild;
TreeNode rightChild;

TreeNode(int data) {
this.data = data;
}
}

public static void main(String[] args) {
LinkedList<Integer> inputList = new LinkedList<>(Arrays.asList(new Integer[]{3,2,9,null,null,10,null,null,8,null,4,}));
TreeNode treeNode = createBinaryTree(inputList);
System.out.println("层序遍历:");
levelOrderTraversal(treeNode);
}
}

二叉堆

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
61
62
63
64
65
66
public class HeapOperator {

/**
* 上浮调整
*
* @param array 待调整的堆
*/
public static void upAdjust(int[] array) {
int childIndex = array.length - 1;
int parentIndex = (childIndex - 1) / 2;
int temp = array[childIndex];
while (childIndex > 0 && temp < array[parentIndex]) {
array[childIndex] = array[parentIndex];
childIndex = parentIndex;
parentIndex = (parentIndex - 1) / 2;
}
array[childIndex] = temp;
}

/**
* 下沉调整
*
* @param array 待调整的堆
* @param parentIndex 要下沉的父节点
* @param length 堆的有效大小
*/
public static void downAdjust(int[] array, int parentIndex, int length) {
int temp = array[parentIndex];
int childIndex = 2 * parentIndex + 1;
while (childIndex < length) {
// 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子
if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {
childIndex++;
}
// 如果父节点小于任何一个孩子的值,直接跳出
if (temp <= array[childIndex])
break;
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1;
}
array[parentIndex] = temp;
}

/**
* 构建堆
*
* @param array 待调整的堆
*/
public static void buildHeap(int[] array) {
// 从最后一个非叶子节点开始,依次下沉调整
for (int i = (array.length - 2) / 2; i >= 0; i--) {
downAdjust(array, i, array.length);
}
}

public static void main(String[] args) {
int[] array = new int[]{1, 3, 2, 6, 5, 7, 8, 9, 10, 0};
upAdjust(array);
System.out.println(Arrays.toString(array));

array = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
buildHeap(array);
System.out.println(Arrays.toString(array));
}
}

优先队列

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class PriorityQueue {

private int[] array;
private int size;

public PriorityQueue() {
array = new int[32];
}

/**
* 入队
*
* @param key 入队元素
*/
public void enQueue(int key) {
// 队列长度超出范围,扩容
if (size >= array.length) {
resize();
}
array[size++] = key;
upAdjust();
}

/**
* 出队
*/
public int deQueue() throws Exception {
if (size <= 0) {
throw new Exception("the queue is empty !");
}
// 获取堆顶元素
int head = array[0];
// 最后一个元素移动到堆顶
array[0] = array[--size];
downAdjust();
return head;
}

/**
* 上浮调整
*/
private void upAdjust() {
int childIndex = size - 1;
int parentIndex = (childIndex - 1) / 2;
int temp = array[childIndex];
while (childIndex > 0 && temp > array[parentIndex]) {
array[childIndex] = array[parentIndex];
childIndex = parentIndex;
parentIndex = (parentIndex - 1) / 2;
}
array[childIndex] = temp;
}

/**
* 下沉调整
*/
private void downAdjust() {
int parentIndex = 0;
int temp = array[parentIndex];
int childIndex = 1;
while (childIndex < size) {
// 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
if (childIndex + 1 < size && array[childIndex + 1] > array[childIndex]) {
childIndex++;
}
// 如果父节点大于任何一个孩子的值,直接跳出
if (temp >= array[childIndex])
break;
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1;
}
array[parentIndex] = temp;
}

/**
* 队列扩容
*/
private void resize() {
// 队列容量翻倍
int newSize = this.size * 2;
this.array = Arrays.copyOf(this.array, newSize);
}

public static void main(String[] args) throws Exception {
PriorityQueue priorityQueue = new PriorityQueue();
priorityQueue.enQueue(3);
priorityQueue.enQueue(5);
priorityQueue.enQueue(10);
priorityQueue.enQueue(2);
priorityQueue.enQueue(7);
priorityQueue.printPriorityQueue(priorityQueue);
System.out.println("出队元素:" + priorityQueue.deQueue());
System.out.println("出队元素:" + priorityQueue.deQueue());
}

private void printPriorityQueue(PriorityQueue priorityQueue) {
for (int i = 0; i < priorityQueue.size; i++) {
if (i == 0) {
System.out.print("[" + priorityQueue.array[i] + ",");
} else if (i == priorityQueue.size - 1) {
System.out.println(priorityQueue.array[i] + "]");
} else {
System.out.print(priorityQueue.array[i] + ",");
}
}
}
}

参考资料

《漫画算法》第 3 章


漫画算法(3)- 树
https://lcf163.github.io/2020/11/16/漫画算法(3) - 树/
作者
乘风的小站
发布于
2020年11月16日
许可协议