常见的查找算法(五):树表查找之一 ---- 二叉查找树

二叉查找树英语:Binary Search Tree),也称为二叉搜索树有序二叉树ordered binary tree)或排序二叉树sorted binary tree),是指一棵空树或者具有下列性质的二叉树

  1. 若任意节点的左子树不空,则左子树上所有节点的key值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的key值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

 

二叉查找树的节点

 1     //二叉树节点
 2     static class BSTNode<T> {
 3         T data;
 4         BSTNode<T> parent;
 5         BSTNode<T> left;
 6         BSTNode<T> right;
 7 
 8         public BSTNode() {
 9             this.data = null;
10             this.left = left;
11             this.right= right;
12         }
13 
14         public BSTNode(T data) {
15             this(data,null, null);
16         }
17 
18         public BSTNode(T data, BSTNode<T> left, BSTNode<T> right) {
19             this.data = data;
20             this.left = left;
21             this.right = right;
22         }
23     }

查找操作

  这个过程是从树根开始查找,沿着这棵树的一条简单路劲向下进行,根据二叉查找树的性质来比较每个节点的关键字的值,来决定下一个节点的查找方向,若该节点是要查找的关键字,则结束查找过程。

 1     /******************************* 查找 start *******************************/
 2 
 3     /**
 4      * 从根节点查找
 5      *
 6      * @param data 要查找的元素
 7      * @return
 8      */
 9     public boolean searchBST(T data) {
10         return searchBST(data, root);
11     }
12 
13     /**
14      * 递归查找指定元素是否在树中
15      *
16      * @param node 树中节点
17      * @param data 要查找的元素
18      * @return
19      */
20     public boolean searchBST(T data, BSTNode<T> node) {
21         if (node == null)
22             return false;
23 
24         count++;
25         int result = data.compareTo(node.data);
26 
27         if (result > 0) {
28             return searchBST(data, node.right);//往右子树查询
29         } else if (result < 0) {
30             return searchBST(data, node.left);//往左子树查询
31         } else {
32             return true;
33         }
34     }
35 
36     /**
37      * 寻找二叉树中最大的元素
38      *
39      * @return
40      */
41     public T findMax() {
42         if (isEmpty()) {
43             System.out.println("二叉树为空");
44             return null;
45         } else {
46             return findMax(root).data;
47         }
48     }
49 
50     /**
51      * 寻找二叉树中最大的元素
52      *
53      * @param node 当前的结点
54      * @return
55      */
56     public BSTNode<T> findMax(BSTNode<T> node) {
57         if (node == null) {
58             return null;
59         } else if (node.right == null) {
60             return node;
61         } else {
62             //迭代
63             while (node.right != null) {
64                 node = node.right;
65             }
66             return node;
67         }
68     }
69 
70     /**
71      * 寻找二叉树中最小的元素
72      *
73      * @return
74      */
75     public T findMin() {
76         if (isEmpty()) {
77             System.out.println("二叉树为空");
78             return null;
79         } else {
80             return findMin(root).data;
81         }
82     }
83 
84     /**
85      * 寻找二叉树中最小的元素
86      *
87      * @param node 当前节点
88      * @return
89      */
90     public BSTNode<T> findMin(BSTNode<T> node) {
91         if (node == null)
92             return null;
93         else if (node.left == null)
94             return node;
95         return findMin(node.left);
96     }
97 
98     /******************************* 查找 end *******************************/

时间复杂度分析二叉搜索树上的基本操作所花费的时间与这颗树的高度成正比。根据二叉查找树的性质,给定一个元素,去查找树中的元素,是从根节点那开始一层层比较节点的值,从而选定在树中查找的方向。当查找到该元素时,已经比较了n层,也就是元素在树中的层数(根节点为第一层),每层比较一个节点,然而二叉树的高度与它的节点数量有关,为log₂(n+1),所以二叉查找树的朝招时间复杂度为O(log₂n)。

插入操作

  1. 此树是空树,则直接将插入的结点作为根结点插入。
  2. 插入的值等于插入的值的根结点的数据的值,则直接返回,否则。
  3. 插入的值小于此树根结点的数据的值,则将要插入的结点的位置改变为此树左子树,否则4。
  4. 插入的值的结点的位置改变为此树右子树
 1     /******************************* 插入 start *******************************/
 2     //插入元素
 3     public void insert(T t) {
 4         root = insert(t, root);
 5     }
 6 
 7     /**
 8      * 构建一个二叉查找树
 9      *
10      * @param t    插入元素
11      * @param node 插入结点
12      * @return
13      */
14     public BSTNode<T> insert(T t, BSTNode<T> node) {
15         if (node == null)
16             return new BSTNode<T>(t, null, null);
17         int result = t.compareTo(node.data);
18         if (result < 0) {
19             node.left = insert(t, node);
20         } else if (result > 0) {
21             node.right = insert(t, node);
22         } else {
23             System.out.println("插入失败");
24         }
25         return node;
26     }
27     /******************************* 插入 end *******************************/

关于前驱和后继

  所有的关键字都互不相同,则一个节点的x的后继是大于x.key的最小关键字的结点。

删除操作

对于二叉查找树的删除操作(这里根据值删除,而非结点)分三种情况:

  1. 如果结点为叶子结点(没有左、右子树),此时删除该结点不会破坏树的结构,直接删除即可,并修改其父结点指向它的引用为null
  2. 如果其结点只包含左子树,或者右子树的话,此时直接删除该结点,并将其左子树或者右子树设置为其父结点的左子树或者右子树即可,此操作不会破坏树结构
  3. 当结点的左、右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替 要删除的结点数据递归删除该结点(此时为null)
 1     /******************************* 删除 start *******************************/
 2     /**
 3      * 删除元素
 4      * @param t
 5      */
 6     public void remove(T t) {
 7         root = remove(t, root);
 8     }
 9 
10     /**
11      * 删除某个位置的结点
12      * @param t
13      * @param node
14      * @return
15      */
16     public BSTNode<T> remove(T t, BSTNode<T> node) {
17         if (node == null) {
18             System.out.println("删除失败");
19             return node;
20         }
21         int result = t.compareTo(node.data);
22         if (result > 0) {
23             node.right = remove(t, node.right);
24         } else if (result < 0) {
25             node.left = remove(t, node.left);
26         } else if (node.left != null && node.right != null) {
27             node.data = findMin(node.right).data;
28             node.right = remove(node.data, node.right);
29         } else {
30             node = (node.left != null) ? node.left : node.right;
31         }
32         return node;
33     }
34     /******************************* 删除 end *******************************/

遍历二叉查找树(先序遍历):

1     public void preOrder(BSTNode node) {
2         if (node != null) {
3             System.out.print(node.data + " ");
4             preOrder(node.left);
5             preOrder(node.right);
6         }
7     }

测试代码:

 1     public static void main(String[] args) {
 2         BSTNode<Integer> node3 = new BSTNode<>(3);
 3         BSTNode<Integer> node1 = new BSTNode<>(1);
 4         BSTNode<Integer> node4 = new BSTNode<>(4, node3, null);
 5         BSTNode<Integer> node2 = new BSTNode<>(2, node1, node4);
 6         BSTNode<Integer> node8 = new BSTNode<>(8);
 7         BSTNode<Integer> root = new BSTNode<>(6, node2, node8);
 8 
 9         BSTree bsTree = new BSTree<>();
10         bsTree.root = root;
11         bsTree.preOrder(bsTree.root);
12         //bsTree.remove(4);
13         //System.out.println();
14         //bsTree.preOrder(bsTree.root);
15         bsTree.searchBST(3);
16         System.out.println("查找次数:" + count);
17     }
posted @ 2019-08-21 19:42  賣贾笔的小男孩  阅读(804)  评论(0编辑  收藏  举报