zoukankan      html  css  js  c++  java
  • 二叉搜索树

    二叉搜索树的特点:

    二叉搜索树的左节点小于它的父节点,右节点大于父节点

    二叉搜索树中的结点:

     1     private static class Node<E>{
     2 
     3         private E element;
     4         private Node<E> parent;
     5         private Node<E> left;
     6         private Node<E> right;
     7 
     8         public Node(E element, Node<E> parent){
     9             this.element = element;
    10             this.parent = parent;
    11         }
    12 
    13     }

    二叉搜索树的添加方法:

     public void add(E element){
            if(size == 0){
                root = new Node<E>(element,null);//创建一个头节点
            }
    
            Node<E> parent = root;
            Node<E> node = root;
            int cmp = 0;
    
            while(node != null){
                cmp = compare(element,node.element);//比较两个节点的大小
                parent = node;
                if(cmp > 0){
                    node = node.right;
                }else if(cmp < 0){
                    node = node.left;
                }else{
                    return;
                }
            }
    
            if(cmp > 0 ){
                parent.right = new Node<E>(element,parent);
            }else if(cmp < 0 ){
                parent.left = new Node<E>(element,parent);
            }else{
                parent.element = element;
            }
            
            size++;
        }

    二叉搜索树中的元素的比较

    1.插入的元素中实现Comparable接口,重写compare方法.

    2.如果插入的元素不想实现接口,

     

     在创建二叉搜索树的时候new 一个Comparator的匿名内部类,重写compare方法.

    二叉树的遍历(所有二叉树)

    前序遍历:

    先访问该节点,在访问该节点的左子树,然后访问该节点的右子树.

    public void preOrderTree(){
        preOrderTree(root);
    }
    
    private void preOrderTree(Node<E> node){
        if(node == null) return;
    
         System.out.println(node.element);
         preOrderTree(node.left);
         preOrderTree(node.right);
    }    

    中序遍历:

    中序遍历根节点的左子树,访问根节点,中序遍历根节点的右子树

    public void inOrderTree(){
            inOrderTree(root);
        }
    
        private void inOrderTree(Node<E> node){
            if(node == null) return;
            inOrderTree(node.left);
            System.out.println(node.element);
            inOrderTree(node.right);
        }

    后序遍历

    后序遍历根节点的左子树,后序遍历根节点的右子树,访问根节点.

    public void  lastOrderTree(){
            inOrderTree(root);
        }
    
    private void lastOrderTree(Node<E> node){
        if(node == null) return;
        System.out.println(node.element);
        inOrderTree(node.left);
        inOrderTree(node.right);
     }

    层序遍历

    从根节点开始一层一层的访问节点

       public void levelOrderTree(Node<E> root){
            Queue<Node<E>> queue = (Queue<Node<E>>) new LinkedList<E>();
            queue.offer(root);
            while(!queue.isEmpty()){
                Node<E> node = queue.poll();
                System.out.println(node.element);
                if(node.left != null){
                    queue.offer(node.left);
                }
                if(node.right != null){
                    queue.offer(node.right);
                }
            }
        }

    利用队列先进先出的特点,每次弹出一个,就把他的左右节点添加进来.

    前驱结点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的前一个节点为该节点的前驱节点;

    后继节点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的后一个节点为该节点的后继节点;

    前驱结点的实现:

     public Node<E> predecessor(Node<E> node){
            if(node == null) return null;
         
          
          //如果该结点有左子节点,那么该节点的前驱结点就是左子节点的最后一个右子节点
    if(node.left != null){ node = node.left; while(node.right != null){ node = node.right; } return node; }      
        
         //如果该节点没有左子节点,那么分两种情况,如果这个节点在父节点的右边,那么这个父节点就是前驱结点
         //吐过这个节点在父节点的左边,那么就要找父节点的父节点,知道父节点在前一个父节点的右边.
    while(node.parent != null && node.parent.right != node){ node = node.parent; } return node.parent; }

    二叉搜索树的删除方法:

     public void remove(Node<E> node){
            if(node == null) return;
    
            //当删除的节点有两个子节点时
            if(node.left != null && node.right != null){
                Node<E> s = predecessor(node);//前序节点只可能有一个左子点或者没有子节点
                node.element = s.element;
                s = node; //把前序节点的值赋给要删除的节点,然后把node指向这个前序节点,那么就只需要删除前序节点就可.
            }
            
            //我觉得replacement只可能是node.left或者为null;不用加node.right
            Node<E> replacement = node.left != null ? node.left : node.right;
            
            if(replacement != null){
                replacement.parent = node.parent;//如果node有一个子节点的话,把node的父节点赋给子节点
                if(node.parent == null){
                    root = replacement;//如果node没有父节点的话,那么他就是根节点
                }else if(node.parent.left == node){
                    node.parent.left = replacement;
                }else if(node.parent.right == node){
                    node.parent.right = replacement;
                }
                //根据node节点在父节点的左边还是右边赋给node的子节点.这样,node就被删除了
            }else if(node.parent == null){
                root = null;
            }else{
                if(node == node.parent.left){
                    node.parent.left = null;
                }else if(node == node.parent.right){ //如果node没有子节点的话,那么就直接删除
                    node.parent.right = null;
                }
            }
    
    
        }
  • 相关阅读:
    NYOJ 625 笨蛋的难题(二)
    NYOJ 102 次方求模
    ZJU Least Common Multiple
    ZJUOJ 1073 Round and Round We Go
    NYOJ 709 异形卵
    HDU 1279 验证角谷猜想
    BNUOJ 1015 信息战(一)——加密程序
    HDU 1202 The calculation of GPA
    "蓝桥杯“基础练习:字母图形
    "蓝桥杯“基础练习:数列特征
  • 原文地址:https://www.cnblogs.com/lzh66/p/12944631.html
Copyright © 2011-2022 走看看