【问题标题】:Augment java collection to get Interval Tree增加 java 集合以获取区间树
【发布时间】:2013-09-20 17:23:12
【问题描述】:

我正在阅读Introduction to Algorithms by Cormen 第 14 章(增强数据结构),其中他在谈论区间树。下面是他提到的区间树背后的设计方法。

第 1 步:底层数据结构

我们选择一棵红黑树,其中每个节点x包含一个区间x:intx的key是low区间的端点 x.int.low。因此,数据结构的中序树遍历按低端点排序的顺序列出了区间。

这可以通过声明一个具有 minmax 的节点来完成。 comparableTo 函数应该只比较 x.int.low

第 2 步:附加信息

除了区间本身,每个节点x还包含一个值x.max,它是存储在根子树中的任何区间端点的最大值在 x

第 3 步:维护信息

我们必须验证插入和删除在 n 个节点的区间树上花费 O(lg n) 时间。我们可以确定 x.max 给定区间 x.int 和节点 x 的子节点的 max 值:

x:max = max(x.int.high; x.left.max; x.right.max)

第 4 步:开发新业务

我们唯一需要的新操作是INTERVAL-SEARCH(T,i),它在树T中找到一个区间重叠的节点间隔i。如果树中没有与 i 重叠的区间,则该过程返回一个指向标记 T:nil 的指针。

我可以通过 AVL 树 来实现这一点,但出于好奇想知道我们是否可以扩充 Java 中的现有库,例如 TreeSet 或其他 collection 实体 em> 以适应上述设计。如果是这样,您能否提供示例代码或示例?

【问题讨论】:

  • 特别是,我认为你不能这样做的原因是你不能挂钩树旋转事件来更新 max 值。
  • @ErikP。谢谢。我自己实现了,下面我放了。如果您有任何评论,请发表评论。
  • 一个基于 AVL 的 Java 实现已得到维护,也可在此处获得 github.com/Breinify/brein-time-utilities/#intervaltree

标签: java algorithm data-structures tree interval-tree


【解决方案1】:

我使用AVL tree 实现的区间树。

public class IntervalTreeAVL<T>{
    private static class TreeNode<T>{
        private T low;
        private T high;
        private TreeNode<T> left;
        private TreeNode<T> right;
        private T max;
        private int height;
        private TreeNode(T l, T h){
            this.low=l;
            this.high=h;
            this.max=high;
            this.height=1;
        }
    }
    private TreeNode<T> root;
    public void insert(T l, T h){
        root=insert(root, l, h);
    }
    private TreeNode<T> insert(TreeNode<T> node, T l, T h){
        if(node==null){
            return new TreeNode<T>(l, h);
        }
        else{
            int k=((Comparable)node.low).compareTo(l);
            if(k>0){
                node.left=insert(node.left, l, h);
            }
            else{
                node.right=insert(node.right, l, h);
            }
            node.height=Math.max(height(node.left), height(node.right))+1;
            node.max=findMax(node);
            int hd = heightDiff(node);
            if(hd<-1){
                int kk=heightDiff(node.right);
                if(kk>0){
                    node.right=rightRotate(node.right);
                    return leftRotate(node);
                }
                else{
                    return leftRotate(node);
                }
            }
            else if(hd>1){
                if(heightDiff(node.left)<0){
                    node.left = leftRotate(node.left);
                    return rightRotate(node);
                }
                else{
                    return rightRotate(node);
                } 
            }
            else;
        }
        return node;
    }
    private TreeNode<T> leftRotate(TreeNode<T> n){
        TreeNode<T> r =  n.right;
        n.right = r.left;
        r.left=n;
        n.height=Math.max(height(n.left), height(n.right))+1;
        r.height=Math.max(height(r.left), height(r.right))+1;
        n.max=findMax(n);
        r.max=findMax(r);
        return r;
    }
    private TreeNode<T> rightRotate(TreeNode<T> n){
        TreeNode<T> r =  n.left;
        n.left = r.right;
        r.right=n;
        n.height=Math.max(height(n.left), height(n.right))+1;
        r.height=Math.max(height(r.left), height(r.right))+1;
        n.max=findMax(n);
        r.max=findMax(r);
        return r;
    }
    private int heightDiff(TreeNode<T> a){
        if(a==null){
            return 0;
        }
        return height(a.left)-height(a.right);
    }
    private int height(TreeNode<T> a){
        if(a==null){
            return 0;
        }
        return a.height;
    }
    private T findMax(TreeNode<T> n){
        if(n.left==null && n.right==null){
            return n.max;
        }
        if(n.left==null){
            if(((Comparable)n.right.max).compareTo(n.max)>0){
                return n.right.max;
            }
            else{
                return n.max;
            }
        }
        if(n.right==null){
           if(((Comparable)n.left.max).compareTo(n.max)>0){
                return n.left.max;
            }
            else{
                return n.max;
            } 
        }
        Comparable c1 = (Comparable)n.left.max;
        Comparable c2 = (Comparable)n.right.max;
        Comparable c3 = (Comparable)n.max;
        T max=null;
        if(c1.compareTo(c2)<0){
            max=n.right.max;
        }
        else{
            max=n.left.max;
        }
        if(c3.compareTo((Comparable)max)>0){
            max=n.max;
        }
        return max;
    }


TreeNode intervalSearch(T t1){
        TreeNode<T> t = root;
        while(t!=null && !isInside(t, t1)){
            if(t.left!=null){
                    if(((Comparable)t.left.max).compareTo(t1)>0){
                    t=t.left;
                }
                else{
                    t=t.right;
                }
            }
            else{
                t=t.right;
            }
        }
        return t;
    }
    private boolean isInside(TreeNode<T> node, T t){
        Comparable cLow=(Comparable)node.low;
        Comparable cHigh=(Comparable)node.high;
        int i = cLow.compareTo(t);
        int j = cHigh.compareTo(t);
        if(i<=0 && j>=0){
            return true;
        }
        return false;
    }
}

【讨论】:

  • 嗨。一个有趣的实现。你能提供一个简单的测试用例吗?或者,如果您更喜欢 junit 测试?谢谢。
  • 对于未来的读者:如果我没记错的话,findMax 中的所有 n,max 都应该替换为 n.high。否则旋转时可能会得到错误的最大值(当当前最大值的源旋转到 n 以上时)
  • 如何获得与给定区间相交的所有区间?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
相关资源
最近更新 更多