在线性时间内从排序数组中构建红黑树

时间:2016-01-24 00:33:50

标签: algorithm data-structures tree big-o red-black-tree

我知道如何使用n次插入(每次都有O(log(n))效率)来构建它 (n * log(n))整体而言 ,我也知道2-3-4树的等效结构也可以用排序数组的线性时间构建。 任何人都可以提供有关红黑版本的简单说明吗?

4 个答案:

答案 0 :(得分:6)

无论你打算建造什么样的BST。算法将是相同的。只需要构建平衡的二叉树。

  1. 将中间元素放置到当前位置
  2. 放置[开始;中间)元素到左子树。
  3. 将(中间;结束)元素放置到右子树。
  4. 这是O(N)算法。可以看出,结果树将是平衡的。

    我们有平衡的树,所以根据定义:

    长度(最长路径) - 长度(最短路径)< = 1

    所以你需要将所有节点标记为黑色,除了树中最深的节点(将它们标记为红色)。

答案 1 :(得分:2)

高度 H 的完整二叉树具有 2 ^ H-1 节点。

从排序列表中制作红黑树:

  1. 从列表中删除每个第二项,直到您为某些 H 剩余 2 ^ H-1 项目。请注意,你总是有足够的。
  2. 从其余项目中构建一个完整的树,全部为黑色。
  3. 现在将您删除的所有项目附加到树中。每个项目都是一个红色节点,附在其正确位置周围的任何黑色节点上都是叶子。
  4. 执行步骤(3)的最简单方法就是对树进行预先遍历,将新的红色节点附加到每个黑叶上,直到用完项目为止。

    注意:Sasha的算法也有效,但这个显然有效。

答案 2 :(得分:0)

从功能数据结构的角度来看:有System#arraycopy()的论文,它发现了连续插入的模式,并将其与1-2数字系统相关联。

这是一个有趣的阅读。

答案 3 :(得分:0)

对于用 Java 实现的工作示例,您可能需要查看 buildFromSorted(int level, int lo, int hi, int redLevel, ...) 中的方法 Java.util.TreeMap

特别是关于 Java 的另一条评论:不幸的是,如果您有自己的以排序方式构建的数据(例如排序的 ArrayLists),则以线性方式将其放入 TreeMap 并不容易。然而,一种可能性是创建您自己的 SortedMapNavigableMap 实现,它由内部的 ArrayList 支持。那么就可以使用这个构造函数来高效地构造TreeMap:

    MySortedMap myMap = new MySortedMap(keyArray, valueArray);
    new TreeMap<K, V> (myMap)

以下是一些示例代码:

    public class MySortedMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V> {

        private ArrayList<K> keyArray;
        private ArrayList<V> valueArray;

        public Set<Map.Entry<K,V>> entrySet() {
            return new EntrySet();
        }

        class EntryIterator implements Iterator<Map.Entry<K,V>> {

            int i;

            public EntryIterator () {
                i = 0;
            }


            @Override
            public boolean hasNext() {
                if (i < keyArray.size()) {
                    return true;
                } else {
                    return false;
                }
            }

            @Override
            public Map.Entry<K,V> next() {
                if (hasNext()) {
                    Map.Entry<K,V> en = new Entry<K,V> (keyArray.get(i), valueArray.get(i));
                    i++;
                    return en;
                } else {
                    return null;
                }
            }
        }

        final class Entry<K,V> implements Map.Entry<K,V> {
            K key;
            V value;

            @Override
            public K getKey() {
                return key;
            }

            @Override
            public V getValue() {
                return value;
            }

            @Override
            public V setValue(V value) {
                this.value = value;
                return value;
            }

            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
            }
        }

        class EntrySet extends AbstractSet<Map.Entry<K,V>> {
            public Iterator<Map.Entry<K,V>> iterator() {
                return new EntryIterator();
            }

            public int size() {
                return keyArray.size();
            }

            
        }

        public MySortedMap (ArrayList<K> keyArray, ArrayList<V> valueArray) {
            if (keyArray.size() != valueArray.size()) {
                throw new RuntimeException("Key and value arrays must have the same length!");
            }

            this.keyArray = keyArray;
            this.valueArray = valueArray;
        }

        ... some unused methods ...
    }