二叉搜索树(BST)

二叉树:每个节点最多有两个孩子,是一种动态数据结构,具有递归结构。

//二叉树的节点定义
class Node<E extends Comparable<E>> {
    E e;
    Node left;
    Node right;
    
    public Node(e) {
        this.e = e;
        left = null;
        right = null;
    }
    
    public String toString() {
        return e.toString();
    }
}

其中空树和只有根节点的树都是二叉树。

满二叉树:对于每一个非叶子节点都有两个节点。

  1. 二分搜索数(BST)

    • 对于每一个节点的值,都大于其左子树的所有节点,小于其右子树的所有节点。另外存储的元素是可比较的。

      public class BST<E extends Comparable<E>> {
          
          private Node root;  //BST的根节点
          private int size;   //BST的大小
          
          public BST() {
              root = null;
              size = 0;
          }
          
      }
      

    BST的一些重要操作

    • contains(E e):判断元素e是否在该BST中

      public boolean contains(E e) {
          return contains(root, e);
      }
      //在以node为根的BST中,判断元素e是否存在于BST中
      private boolean contains(Node node, E e) {
          if(node == null) {
              //没找到e元素
              return false;
          }
          if(e.compareTo(node.e) < 0) {
              //去左子树
              return contains(node.left, e);
          }else if(e.compareTo(node.e) > 0) {
              //去右子树
              return contains(node.right, e);
          }else{
              //找到了e
              return true;
          }
      }
      
    • add(E e):向BST中添加元素e

      public void add(E e) {
          if(root == null) {
              //空树
              root = new Node(e);
              size ++
          }else{
              add(root, e);
          }
          
      }
      
      //在以node为根的BST中添加一个元素,并返回操作之后的以node为根节点的BST
      private Node add(Node node, E e) {
          if(node == null) {
              //找待插入的位置
              size ++;
              //生成新结点,并向上层返回,与上层链接
              return new Node(e);
          }
          if(e.compareTo(node.e) < 0) {
              //去往左子树,并接受返回的树
              node.left = add(node.left, e);
          }else if(e.compareTo(node.e) > 0) {
              //去往右子树,并接受返回的树
              node.right = add(node.right, e)
          }
          return node;
      }
      
    • getMin():获取BST中的最小值节点的值

      public E getMin() {
          if(isEmpty()) {
              throw new RuntimeException("Empty BST!");
          }
          return getMin(root).e;
      }
      
      private Node getMin(Node node) {
          if(node.left == null) {
              return node;
          }
          return getMin(node.left);
      }
      
    • getMax():获取BST中最大节点的值

      public E getMax() {
          if(isEmpty()) {
              throw new RuntimeException("Empty BST!");
          }
          return getMax(root).e;
      }
      
      private Node getMax(Node node) {
          if(node.right == null) {
              return node;
          }
          return getMax(node.right);
      }
      
      
    • remove():移除操作

      public void remove(E e) {
          //注意:root仍然需要承接删除节点后的树
          root = remove(root, e);
      }
      
      public E removeMin() {
          root = remove(root);
          return getMin();
      }
      
      //在以node为根的BST中,删除元素e,返回删除之后的新树
      private Node removeMin(Node node) {
          if(node.left == null) {
              Node rightNode = node.right;
              node.right = null;
              size --;
              return rightNode;
          }
          node.left = removeMin(node.left);
          return node;
      }
      
      private Node remove(Node node, E e) {
          if(node == null) {
              return null;
          }
          if(e.compareTo(node.e) < 0) {
              node.left = remove(node.left, e);
              return node;
          }else if(e.compareTo(node.e) > 0){
              node.right = remove(node.right, e);
              return node;
          }else{
              if(node.right == null) {
                  //没有右子树的情况
                  Node leftNode = node.left;
                  node.left = null;
                  size --;
                  return leftNode;
              }
              if(node.left == null) {
                  //没有左子树的情况
                  Node rightNode = node.right;
                  node.right = null;
                  size --;
                  return rightNode;
              }
              //左右子树均存在
              //获取待删除节点的右子树的最小节点
              Node successor = getMin(node.right);
              //后继结点的右子树接替删除右子树中最小节点后的新树
              successor.right = removeMin(node.right);
              successor.left = node.left;
              
              node.left = node.right = null;
          }
          
      }
      
    • 遍历BST

      • 先序遍历

        //递归写法
        public void preOrder() {
            preOrder(root);
        }
        //在以node为根的BST中先序遍历各节点
        private void preOrder(Node node) {
            if(node == null) {
                return;
            }
            System.out.println(node.e);
            preOrder(node.left);
            preOrder(node.right);
        }
        //非递归写法:借助栈
        private List<E> preOrderNR(Node root) {
            ArrayList<E> res = new ArrayList<>();
            if(root == null) {
                return res;
            }
            
            Stack<Node> stack = new Stack<>();
            stack.push(root);
            while(!statck.isEmpty()) {
                Node curr = stack.pop();
                res.add(curr.e);
                
                //左右子节点入栈,先入有孩子
                if(curr.right != null) {
                    stack.push(curr.right);    
                }
                if(curr.left != null) {
                    stack.push(curr.left);    
                }
            }
            return res;
        }
        
      • 中序遍历

        public void inOrder() {
            inOrder(root);
        }
        //递归写法
        private void inOrder(Node node) {
            if(node != null) {
                return;
            }
            inOrder(node.left);
            System.out.println(node.e);
            inOrder(node.right);
        }
        //非递归写法
        public void inOrder(Node root) {
            ArrayList<Integer> res = new ArrayList<>();
            if(root == null)    return res;
            
            Stack<Node> stack = new Stack<>();
            Node curr = root;
            while(curr != null || !stack.isEmpty()) {
                //当前节点不为空或栈不为空即可循环
                if(curr != null) {
                    stack.push(curr);
                    curr = curr.left;
                }else{
                    curr = stack.pop();
                    res.add(curr.e);
                    curr = curr.right;
                }
            }
            return res;
        }
        
      • 后序遍历

        public void postOrder() {
            postOrder(root);
        }
        //递归写法
        private void postOrder() {
            if(node != null) {
                return;
            }
            postOrder(node.left);
            postOrder(node.right);
            System.out.println(node.e);
        }
        //非递归写法
        private void postOrderNR(Node root) {
            if(root == null) {
                return;
            }
            Stack<Node> traStack = new Stack<>();
            Stack<Node> resStack = new Stack<>();
            traStack.push(root);
            while(!traStack.isEmpty()) {
                Node curr = traStack.pop();
                resStack.push(curr);
                if(curr.left != null) {
                    traStack.push(curr.left);
                }
                if(curr.right != null) {
                    traStack.push(curr.right);
                }
            }
            while(!resStack.isEmpty()) {
                Node curr = resStack.pop();
                System.out.println(curr.e);
            }
        }
        
      • 层序遍历

        //借助队列
        private void levelOrder() {
            if(root == null) {
                    //空树
                    return;
            }
            
            Queue<Node> queue = new LinkedList<>();
            queue.add(root);
            while(!queue.isEmpty()) {
                Node curr = queue.remove();
                System.out.println(curr.e);
                
                if(curr.left != null) {
                    queue.add(curr.left);
                }
                if(curr.right != null) {
                    queue.add(curr.right);
                }
            }
        }
        
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 如需转载, 请咨询作者, 并且注明出处.有任何问题, 可以关注我的微博: coderwhy, 或者添加我的微信: ...
    coderwhy阅读 8,664评论 12 35
  • 1.HashMap是一个数组+链表/红黑树的结构,数组的下标在HashMap中称为Bucket值,每个数组项对应的...
    谁在烽烟彼岸阅读 994评论 2 2
  • 构造一棵二叉排序树的目的,其实并不是为了排序,而是为了提高查找的效率。 那么什么是二叉排序树呢?二叉排序树具有以下...
    lintong阅读 539评论 0 1
  • 今天是2019年4月9日,星期二,天气中雨。今天的天气特别冷,外面早上起来一直下着雨,上学的点到了,我开...
    杨张清淙阅读 181评论 0 1
  • 生活,活见鬼 生活是一团扯不清的麻团,以为要解开了,实则越扯越乱,越扯越紧。 她目前的状态便是如此,肚里的宝宝7个...
    峮子说阅读 1,192评论 0 3