有序表


 

 

有序表只是一個接口,實現有很多,如:AVL,SB,RedBlackTree ,skipTable

AVL,SB,RedBlackTree是基於搜索二叉樹設計出來的,增刪改查是O(logn)

無重復節點,改成有重復節點可以這么設計:K,List<V>

二叉搜索樹的增刪改查:

查:val 大->root.right,val小->root.left,== return

增:查,查到空掛上

改:查到改值

刪:分下面幾種情況

前提是先查,查到后判段這個節點的情況

1、無左無右,直刪

2、有左無右(讓左該子去替它的環境)或有右無左,

 

 

 3、有左有右

可以有兩種方法:1:讓左孩子的最右節點去替,2:讓右孩子的最左節點去替

         

 

 

 

各個有序表的實現增刪改查都一樣,只是調整平衡不一樣

  二叉搜索樹的增刪改:

public class AbstractBinarySearchTree {
    public static class Node{
        public Integer value;
        public Node parent;
        public Node left;
        public Node right;
        public Node(Integer value,Node parent,Node left,Node right){
            this.value=value;
            this.parent=parent;
            this.left=left;
            this.right=right;
        }
        public boolean isLeaf(){
            return left==null && right==null;
        }
    }

    Node root;
    int size;

    public Node search(int element){
        Node node=root;
        while(node!=null && node.value!=null && node.value!=element){
            if(element> node.value){
                node=node.right;
            }else {
                node=node.left;
            }
        }
        return node;
    }

    public void update(int element){
        Node node=search(element);
        if(node==null){
            return;
        }
        node.value=element;
    }

    protected Node createNode(int element,Node parent,Node left,Node right){
        return new Node(element,parent,left,right);
    }

    public Node insert(int element){
        if(root==null){
            root=createNode(element,null,null,null);
            size++;
            return root;
        }
        //search
        Node insertParentNode=null;
        Node searchTemNode=root;
        while(searchTemNode!=null && searchTemNode.value!=null){
            insertParentNode=searchTemNode;//最后一個不空的節點就是待加節點的父
            if(element> searchTemNode.value){
                searchTemNode=searchTemNode.right;
            }else{
                searchTemNode=searchTemNode.left;
            }
        }
        Node newNode=createNode(element,insertParentNode,null,null);
        if(insertParentNode.value>newNode.value){
            insertParentNode.left=newNode;
        }else{
            insertParentNode.right=newNode;
        }
        size++;
        return newNode;

    }
    public Node delete(int element){
        Node deleteNode=search(element);
        if(deleteNode==null){
            return null;
        }
        return delete(deleteNode);
    }

    protected Node delete(Node deleteNode){
        if(deleteNode==null){
            return null;
        }
        Node nodeToReturn=null;
        if(deleteNode.left==null){//綜合了無左無右和有右無左的情況
            //transplant(a,b) b去替a的環境,a斷聯,把b返回
            nodeToReturn=transplant(deleteNode,deleteNode.right);
        }else if(deleteNode.right==null){//綜合了無左無右和有左無右的情況
            nodeToReturn=transplant(deleteNode,deleteNode.left);
        }else{
            //找到右孩子的最左節點
            Node successorNode=getMinimun(deleteNode.right);
            if(successorNode.parent!=deleteNode){
                transplant(successorNode,successorNode.right);
                successorNode.right=deleteNode.right;
                successorNode.right.parent=successorNode;
            }
            transplant(deleteNode,successorNode);
            successorNode.left=deleteNode.left;
            successorNode.left.parent=successorNode;
            nodeToReturn=successorNode;

        }
        size--;
        return nodeToReturn;


    }
}

  

擴展,可以改出很多API,TeeMap 中沒有如下API,但可以通過SB樹改

1:找到<=num離它最近的,>=num離它最近的,二分后大於往右,小於往左,

標記最后一個比它小的,和最后一個比它大的

 

2:找最小的第100個key是什么

 

 

 

二叉搜索樹通過增刪改后,搜索的效率有可能會退化成O(n)

AVL,SB,RBT都是在維持平衡性

AVL樹左右子樹高度差不超過1

如何維持平衡性?左旋,右旋

 

 

調整策略:4種違規

LL型:左邊的左孩子過多->右旋

 

RR型:右邊的右孩子過多->左旋

LR型:左邊的右孩子過多->針對X想讓它成於頭,對Y先左旋,再整顆樹右旋

 

RL型:右邊的左孩子過多->先右旋,再左旋

 private void avlRebalance(Node node,Node parent){
        int lH=node.left==null?-1:node.left.height;
        int rH=node.right==null?-1:node.right.height;
        int nodeBalance=rH-lH;
        if(nodeBalance==2){
            if(node.right.right!=null){
                node=avlRotaleft(node);
                break;
            }else{
                node=doubleRotateRightLeft(node);
                break;
            }
        }else if(nodeBalance==-2){
            if(node.left.left!=null){
                node=avlRotateRight(node);
                break;
            }else{
                node=doubleRotateLeftRight(node);
                break;
            }
        }else{
            updateHeight(node);
        }
    }

  

SB樹:API好改

AVL樹維持了一個高度信息,高度差不能超過1,

而SB樹是要求叔叔節點數不能小於任何侄子的節點數,如此規定后,左樹子樹的節點數不會超過2倍多

 調整策略和AVL樹一樣,4種違規

1、LL型:對X來說,是R違規了,a的節點數比R多

2、LR型:對X來說,是R違規了,b的節點數比R多

3、RR型:對X來說,是L違規了,d的節點數比R多

4、RL型:對X來說,是L違規了,c的節點數比R多

為什么這4種只有一種違規,因為插入和刪除都是一個個插入和刪除的,插刪后都是從下往上查平衡,所以不會出現多種違規的情況

在這4種情況下如何調整?maintain

LL:X右旋,誰的子樹發生了變化,還要miantain一下

 

 

RR:X左旋,誰的子樹發生了變化,還要miantain一下

LR:先對L左旋,再對X右旋,再m(L),m(x),m(b)

 

 RL:同理

SB左右旋后,還有遞歸行為,但時間復雜度進了是O(logn)

在刪除節點時可以不調,在插入時統一調

平衡指標只能是size(不同的key的數量),每個節點收了多少個節點用times,  size,times是兩個不同的字段

不同的key, 一共的key

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM