zoukankan      html  css  js  c++  java
  • 有序符号表(二叉树实现,JAVA,算法(四))

    二叉树的实现和链表的节点是一致的,一个节点里面包含了键值对。只是由于二叉树的特性,便于插入,删除,查询等操作。二叉树的性质使这些操作都可以在logN的时间完成。但是,,,由于执行插入操作的不确定性,比如大多的升序或者降序插入,将导致二叉树的高度像链表一样,不再具有二叉树特有的logN的高度了。所以基于二叉树之上,一种可以维持自身高度的树出现了,那就是红黑树。下一篇再介绍红黑树。

    package com.lizi.datastructure.symboltable;
    
    import java.util.ArrayList;
    import java.util.List;
    
    //二叉搜索树,继承的类在上一篇中有写到
    public class BinarySearchTreeST<Key extends Comparable<Key>,Value> extends SymbolTable<Key,Value> {
        private Node root;//根节点
        private class Node{
            private Key key;  //键
            private Value value;    //值
            private Node left;      //左孩子
            private Node right;     //右孩子
            private int size;       //以该节点为根的子树中节点总数
            public Node(Key key,Value value,int size){
                this.key=key;
                this.value=value;
                this.size=size;
            }
        }
        @Override
        public void put(Key key, Value value) {
            if(value==null) {delete(key); return;}
            root=put(root, key, value);
    
        }
        private Node put(Node root,Key key,Value value) {
            if(root==null) return new Node(key, value, 1);
            int cmp=key.compareTo(root.key);
            if(cmp<0)       root.left=put(root.left, key, value);
            else if(cmp>0)  root.right=put(root.right, key, value);
            else            root.value=value;
            root.size=size(root.left)+size(root.right)+1;
            return root;
    
        }
        @Override
        public Value get(Key key) {
            return get(root, key);
        }
        private Value get(Node root,Key key) {
            if(root==null)  return null;
            int cmp=key.compareTo(root.key);
            if(cmp<0)       return get(root.left, key);
            else if(cmp>0)  return get(root.right, key);
            else            return root.value;
        }
        @Override
        public Value delete(Key key) {
            Value value=get(key);
            root=delete(root, key);
            return value;
    
        }
        private Node delete(Node root,Key key) {
            if(root==null) return null;
            int cmp=key.compareTo(root.key);
            if  (cmp<0) root.left=delete(root.left, key);
            else if(cmp>0) root.right=delete(root.right, key);
            else{//删除操作
                if(root.right==null) return root.left;//左右孩子不全,直接替补上去
                if(root.left==null) return root.right;
                Node node=root;//包含左右孩子的删除操作
                root=min(node.right);
                root.right=deleteMin(node.right);
                root.left=node.left;
            }
            root.size=size(root.left)+size(root.right)+1;
            return root;
        }
    
        @Override
        public int size() {
            return size(root);
        }
        private int size(Node root) {
            if (root==null) return 0;
            else return root.size;
        }
    
        @Override
        public Key min() {
            return min(root).key;
        }
        private Node min(Node root) {
            if(root.left==null) return root;
            else return root.left;
        }
    
        @Override
        public Key max() {
            return max(root).key;
        }
        private Node max(Node root) {
            if(root.right==null) return root;
            else return root.right;
        }
    
        @Override
        public Key floor(Key key) {
            Node node=floor(root, key);
            if(node==null) return null;
            return node.key;
        }
        //找到第一个小于等于key的节点,再在它的右子树的左子树中找寻是否有小于key的节点
        //如果有,那么这个键就是最接近key的节点,一个闪电形状
        private Node floor(Node root,Key key) {
            if(root==null) return null;
            int cmp=key.compareTo(root.key);
            if(cmp==0)      return root;
            if(cmp<0)       return floor(root.left, key);
            Node node=floor(root.right, key);
            if (node!=null) return node;
            else            return root;
        }
        @Override
        public Key ceiling(Key key) {
            Node node=ceiling(root, key);
            if(node==null) return null;
            return node.key;
        }
        private Node ceiling(Node root,Key key) {
            if(root==null) return null;
            int cmp=key.compareTo(root.key);
            if(cmp==0)          return root;
            if(cmp>0)           return floor(root.right, key);
            Node node=floor(root.left, key);
            if (node!=null)     return node;
            else                return root;
        }
        @Override
        public int rank(Key key) {
            return rank(root, key);
        }
        //返回以root为根节点的子树中小于key的键的数量
        private int rank(Node root,Key key) {
            if(root==null) return 0;
            int cmp=key.compareTo(root.key);
            if(cmp<0)       return rank(root.left, key);
            else if(cmp>0)  return rank(root.right, key)+size(root.left)+1;
            else            return size(root.left);
        }
        @Override
        public Key select(int index) {
            if(index>=size()) return null;
            return select(root,index).key;
        }
        //返回下标为index的键
        private Node select(Node root,int index) {
            if(root==null) return null;
            int size=size(root.left);
            if(size>index)      return select(root.left, index);
            else if(size<index) return select(root.right, index);
            else                return root;
        }
        //将下标位于low-high之间的所有键放入链表中
        @Override
        public Iterable<Key> keys(Key low, Key high) {
            List<Key> list=new ArrayList<Key>();
            keys(root,list,low,high);
            return list;
        }
        private void keys(Node root,List<Key> list,Key low, Key high) {
            if(root==null) return;
            int cmplow=low.compareTo(root.key);
            int cmphigh=high.compareTo(root.key);
            if(cmplow<0) keys(root.left, list, low, high);
            if(cmphigh<=0&&cmphigh>=0) list.add(root.key);
            if(cmphigh>0) keys(root.right, list, low, high);
        }
        //删除最小的键
        public void deleteMin(){
            root=deleteMin(root);
        }
        private Node deleteMin(Node root){
            if(root.left==null) return root.right;
            root.left=deleteMin(root.left);//如果最小节点有右孩子,那么替代自身成为其父节点的左孩子
            root.size=size(root.left)+size(root.right)+1;//左右孩子加上自身
            return root;
        }
    
        //删除最大的键
        public void deleteMax(){
            deleteMax(root);
        }
        private Node deleteMax(Node root){
            if(root.right==null) return root.left;
            root.right=deleteMin(root.right);//如果最小节点有左孩子,那么替代自身成为其父节点的右孩子
            root.size=size(root.left)+size(root.right)+1;//左右孩子加上自身
            return root;
        }
        public void print() {
            print(root);
        }
        private void print(Node root) {
            if(root==null) return;
            print(root.left);
            System.out.println(" 键:"+root.key+" 值:"+root.value);
            print(root.right);
        }
    }
  • 相关阅读:
    Code Review(代码的自我评审)
    在ANDROID STUDIO环境下使用Espresso 测试框架进行UI测试
    第一个迭代任务——倒计时
    Scrum的3种角色划分——倒计时
    需求分析(WBS图)
    countdown(计时器)
    Countdown(计时器)
    团队模式选择
    软件开发流程
    软件团队的模式
  • 原文地址:https://www.cnblogs.com/lizijuna/p/11907421.html
Copyright © 2011-2022 走看看