二叉搜索树(BST)

一、树形结构VS线性结构

动态数组 单向链表 双向链表 二叉搜索树
增加的时间复杂度 O(N) O(N) + O(1) O(N) + O(1) O(log N)
删除的时间复杂度 O(N) O(N) + O(1) O(N) + O(1) O(log N)
查询的时间复杂度 O(1) O(N) O(N) O(log N)





二、树的基本概念梳理

       结点的度:子树的个数。

       树的度:所有结点度中的最大值。

       结点的高度:当前结点到最远叶子结点路径上的结点总数。

       结点的深度:根结点到当前结点唯一路径上的结点总数。

       树的高度:所有结点中的最大高度。

       树的深度:所有结点中的最大深度。

       树的高度和深度相等

       N叉树:每个结点的最大度为N

       真二叉树:所有结点的度为2或者0。

       满二叉树:每一层都排满结点,而且有第n层结点数为2^(n-1), n层的满二叉树结点总数为2^n-1, n层的满二叉树高度为log2(n+1)

       完全二叉树:叶子节点只能分布在最后一层和最后第二层,最后层叶子结点一定先排满左边。



       完全二叉树一些性质:

              1、高度为h的完全二叉树结点最多是2 ^h-1,此时是满二叉树;结点最少是2 ^(h-1)。

              2、N个结点的完全二叉树高度为floor(log2 N)+1,可由性质2的不等式推导出来。

              3、度为1的结点数只能是1或者0

              4、nm 表示度为m的结点,有n2 + 1 = n0

              证明依据:结点总数 = 总边数(n0 x 0 + n1 x 1 + n2 x 2) + 1 = n0 + n1 + n2






二、二叉搜索树

1、BST简介

       二叉搜索树也叫二叉排序树、二叉查找树。Binary Search Tree满足下面三个条件:
              ① 任意一个结点的值都大于其左子树所有结点的值 ;
              ② 任意一个结点的值都小于其右子树所有结点的值 ;
              ③ 它的左右子树也是一棵二叉搜索树。

       下图就是一棵简单的二叉搜索树:
Alt


2、BST的设计

       定义一个抽象的基类,装一些二叉树通用的成员方法,二叉搜索树继承这个父类。

Alt

       这两个都用泛型,二叉搜索树因为需要比较大小,考虑下面两种方案:

              ① public class BinarySearchTree<E extends Comparable>肯定不可取,只有实现接口才能通过编译。

              ② 组合一个比较器Comparator,完全解决顾虑,在构造函数中传入参数,当想要插入引用数据类型的时候,可以传入匿名类搞定。



3、左右旋转图解

Alt

Alt





三、二叉搜索树代码

1、秘籍

       二叉树共有的方法:

              前序遍历:先访问根结点,再前序遍历访问左子树,最后前序遍历访问右子树。

              中序遍历:先中序遍历访问左子树,再访问根结点,最后中序遍历访问右子树。BST中序遍历一定是升序或者降序

              后序遍历:先后序遍历访问左子树,再后序遍历访问右子树,最后访问根结点

              层次遍历:从上到下,从左到右,八个字言简意赅。计算二叉树高度、判断是否是完全二叉树

              寻找A结点的前驱结点:中序遍历时的前一个结点。如果A结点有左子树的话,前驱结点就是左子树上最右边的结点。如果A结点没有左子树的话,前驱结点就是其父结点中第一个是右子树的结点

              寻找A结点的后继结点:中序遍历时的后一个结点。参照BST理解为结点值大于A结点的值,而且最靠近A的值。如果A结点有右子树的话,后继结点就是右子树上最左边的结点。如果A结点没有右子树的话,后继结点就是其父结点中第一个是左子树的结点



       二叉搜索树特有方法:
              插入:比大小插入即可。

              删除:删除某个结点按度分为三种情况。当度为0时直接删掉叶子结点;当度为1找自己的儿子代替自己的位置;当度为2时,先找到该结点的前驱结点或者后继结点,将找到结点的数据覆盖掉要删除结点的数据,再将前驱结点或后继结点删除(此时这两个结点的度要么是1,要么是0)。



2、代码

       BinaryTree代码:

	public abstract class BinaryTree<E> {
	    protected Node<E> root;
	    protected int size = 0;
	
	    protected class Node<E> {
	        Node<E> left;
	        Node<E> right;
	        Node<E> parent;
	        E element;
	
	        public Node(Node<E> parent, E element) {
	            this.parent = parent;
	            this.element = element;
	        }
	
	        @Override
	        public String toString() {
	            StringBuilder str = new StringBuilder();
	            str.append("Node{");
	//            str.append(" parent=");
	//            if (parent != null)
	//                str.append(parent.element);
	//            else
	//                str.append("null");
	            str.append(", element=").append(element).append("}");
	            return str.toString();
	        }
	    }
	
	    public int size() {
	        return this.size;
	    }
	
	    public boolean isEmpty() {
	        return size == 0;
	    }
	
	    public void clear() {
	        size = 0;
	        root = null;
	    }
	
	    /**
	     * 获取某个结点的度
	     */
	    protected int getDegree(Node<E> node) {
	        int s = 0;
	        if (node.left != null)
	            s++;
	        if (node.right != null)
	            s++;
	        return s;
	    }
	
	    /**
	     * 二叉树前序遍历
	     */
	    public void preOrderTraversal() {
	        preOrder(root);
	    }
	
	    private void preOrderTraversal(Node<E> node) {
	        if (node == null)
	            return;
	        System.out.print(node.element + " ");     //最外层递归root并没有变
	        preOrderTraversal(node.left);
	        preOrderTraversal(node.right);
	    }
	
	    /**
	     * 非递归二叉树前序遍历
	     */
	    private void preOrder(Node<E> node) {
	        Stack<Node<E>> stack = new Stack<>();
	
	        while (true) {
	            if (node != null) {
	                System.out.print(node.element + " ");
	                if (node.right != null)
	                    stack.push(node.right);
	                node = node.left;
	            } else {
	                if (!stack.isEmpty())
	                    node = stack.pop();
	                else
	                    break;
	            }
	        }
	    }
	
	    /**
	     * 二叉树中序遍历
	     */
	    public void inOrderTraversal() {
	        inOrder(root);
	    }
	
	    private void inOrderTraversal(Node<E> node) {
	        if (node == null)
	            return;
	        inOrderTraversal(node.left);
	        System.out.print(node.element + " ");     //最外层递归root并没有变
	        inOrderTraversal(node.right);
	    }
	
	    /**
	     * 非递归二叉树中序遍历
	     */
	    private void inOrder(Node<E> node) {
	        Stack<Node<E>> stack = new Stack<>();
	        while (true) {
	            if (node != null) {
	                stack.push(node);
	                node = node.left;
	            } else {
	                if (!stack.isEmpty()) {
	                    node = stack.pop();
	                    System.out.print(node.element + " ");
	                } else
	                    break;
	                node = node.right;
	            }
	        }
	    }
	
	    /**
	     * 二叉树后序遍历
	     */
	    public void postOrderTraversal() {
	        postOrder(root);
	    }
	
	    private void postOrderTraversal(Node<E> node) {
	        if (node == null)
	            return;
	        postOrderTraversal(node.left);
	        postOrderTraversal(node.right);
	        System.out.print(node.element + " ");     //最外层递归root并没有变
	    }
	
	    /**
	     * 非递归二叉树后序遍历
	     */
	    private void postOrder(Node<E> node) {
	        Stack<Node<E>> stack = new Stack<>();
	        stack.push(node);
	        Node<E> prevNode = null;
	        while (!stack.isEmpty()) {
	            Node<E> top = stack.peek();
	            if ((top.left == null && top.right == null) || (prevNode != null && prevNode.parent == top)) {
	                prevNode = stack.pop();
	                System.out.print(prevNode.element + " ");
	            } else {
	                if (top.right != null)
	                    stack.push(top.right);
	                if (top.left != null)
	                    stack.push(top.left);
	            }
	        }
	    }
	
	    /**
	     * 二叉树层次遍历
	     */
	    public void levelTraversal() {
	        Queue<Node<E>> queue = new LinkedList<>();
	        if (root == null)
	            return;
	        queue.add(root);
	        while (!queue.isEmpty()) {
	            Node<E> t = (Node<E>) queue.remove();
	            System.out.print(t.element + " ");      //访问根结点
	            if (t.left != null)
	                queue.add(t.left);  //左子树入队
	            if (t.right != null)
	                queue.add(t.right); //右子树入队
	        }
	    }
	
	    /**
	     * 获取某个结点的前驱结点
	     */
	    public Node<E> getPrecursor(Node<E> node) {
	        Node<E> t = node.left;
	        if (t != null) {  //有左子树就遍历左子树的右子树
	            while (t.right != null) {
	                t = t.right;
	            }
	            return t;
	        } else {     //说明没有左子树就从父结点找
	            Node<E> parent = node;
	            while (parent != null) {
	                if (parent.parent == null)
	                    return null;
	                if (parent.parent.right == parent)
	                    return parent.parent;
	                parent = parent.parent;
	            }
	            return null;
	        }
	    }
	
	    /**
	     * 获取某个结点的后继结点
	     */
	    public Node<E> getSuccessor(Node<E> node) {
	        Node<E> t = node.right;
	        if (t != null) {  //有右子树就遍历右子树的左子树
	            while (t.left != null) {
	                t = t.left;
	            }
	            return t;
	        } else {     //说明没有右子树就从父结点找
	            Node<E> parent = node;
	            while (parent != null) {
	                if (parent.parent == null)
	                    return null;
	                if (parent.parent.left == parent)
	                    return parent.parent;
	                parent = parent.parent;
	            }
	            return null;
	        }
	    }
	
	    /**
	     * 判断是否是完全二叉树
	     */
	    public boolean isComplete() {
	        Queue<Node<E>> queue = new LinkedList<>();
	        queue.add(root);
	        boolean leaf = false;
	        while (!queue.isEmpty()) {
	            Node<E> node = queue.remove();
	
	            //总共情况: 1、左为空,右为空; 2、左为空,右不为空(false); 3、左不为空,右为空; 4、左右都不为空
	            //1 和 3 的情况出现后, 之后访问的结点都是叶子结点才是true
	            if (node.left != null) {
	                if (leaf)
	                    return false;
	                queue.add(node.left);
	            } else if (node.right != null) {   //说明左子树为空, 右子树不为空, 一定不是完全二叉树
	                return false;
	            }
	
	            if (node.right != null) {    //能走到这里说明不会是情况2
	                if (leaf)
	                    return false;
	                queue.add(node.right);
	            } else      //1 和 3情况
	                leaf = true;
	        }
	        return true;
	    }
	
	    /**
	     * 获取二叉树的高度
	     */
	    public int getHeight() {
	        return height(root);
	    }
	
	    private int height(Node<E> node) {
	        Queue<Node<E>> queue = new LinkedList<>();
	        queue.add(root);
	        int size = 1;
	        int height = 0;
	        while (!queue.isEmpty()) {
	            Node<E> t = queue.remove();
	            size--;
	            if (t.left != null)
	                queue.add(t.left);
	            if (t.right != null)
	                queue.add(t.right);
	            if (size == 0) {
	                height++;
	                size = queue.size();
	            }
	        }
	        return height;
	    }
	}

       BinarySearchTree代码:

	public class BinarySearchTree<E> extends BinaryTree<E> {
	    private Comparator<E> comparator;
	
	    public BinarySearchTree(Comparator<E> comparator) {
	        this.comparator = comparator;
	    }
	
	    public BinarySearchTree() {
	        this(null);     //调用有参构造
	    }
	
	    private int compare(E e1, E e2) {
	        if (comparator != null)
	            return comparator.compare(e1, e2);
	        else
	            return ((Comparable) e1).compareTo(e2);
	    }
	
	    public boolean contains(E element) {
	        return getNode(element) != null;
	    }
	
	    public Node<E> getNode(E element) {
	        Node<E> node = root;
	        while (node != null) {
	            int cmp = compare(element, node.element);
	            if (cmp > 0) {
	                node = node.right;
	            } else if (cmp < 0) {
	                node = node.left;
	            } else {
	                return node;
	            }
	        }
	        return null;
	    }
	
	    /**
	     * BST插入一个结点
	     *
	     * @param element
	     */
	    public void add(E element) {
	        Node<E> node = root;
	        if (root == null) {    //插入第一个结点
	            root = new Node(null, element);
	            size++;
	            return;
	        }
	        int cmp = 0;
	        Node<E> parent = null;
	        while (node != null) {
	            parent = node;
	            cmp = compare(element, node.element);
	            if (cmp > 0) {   //待插入的元素比根结点元素大
	                node = node.right;
	            } else if (cmp < 0) {   //待插入的元素比根结点元素小
	                node = node.left;
	            } else {
	                return;
	            }
	        }
	        if (cmp > 0)
	            parent.right = new Node<E>(parent, element);
	        else
	            parent.left = new Node<E>(parent, element);
	        size++;
	    }
	
	    /**
	     * BST删除节点要分情况, 度为0、1、2
	     *
	     * @param element
	     */
	    public void remove(E element) {
	        Node<E> node = getNode(element);
	        if (node == null)
	            return;
	
	        if (getDegree(node) == 2) {
	            Node<E> t = getSuccessor(node);
	            node.element = t.element;
	            node = t;    //复用代码
	        }
	
	        if (getDegree(node) == 0) {    //度为0, 直接删除即可
	            if (root == node) {		//只有一个根结点
	                root = null;	  
	                return;
	            }
	            if (node == node.parent.left)
	                node.parent.left = null;
	            else
	                node.parent.right = null;
	                
	        } else if (getDegree(node) == 1) { //度为1, 找自己的左儿子或右儿子替代
	            if (node.left != null) {    //找左儿子代替
	                if (root == node) {		//只有一个根结点
	                    root = node.left;
	                    return;
	                }
	                if (node.parent.left == node) {
	                    node.parent.left = node.left;
	                    node.left.parent = node.parent;   //改变父结点
	                } else {
	                    node.parent.right = node.left;
	                    node.left.parent = node.parent;   //改变父结点
	                }
	            } else {    //找右儿子代替
	                if (root == node) {		//只有一个根结点
	                    root = node.right;
	                    return;
	                }
	                if (node.parent.left == node) {
	                    node.parent.left = node.right;
	                    node.right.parent = node.parent;   //改变父结点
	                } else {
	                    node.parent.right = node.right;
	                    node.right.parent = node.parent;   //改变父结点
	                }
	            }
	        }
	    }
	}
发布了54 篇原创文章 · 获赞 5 · 访问量 4611

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/104505929
今日推荐