Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 21.3k
Expand file tree
/
Copy pathCheckIfBinaryTreeBalanced.java
More file actions
Latest commit
157 lines (135 loc) · 6.09 KB
/
Copy pathCheckIfBinaryTreeBalanced.java
File metadata and controls
157 lines (135 loc) · 6.09 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
packagecom.thealgorithms.datastructures.trees;
importjava.util.HashMap;
importjava.util.Stack;
/**
* This class will check if a BinaryTree is balanced. A balanced binary tree is
* defined as a binary tree where the difference in height between the left and
* right subtree of each node differs by at most one.
* <p>
* This can be done in both an iterative and recursive fashion. Below,
* `isBalancedRecursive()` is implemented in a recursive fashion, and
* `isBalancedIterative()` is implemented in an iterative fashion.
*
* @author [Ian Cowan](<a href="https://github.com/iccowan">Git-Ian Cowan</a>)
*/
publicfinalclassCheckIfBinaryTreeBalanced {
privateCheckIfBinaryTreeBalanced() {
}
/**
* Recursive is BT balanced implementation
*
* @param root The binary tree to check if balanced
*/
publicstaticbooleanisBalancedRecursive(BinaryTree.Noderoot) {
if (root == null) {
returntrue;
}
// Create an array of length 1 to keep track of our balance
// Default to true. We use an array, so we have an efficient mutable object
boolean[] isBalanced = newboolean[1];
isBalanced[0] = true;
// Check for balance and return whether we are balanced
isBalancedRecursive(root, 0, isBalanced);
returnisBalanced[0];
}
/**
* Private helper method to keep track of the depth and balance during
* recursion. We effectively perform a modified post-order traversal where
* we are looking at the heights of both children of each node in the tree
*
* @param node The current node to explore
* @param depth The current depth of the node
* @param isBalanced The array of length 1 keeping track of our balance
*/
privatestaticintisBalancedRecursive(BinaryTree.Nodenode, intdepth, boolean[] isBalanced) {
// If the node is null, we should not explore it and the height is 0
// If the tree is already not balanced, might as well stop because we
// can't make it balanced now!
if (node == null || !isBalanced[0]) {
return0;
}
// Visit the left and right children, incrementing their depths by 1
intleftHeight = isBalancedRecursive(node.left, depth + 1, isBalanced);
intrightHeight = isBalancedRecursive(node.right, depth + 1, isBalanced);
// If the height of either of the left or right subtrees differ by more
// than 1, we cannot be balanced
if (Math.abs(leftHeight - rightHeight) > 1) {
isBalanced[0] = false;
}
// The height of our tree is the maximum of the heights of the left
// and right subtrees plus one
returnMath.max(leftHeight, rightHeight) + 1;
}
/**
* Iterative is BT balanced implementation
*/
publicstaticbooleanisBalancedIterative(BinaryTree.Noderoot) {
if (root == null) {
returntrue;
}
// Default that we are balanced and our algo will prove it wrong
booleanisBalanced = true;
// Create a stack for our post order traversal
Stack<BinaryTree.Node> nodeStack = newStack<>();
// For post order traversal, we'll have to keep track of where we
// visited last
BinaryTree.NodelastVisited = null;
// Create a HashMap to keep track of the subtree heights for each node
HashMap<BinaryTree.Node, Integer> subtreeHeights = newHashMap<>();
// We begin at the root of the tree
BinaryTree.Nodenode = root;
// We loop while:
// - the node stack is empty and the node we explore is null
// AND
// - the tree is still balanced
while (!(nodeStack.isEmpty() && node == null) && isBalanced) {
// If the node is not null, we push it to the stack and continue
// to the left
if (node != null) {
nodeStack.push(node);
node = node.left;
// Once we hit a node that is null, we are as deep as we can go
// to the left
} else {
// Find the last node we put on the stack
node = nodeStack.peek();
// If the right child of the node has either been visited or
// is null, we visit this node
if (node.right == null || node.right == lastVisited) {
// We assume the left and right heights are 0
intleftHeight = 0;
intrightHeight = 0;
// If the right and left children are not null, we must
// have already explored them and have a height
// for them so let's get that
if (node.left != null) {
leftHeight = subtreeHeights.get(node.left);
}
if (node.right != null) {
rightHeight = subtreeHeights.get(node.right);
}
// If the difference in the height of the right subtree
// and left subtree differs by more than 1, we cannot be
// balanced
if (Math.abs(rightHeight - leftHeight) > 1) {
isBalanced = false;
}
// The height of the subtree containing this node is the
// max of the left and right subtree heights plus 1
subtreeHeights.put(node, Math.max(rightHeight, leftHeight) + 1);
// We've now visited this node, so we pop it from the stack
nodeStack.pop();
lastVisited = node;
// Current visiting node is now null
node = null;
// If the right child node of this node has not been visited
// and is not null, we need to get that child node on the stack
} else {
node = node.right;
}
}
}
// Return whether the tree is balanced
returnisBalanced;
}
}