簡體   English   中英

AVL樹,Java,后繼者,前任者

[英]AVL tree, java, successor, predecessor

我需要在此實現中編寫后繼和前任,但是我不知道如何在沒有父級的情況下進行此操作。 這是我的TreeNode類

public class TreeNodee<K extends Comparable<K>> {
    public  K data;
    int counter;
    public  TreeNodee<K> left, right;
    public  int height;
    public int bf;
    TreeNodee parent;

    public TreeNodee(K data, TreeNodee parent) {
        this.data = data;
        counter = 1;
        this.parent = parent;
    }
    public TreeNodee(K data) {
        this.data = data;
        counter = 1;
    }
}

那棵AVL樹:

public class AVL<T extends Comparable<T>> {

        private TreeNodee<T> root;
        private int size;

        public void add(T data) {
            if (contains(data)){
                root.counter++;
                return;
            }


            TreeNodee<T> newNode = new TreeNodee<T>(data);

            root = add(root,newNode);
            size++;
        }


        public boolean contains(T data) {
            if (isEmpty())return false;
            return contains(root,data);
        }

        private boolean contains(TreeNodee<T> current, T n){
            if(current==null)return false;
            if(compare(current.data,n) == 0){
                return true;
            }
            else{
                if(contains(current.right,n)){return true;}
                else if(contains(current.left,n)){return true;}
                return false;
            }
        }


        private TreeNodee<T> add(TreeNodee<T> current, TreeNodee<T> n){
            if (current == null){
                n.bf = 0;

                n.height = 0;
                return n;
            }
            if (compare(n.data,current.data)>0){
                current.right = rotate(add(current.right,n));
            }
            else{
                current.left = rotate(add(current.left,n));
            }
            current = rotate(current);
            return current;
        }


        public T remove(T data) {
            if(!contains(data)){
                return null;
            }
            root = rotate(remove(root,data));
            size--;
            return data;
        }
        private TreeNodee<T> remove(TreeNodee<T> current, T n){

            if (compare(current.data,n)==0){
                if(current.right == null && current.left== null){
                    return null;
                }
                else if(current.right == null){
                    return rotate(current.left);
                }
                else if(current.left == null){
                    return rotate(current.right);
                }
                else{
                    TreeNodee<T> pre = current.left;
                    TreeNodee<T> predecessor;
                    if (pre.right==null){
                        predecessor = pre;
                        predecessor.right = current.right;
                    }
                    else{
                        while(pre.right.right!=null){
                            pre = pre.right;
                        }
                        predecessor = pre.right;
                        pre.right = predecessor.left;
                        predecessor.left = current.left;
                        predecessor.right = current.right;
                    }
                    return predecessor;
                }
            }
            else{
                if (compare(n,current.data)>0){
                    current.right = rotate(remove(current.right,n));
                }
                else{
                    current.left = rotate(remove(current.left,n));
                }
                return rotate(current);
            }
        }



        private TreeNodee<T> updateHeightAndBF(TreeNodee<T> n) {

            int left,right;
            left = n.left!=null ? n.left.height : -1;
            right = n.right!=null ? n.right.height : -1;
            n.bf = left-right;
            n.height = (right>left ? right : left) +1;
            return n;
        }


        private TreeNodee<T> rotate(TreeNodee<T> n) {
            if(n == null)return n;
            n = updateHeightAndBF(n);
            if(n.bf<-1){
                if(n.right.bf>0){
                    n = rightLeft(n);
                }
                else{
                    n = left(n);
                }
            }
            else if(n.bf>1){
                if(n.left.bf<0){
                    n = leftRight(n);
                }
                else{
                    n = right(n);
                }
            }
            return n;
        }


        private TreeNodee<T> left(TreeNodee<T> n) {
            TreeNodee<T> newRoot = n.right;
            TreeNodee<T> temp = n.right.left;
            n.right.left = n;
            n.right = temp;
            n = updateHeightAndBF(n);
            return newRoot;
        }


        private TreeNodee<T> right(TreeNodee<T> n) {
            TreeNodee<T> newRoot = n.left;
            TreeNodee<T> temp = n.left.right;
            n.left.right = n;
            n.left = temp;
            n = updateHeightAndBF(n);
            return newRoot;
        }


        private TreeNodee<T> leftRight(TreeNodee<T> n) {
            n.left = left(n.left);
            n = right(n);
            return n;
        }


        private TreeNodee<T> rightLeft(TreeNodee<T> n) {
            n.right = right(n.right);
            n = left(n);
            return n;
        }


        public boolean isEmpty() {
            if (size==0) return true;
            return false;
        }


        private int compare(T d1,T d2){
            if (d1==null && d2 == null){
                return 0;
            }
            else if(d1==null){
                return 1;
            }
            else if(d2==null){
                return -1;
            }
            else{
                return d1.compareTo(d2);
            }
        }
    }

不需要父鏈接。 您只需要沿着樹走下去,直到找到一片葉子。 問題是“哪個葉子包含此值的后繼/前任?”

考慮到您在樹中找到了該節點,我將直接使用該節點。 另外,我將認為左子項比當前節點小,而右子項比當前節點高。

現在,您已經有了節點,並且想找到它的前身。 前任意味着您希望最大的節點更小。 我們將仔細研究這些案例。

情況1:我沒有孩子

想象一下,您的樹是這棵樹,並且您想要3的前身。容易,這是他的父母:2.您可以從樹的根開始遞歸地實現它。 您只需要跟蹤自己在前進過程中遇到的最好的前任。

  2
 / \
1   3

執行如下所示:

I'm at node 2, looking for the predecessor of 3 -> go right
    I'm at node 3, looking for a predecessor of 3 -> go left
        There's nothing, I didn't find any predecessor -> recursion rewinds
    Crap, there is no predecessor found and 3 is not a predecessor of 3 -> recursion rewinds
Still no predecessor, but 2 is a predecessor of 3 -> recursion rewinds sending 2
Recursion ends: 2 is your value.

現在,如果要查找其前任節點的節點沒有左子樹並且是其父節點的左子節點->在遞歸過程中尋找其祖父母,直到找到一個較小的節點。

如果沒有更小的節點怎么辦? 這樣,該節點實際上是樹的最小節點,並且他沒有前任。

案例2:我有孩子

希望那是艱難的情況。 現在,我們正在查看的節點具有左子樹。 容易:前任隱藏在左子樹中的某個位置。 很好的是,它是其中最大的節點(根據定義)。

因此,您的前任是左側子樹中最大的節點,這很容易找到->向右走直到碰到葉子。

那后繼者呢? 相同,但相反。 節點的后繼者是其右子樹的最左側葉。 同樣,邊緣情況是相同的,您有可能在尋找樹中不存在的最大節點的后繼節點。

實施提示

為了實現這種操作,更容易完全放棄您正在AVL樹上工作的事實,只需要考慮如何在標准二叉樹中進行操作即可。

如果沒有父指針,則可以迭代:從根開始,並始終在那些操作中考慮父,當前子對象,左子對象和右子對象。 實際上,這種方法通常更為復雜,因為您有很多節點需要同時跟蹤。 另外,您還必須更新在每次迭代中找到的值,因為沒有指針就不會增加。

因為結構本身是遞歸的,所以我們傾向於在二叉樹上遞歸地工作 您可以通過始終傳遞遞歸來讓父遞歸,但是沒有強制要求(這里沒有必要)。 您只需要記住,您是剛剛向您返回值的節點的父節點,並采取相應的措施。

它需要一些練習,但是一旦掌握了它,它就會非常直觀。

我需要在此實現中編寫后繼者和前任者,但是如果沒有parent ,我不知道該怎么做。

嗯...什么?

public class TreeNodee<K extends Comparable<K>> {
    public  K data;
    int counter;
    public  TreeNodee<K> left, right;
    public  int height;
    public int bf;
    // ------------------------------------
    // Why, this parent is not good enough?
    //           |
    //           V
    TreeNodee parent;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM