赤黒木など、すでにソートされている木のような構造に単一の項目を挿入するには、O(log n ) が必要です。すべてのノードの子孫の数を維持する場合、中央値を見つけることも O(log n ) で行うことができます。ストリームのすべてのn要素に対してこれを行うと、O( n log n ) アルゴリズムが得られます。
データ構造と中央値の計算は次のようになります。
struct TreeNode {
enum { RED, BLACK } color;
size_t numElements;
int value;
TreeNode* left, right;
} *root;
TreeNode* treeSelect(TreeNode *top, size_t count) {
if (top->left != NULL) {
if (count < top->left->numElements)
return treeSelect(top->left, count)
count -= top->left->numElements;
}
if (count == 0)
return top;
return treeSelect(top->right, count - 1);
}
TreeNode* treeMedian() {
return treeSelect(root, root->numElements / 2);
}
他の操作は通常、赤黒木に使用される操作ですが、ノードの削除にはスキップできます。重複する要素で機能するように調整できます。ここでの原則は、挿入する要素が現在のノードの要素と等しい場合、どの子ツリーにも挿入できるということです。また、ツリーのバランスをとるときは、重複キーの順序を維持する必要があります。これにより、接続されたサブツリーの順序も維持できます。しかし、私が何かを見逃していない限り、いずれの場合でも値の比較なしでバランスを取ることができるので、重複を挿入したら完了です。非常に多くの重複値が予想される場合は、各ノードにカウンターを使用して、代わりにマルチマップのようなアプローチを使用できます。