zoukankan      html  css  js  c++  java
  • 《算法导论》学习笔记——二叉搜索树

    二叉搜索树

    什么是二叉搜索树

    对于任何节点x,其左子树中的关键字最大不超过(x.key),其右子树中的关键字最小不低于(x.key)。即:

    ​ 设x是二叉搜索中的一个结点。如果y是x左子树中的任意结点,那么(y.key<=x.key)。如果y是x右子树中的任意结点,那么(y.key>=x.key)

    中序遍历

    中序遍历可以按序输出二叉搜索树中的所有关键字。

    public void inorderTreeWalk(Node x){
      if(x != null){
        inorderTreeWalk(x.left);
        System.out.println(x.key);
        inorderTreeWalk(x.right);
      }
    }
    

    查询二叉搜索树

    高度为h的二叉搜索树上进行SEARCH(普通查询)、MINIMUM(最大关键字)、MAXIMUM(最小关键字)、SUCCESSOR(后继)和PREDECESSOR(前驱)等查询操作,都可以在(O(h))世间内完成。

    • 普通查找
     /**
    	 * 递归实现的普通查找
    	 * @param x   二叉搜索树的根结点
    	 * @param key 查询结点的关键字
    	 */
    	public Node treeSearch(Node x, int key) {
    		if (x == null || key == x.key)
    			return x;
    		if (key < x.key) {
    			return treeSearch(x.left, key);
    		} else {
    			return treeSearch(x.right, key);
    		}
    	}
    	/**
    	 * 迭代实现的普通查找
    	 */
    	public Node iterativeTreeSearch(Node x, int key) {
    		while (x != null && key != x.key) {
    			if (key < x.key) {
    				x = x.left;
    			} else {
    				x = x.right;
    			}
    		}
    		return x;
    	}
    
    • 最大关键字元素和最小关键字元素
      /**
    	 * 获取最小关键字元素
    	 * @param x 查询二叉树根结点
    	 */
    	public Node treeMinimum(Node x) {
    		while (x.left != null) {
    			x = x.left;
    		}
    		return x;
    	}
    	/**
    	 * 获取最大关键字元素
    	 */
    	public Node treeMaximum(Node x) {
    		while (x.right != null) {
    			x = x.right;
    		}
    		return x;
    	}
    
    • 后继和前驱

      按中序遍历次序查找一个结点的后继和前驱。一个结点x的后继是大于x.key的最小关键字的结点,前驱是小于x.key的最大关键字的结点。

    	/**
    	 * 返回一个结点的后继
    	 */
    	public Node successor(Node x) {
    		if (x.right != null) {
    			return treeMinimum(x.right);
    		}
    		Node y = x.p;
    		while (y != null && x == y.right) {
    			x = y;
    			y = y.p;
    		}
    		return y;
    	}
    
    • 练习

    12.2-5 证明:如果一颗二叉搜索树中的一个结点有两个孩子,那么它的后继没有左孩子,它的前驱没有右孩子。

    证明如下: 根据二叉搜索树的性质,如果一个结点存在右子结点,则这个结点的后继是其右子树中的最小结点;假设这个结点的后继有左孩子,说明该后继结点不是右子树中的最小结点,即假设不成立,即这个结点的后继没有左孩子。同理可证明这个结点前驱没有右孩子。

    插入和删除

    • 插入
    	/**
    	 * 插入一个结点
    	 *
    	 * @param tree 二叉搜索树
    	 * @param z    待插入的结点
    	 */
    	public void treeInsert(BinarySearchTree tree, Node z) {
    		Node y = null;
    		Node x = tree.root;
    		while (x != null) {
    			y = x;
    			if (z.key < x.key) {
    				x = x.left;
    			} else {
    				x = x.right;
    			}
    		}
    		z.parent = y;
    		if (y == null) {
    			tree.root = z; // 二叉搜索树为空
    		} else if (z.key < y.key) {
    			y.left = z;
    		} else {
    			y.right = z;
    		}
    	}
    
    • 删除
     /**
    	 * 在tree中删除结点z
    	 */
    	public void treeDelete(BinarySearchTree tree, Node z) {
    		if (z.left == null) {
    			transplant(tree, z, z.right);
    		} else if (z.right == null) {
    			transplant(tree, z, z.left);
    		} else {
    			Node y = treeMinimum(z.right);
    			if (y != z.right) {
    				transplant(tree, y, y.right);
    				y.right = z.right;
    				y.right.parent = y;
    			}
    			transplant(tree, z, y);
    			y.left = z.left;
    			y.left.parent = y;
    		}
    	}
    	/**
    	 * 在tree中,用一棵以v为根的子树替换一棵以u为根的子树
    	 * 替换完后,结点u的父结点变为结点v的父结点,并且结点v成为u的父结点的相应子结点
    	 * 注意,这里并没有处理v的子结点更新;这些更新由此方法调用者来负责。
    	 */
    	public void transplant(BinarySearchTree tree, Node u, Node v) {
    		if (u.parent == null) {
    			tree.root = v;
    		} else if (u.parent.left == u) {
    			u.parent.left = v;
    		} else {
    			u.parent.right = v;
    		}
    		if (v != null) {
    			v.parent = u.parent;
    		}
    	}
    
  • 相关阅读:
    原!!如何将多个复杂查询整合成一个查询,并作为一个对象的各个字段输出
    转!!mysql order by 中文排序
    mybatis 模糊查询 like
    转!!log4j基础
    CI框架下的PHP增删改查总结
    tp5中url使用js变量传参方法
    一个用户管理的ci框架的小demo--转载
    CI框架入门教程
    PHP的CI框架流程基本熟悉
    CI
  • 原文地址:https://www.cnblogs.com/k-blog/p/14225760.html
Copyright © 2011-2022 走看看