Part 1 理论部分
一、综述
二叉搜索树(Binary Search Tree),又名二叉查找树,二叉排序树:
- 它或者是一棵空树,或者是具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉搜索树。
- 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
二、实现原理
一棵二叉搜索树是以二叉树的形式来组织的,可以使用一个链表数据结构来表示,其中每一个结点就是一个对象。一般地,除了key属性之外,每个结点还包含属性left、right,分别指向结点的左孩子、右孩子。如果某个孩子结点或父结点不存在,则相应属性的值为空(NULL)。
三、主要算法
二叉搜索树中的主要算法包括:
- 插入算法(insert)
- 查找算法(search)
- 遍历算法(traverse)
- 结点删除算法(remove)
Part 2 实践部分
一、Python版本
class Node():#结点(node)类
def __init__(self,key):
self.key = key
self.left = None
self.right = None
class BinarySearchTree():
def __init__(self):
self.root = None
'''
二叉搜索树(BST)类
包括:
1.insert(key)*(插入方法)
2.inOrderTraverse()*(中序遍历方法)
3.preOrderTraverse()*(先序遍历方法)
4.postOrderTraverse()*(后序遍历方法)
5.search(key)*(查找方法)
6.min()(找最小值方法)
7.max()(找最大值方法)
8.remove()*(结点删除方法)
注:带 * 的方法含有对应的私有递归函数
'''
def insert(self, key): #插入方法
newNode = Node(key)
if self.root == None:
self.root = newNode
else:
self.__insertNode(self.root, newNode)
def __insertNode(self, node, newNode):#插入方法的递归部分
if newNode.key < node.key:
if node.left == None:
node.left = newNode
else:
self.__insertNode(node.left, newNode)
else:
if node.right == None:
node.right = newNode
else:
self.__insertNode(node.right, newNode)
def inOrderTraverse(self):#中序遍历方法
self.__inOrderTraverseNode(self.root)
def __inOrderTraverseNode(self, node):#中序遍历方法的递归部分
if node != None:
self.__inOrderTraverseNode(node.left)
print(node.key, end=" ")
self.__inOrderTraverseNode(node.right)
def preOrderTraverse(self):#先序遍历方法
self.__preOrderTraverseNode(self.root)
def __preOrderTraverseNode(self, node):#先序遍历方法的递归部分
if node != None:
print(node.key, end=" ")
self.__preOrderTraverseNode(node.left)
self.__preOrderTraverseNode(node.right)
def pastOrderTraverse(self):#后序遍历方法
self.__pastOrderTraverseNode(self.root)
def __pastOrderTraverseNode(self, node):#后序遍历方法的递归部分
if node != None:
self.__pastOrderTraverseNode(node.left)
self.__pastOrderTraverseNode(node.right)
print(node.key, end=" ")
def search(self, key):#查找方法
return __searchNode(self.root, key)
def __searchNode(self, node, key):
if node == None:
return False
if key < node.key:
self.__searchNode(node.left, key)
elif key > node.key:
self.__searchNode(node.right, key)
else:
return True
def min(self):#找最小值方法
node = self.root
while node.left:
node = node.left
return node.key
def max(self):#找最大值方法
node = self.root
while node.right:
node = node.right
return node.key
def remove(self, key):#结点移除方法
self.root = self.__removeNode(self.root, key)
def __removeNode(self, node, key):#结点移除方法的递归部分
if node == None:
return None
if key < node.key:
node.left = self.__removeNode(node.left, key)
return node
elif key > node.key:
node.right = self.__removeNode(node.right, key)
return node
else:
if node.left == None and node.right == None:
return None
elif node.left == None:
return node.right
elif node.right == None:
return node.left
else:
find = node.right
while find and find.left:
find = find.left
node.key = find.key
node.right = self.__removeNode(node.right, find.key)
return node
#测试代码:
nodes = [3,6,2,1,8,5]
bst = BinarySearchTree()
for node in nodes:
bst.insert(node)
bst.inOrderTraverse()#1,2,3,5,6,8
print()
bst.remove(bst.max())
bst.inOrderTraverse()#1,2,3,5,6
二、Java版本
//结点(Node)类
public class Node {
int key;
Node left;
Node right;
public Node(int key){
this.key = key;
this.left = null;
this.right = null;
}
}
//二叉搜索树(BST)类
public class BinarySearchTree {
private Node root;
public BinarySearchTree(){
this.root = null;
}
//结点插入方法:
public void insert(int key){
Node newNode = new Node(key);
if (this.root == null){
this.root = newNode;
}else{
insertNode(this.root, newNode);
}
}
private void insertNode(Node node, Node newNode){
if (newNode.key < node.key){
if (node.left == null){
node.left = newNode;
}else{
insertNode(node.left, newNode);
}
}else{
if (node.right == null){
node.right = newNode;
}
else{
insertNode(node.right, newNode);
}
}
}
//中序遍历方法:
public void inOrderTraverse(){
inOrderTraverseNode(this.root);
}
private void inOrderTraverseNode(Node node){
if (node != null){
inOrderTraverseNode(node.left);
System.out.print(node.key + " ");
inOrderTraverseNode(node.right);
}
}
//先序遍历方法:
public void preOrderTraverse(){
preOrderTraverseNode(this.root);
}
private void preOrderTraverseNode(Node node){
if (node != null){
System.out.print(node.key + " ");
preOrderTraverseNode(node.left);
preOrderTraverseNode(node.right);
}
}
//后序遍历方法:
public void pastOrderTraverse(){
pastOrderTraverseNode(this.root);
}
private void pastOrderTraverseNode(Node node){
if (node != null){
pastOrderTraverseNode(node.left);
pastOrderTraverseNode(node.right);
System.out.print(node.key + " ");
}
}
//查找方法:
public boolean search(int key){
return searchNode(this.root, key);
}
private boolean searchNode(Node node, int key){
if (node == null){
return false;
}else if (key < node.key){
searchNode(node.left, key);
}else if (key > node.key){
searchNode(node.right, key);
}
return false;
}
//找最大值方法:
public int max(){
Node node = this.root;
while (node.right != null){
node = node.right;
}
return node.key;
}
//找最小值方法:
public int min(){
Node node = this.root;
while (node.left != null){
node = node.left;
}
return node.key;
}
//删除方法:
public void remove(int key){
this.root = removeNode(this.root, key);
}
private Node removeNode(Node node, int key){
if (node == null){
return null;
}
if (key < node.key){
node.left = removeNode(node.left, key);
return node;
}else if (key > node.key){
node.right = removeNode(node.right, key);
return node;
}else{
if (node.left == null && node.right == null){
return null;
}else if(node.left == null){
return node.right;
}else if (node.right == null){
return node.left;
}else{
Node find = node.right;
while (find != null && find.left != null){
find = find.left;
}
node.key = find.key;
node.right = removeNode(node.right, find.key);
return node;
}
}
}
//main方法测试代码:
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
int[] nodes = new int[]{3, 6, 2, 1, 8, 5};
for (int node : nodes){
bst.insert(node);
}
bst.inOrderTraverse();//1,2,3,5,6,8
System.out.println();
bst.remove(bst.max());
bst.inOrderTraverse();//1,2,3,5,6
}
}
三、JavaScript版本
module.exports = function BinarySerachTree() {
function node(key) { //结点对象,包括键、左孩子和右孩子三个字段
this.key = key
this.left = null
this.right = null
}
let root = null //根结点
this.insert = key => { //插入结点
let newNode = new node(key) //创建新的结点实例
if (root === null) {
root = newNode
} else {
insertNode(root, newNode) //调用插入结点的递归函数
}
}
let insertNode = (node, newNode) => { //插入结点的递归函数
if (newNode.key < node.key) { //如果新结点的键小于该父结点
if (node.left === null) { //如果该父结点的左孩子为空,则插入该结点
node.left = newNode
} else { //若不为空则递归到下一层
insertNode(node.left, newNode)
}
} else { //如果新结点大于或等于该父结点
if (node.right === null) { //如果该父结点的右孩子为空,则插入该结点
node.right = newNode
} else { //若不为空则递归到下一层
insertNode(node.right, newNode)
}
}
}
this.search = key => { //查找一个键,true/false
return searchNode(root, key) //调用查找结点的递归函数
}
let searchNode = (node, key) => { //查找结点的递归函数
if (node === null) {
return false
}
if (key < node.key) { //如果该键小于父结点的键则访问左孩子
return searchNode(node.left, key)
} else if (key > node.key) { //如果该键大于父结点的键则访问右孩子
return searchNode(node.right, key)
} else { //如果该键等于父结点的键
return true
}
}
let printNode = value => { //结点输出函数
console.log(value)
}
this.inOrderTraverse = () => { //二叉树的中序遍历
inOrderTraverseNode(root) //调用中序遍历二叉树结点的递归函数
}
let inOrderTraverseNode = node => { //中序遍历二叉树结点的递归函数
if (node !== null) {
inOrderTraverseNode(node.left)
printNode(node.key)
inOrderTraverseNode(node.right)
}
}
this.preOrderTraverse = () => { //二叉树的先序遍历
preOrderTraverseNode(root) //调用先序遍历二叉树结点的递归函数
}
let preOrderTraverseNode = node => { //先序遍历二叉树结点的递归函数
if (node !== null) {
printNode(node.key)
preOrderTraverseNode(node.left)
preOrderTraverseNode(node.right)
}
}
this.postOrderTraverse = () => { //二叉树的后序遍历
postOrderTraverseNode(root) //调用后序遍历二叉树结点的递归函数
}
let postOrderTraverseNode = node => { //后序遍历二叉树结点的递归函数
if (node !== null) {
preOrderTraverseNode(node.left)
preOrderTraverseNode(node.right)
printNode(node.key)
}
}
this.min = () => { //返回二叉树中最小的键
let node = root
while (node.left !== null) { //遍历二叉树的所有左孩子
node = node.left
}
return node.key
}
this.max = () => { //返回二叉树中最大的键
let node = root
while (node.right !== null) { //遍历二叉树的所有右孩子
node = node.right
}
return node.key
}
this.remove = key => { //从二叉树中移走某个键
root = removeNode(root, key) //调用移除结点的递归函数(root被赋值为remove方法的返回值)
}
let removeNode = (node, key) => { //移除结点的递归函数
if (node === null) { //若结点为null则返回null
return null
}
if (key < node.key) { //若该键小于父结点的键则进入下一层递归
node.left = removeNode(node.left, key)
return node //回调时返回父节点
} else if (key > node.key) { //若该键大于父结点的键则进入下一层递归
node.right = removeNode(node.right, key)
return node //回调时返回父节点
} else { //当该键等于父结点的键时
if (node.left === null && node.right === null) { //第一种情况:要移除的是一个叶子结点
node = null
return node //将该叶子结点赋值为null,并返回这个null到原来位置
} else if (node.left === null || node.right === null) { //第二种情况:要移除的是一个有单个孩子的父结点
if (node.left === null) { //有右孩子的父结点
node = node.right
return node //将该父结点赋值为右孩子,并返回这个结点到原来位置
} else { //有左孩子的父结点
node = node.left
return node
}
} else { //第三种情况:要移除的是一个有左右孩子的父结点
let aux = findMinNode(node.right) //找右子树中最小的一个结点来代替父结点
node.key = aux.key
node.right = removeNode(node.right, aux.key) //将右子树中最小结点移除
return node
}
let findMinNode = node => { //找右子树中最小结点的函数
while (node !== null && node.left !== null) {
node = node.left
}
return node
}
}
}
}