Error message here!

Hide Error message here!

Error message here!

Hide Error message here!

Error message here!

Close

数据结构系列（1）之 二叉搜索树

一、结构概述

``````public class BST<T extends Comparable<? super T>> {
private BSTNode<T> root;
public BST() {root = null;}
...
class BSTNode<T extends Comparable<? super T>> {
T key;
BSTNode<T> parent;
BSTNode<T> left;
BSTNode<T> right;
BSTNode(T key, BSTNode<T> parent, BSTNode<T> left, BSTNode<T> right) {
this.key = key;
this.parent = parent;
this.left = left;
this.right = right;
}
}
}``````

二、查找

``````private BSTNode<T> search(BSTNode<T> x, T key) {
if (x == null) return x;
int cmp = key.compareTo(x.key);
if (cmp < 0)
return search(x.left, key);
else if (cmp > 0)
return search(x.right, key);
else
return x;
}
public BSTNode<T> search(T key) {
return search(root, key);
}``````

三、插入

3. 实现

``````private void insert(T key) {
BSTNode<T> node = new BSTNode<T>(key, null, null, null);
BSTNode<T> r = this.root;
BSTNode<T> p = null;
int cmp;
// 查找插入位置
while (r != null) {
p = r;
cmp = node.key.compareTo(r.key);
if (cmp < 0)
r = r.left;
else
r = r.right;
}
if (p == null)
this.root = node;
else {
node.parent = p;
cmp = node.key.compareTo(p.key);
if (cmp < 0)
p.left = node;
else
p.right = node;
}
}``````

四、删除

2. 删除完全节点

• 需要首先找到目标节点的直接后继（自然顺序或者中序遍历顺序的下一个节点），目标节点右孩子一直往左；当然这里同样可以找目标节点的前驱节点替换；
• 然后交换目标节点和后继节点的位置；
• 最后同上面的删除一样，直接删除节点；

3. 实现

``````public void delete(T key) {
BSTNode<T> node = search(root, key);
if (node != null) delete(node);
node = null;
}
private BSTNode<T> delete(BSTNode<T> node) {
// 将完全节点和直接后继交换
if (node.left != null && node.right != null) {
BSTNode<T> succ = successor(node);
node.key = succ.key;
node = succ;
}
// 将孩子节点的父亲接到祖父上
BSTNode<T> child = node.left != null ? node.left : node.right;
if (child != null) child.parent = node.parent;
// 目标节点没有父节点则是根节点
if (node.parent == null) root = child;
// 目标节点是左孩子时
else if (node == node.parent.left) node.parent.left = child;
// 目标节点是右孩子时
else node.parent.right = child;
return node;
}
private BSTNode<T> successor(BSTNode<T> node) {
BSTNode<T> succ = node.right;
while (succ.left != null) succ = succ.left;
return succ;
}``````

// 这里只是右子树中的直接后继；整个中序遍历中直接后继还可能是其父节点或者祖先节点；

五、前序遍历

1. 描述

• 首先遍历根节点
• 再一次递归遍历左子树和右子树；

2. 实现

``````// 递归实现
private void travPre(BSTNode<T> tree) {
if (tree == null) return;
System.out.print(tree.key + " ");
travPre(tree.left);
travPre(tree.right);
}
// 迭代实现
public void travPre2(BSTNode<T> tree) {
Stack<BSTNode<T>> stack = new Stack<>();
while (true) {
visitAlongVine(tree, stack);
if (stack.isEmpty()) break;
tree = stack.pop();
}
}
private void visitAlongVine(BSTNode<T> tree, Stack<BSTNode<T>> stack) {
while (tree != null) {
System.out.print(tree.key + " ");
stack.push(tree.right);
tree = tree.left;
}
}``````

六、中序遍历

1. 描述

• 对于中序遍历，则首先遍历左子树
• 再遍历根节点
• 最后遍历右子树

2. 实现

``````// 递归实现
private void travIn(BSTNode<T> tree) {
if (tree == null) return;
travIn(tree.left);
System.out.print(tree.key + " ");
travIn(tree.right);
}
// 迭代实现
public void travIn2(BSTNode<T> tree) {
Stack<BSTNode<T>> stack = new Stack<>();
while (true) {
goAlongVine(tree, stack);
if (stack.isEmpty()) break;
tree = stack.pop();
System.out.print(tree.key + " ");
tree = tree.right;
}
}
private void goAlongVine(BSTNode<T> tree, Stack<BSTNode<T>> stack) {
while (tree != null) {
stack.push(tree);
tree = tree.left;
}
}``````

七、后序遍历

1. 描述

• 对于后序遍历，则首先遍历左子树
• 再遍历根右子树
• 最后遍历根节点

2. 实现

``````// 递归实现
private void travPost(BSTNode<T> tree) {
if (tree == null) return;
travPost(tree.left);
travPost(tree.right);
System.out.print(tree.key + " ");
}
// 迭代实现
public void travPost2(BSTNode<T> tree) {
Stack<BSTNode<T>> stack = new Stack<>();
if (tree != null) stack.push(tree);
while (!stack.isEmpty()) {
if (stack.peek() != tree.parent)
gotoHLVFL(stack);
tree = stack.pop();
System.out.print(tree.key + " ");
}
}
private void gotoHLVFL(Stack<BSTNode<T>> stack) {
BSTNode<T> tree;
while ((tree = stack.peek()) != null)
if (tree.left != null) {
if (tree.right != null) stack.push(tree.right);
stack.push(tree.left);
} else
stack.push(tree.right);
stack.pop();
}``````

八、层次遍历

2. 实现

``````public void travLevel() {
queue.offer(root);
while (!queue.isEmpty()) {
BSTNode<T> x = queue.poll();
System.out.print(x.key + " ");
if (x.left != null) queue.offer(x.left);
if (x.right != null) queue.offer(x.right);
}
}``````

总结

• 正是因为二叉树同时具有向量和列表的特性，所以他的使用场景非常广泛，当然他还有很多的变种，这些我们后续会继续讲到；
• 对于文中的动图大家可以在这个网站自行实验；http://btv.melezinek.cz/binary-search-tree.html

https://www.cnblogs.com/sanzao/p/10444931.html

30万现金开奖等你来领