私たちはより良いことができますか


7

この質問に対する答えは「いいえ」であると、私は(愚かにも判明しました)確信しています。なぜ私は尋ねるのですか?

それは、EPFLの並列プログラミングコースのAleksandar Prokopec博士が、さまざまな特性を主張するデータ構造を導入しているためです。これらの特性は保持している場合、そうです、私により良いでバランスの取れたバイナリツリーを構築することが可能でなければならないこと時間。Oログ

私はこれを信じていないので、私の考えのどこに欠陥があるのだろうと思います。

データ構造は、conc-treeリストです。標準形式では、通常のバイナリツリーのように見えconcat、ノードの左右のサブツリーの高さが2以上異なることがないことを保証する操作が付属しています。予想通りconcat、複雑さはです。Oログ

しかし、リストと呼ばれるコンクツリーリストのビルダーバリアントがありAppendます。このバリアントは、複数のサブツリーで一時的な高さの違いを可能にします。このバリアントでは、償却済み時間の追加が要求されます。O1

そのため、要素を追加すると複雑さが必要になるようです。O

ただし、このバリアントの特徴は、が2の累乗であるときは常に、完全にバランスのとれた二分木(これまでに挿入されたすべての要素を含む)になることです。したがって、一時的な不均衡は許容されますが、ツリーは2挿入のすべてのパワーで均衡になります。

このバリアントでは、ノードと呼ばれる新しいクラスのノードAppendが導入され、サブツリーの高さが1つ以上異なることが許可されているノードです。ただし、挿入ごとに、このような一時ノードはすべて削除されます。2k

Wikipediaのページのページは、(基本的なデータ構造の記述と見かなり簡潔なアルゴリズムを説明しappend、特定のメソッドを)。

したがって、が2の累乗の場合、要素を挿入するためのコストはあり、バランスのとれたバイナリツリーを構築しました。またはそうです。O

別の質問私は、特定の値のためのアルゴリズムのためのステップ数を述べることができる場合、私は効果的に」尋ねのために例えば、、整数である、私は複雑さを述べるできるようにするには、この十分ですすべての値?」=2kk

Yuval Filmusの答えから、答えは「いいえ」であることがわかりますが、「多くの場合、はで単調であると予想されます。その場合、控除は成立します。」T

したがって、この場合、要素の挿入に複雑さあり、要素ごとに平衡バイナリツリーがある場合、このコンクツリーバリアントアプローチで平衡バイナリツリーを構築するコストは。O2kO

ここで何が問題になっていますか?正直に言うと、このバリアントに対して要求された償却済み追加時間がわかりません。多くの場合、挿入にはコストがかかりますが、一時ノードで何が起こっているかを見ると、全体的な挿入コストは償却されたように見え。O1O1AppendOログ

これが当てはまる場合、バランスの取れたバイナリツリーを構築すると、驚くほどのコストがかかります。Oログ

長い質問で申し訳ありませんが、問題のアルゴリズムについて詳しく説明していません。代わりに、ウィキペディアを見回してください。


2
質問への新しい質問の追加を停止してください。元の質問に回答した場合は、元の質問に直接関係のない質問や混乱がある場合は、別の質問を開始します。現在の状態の質問は、タイトルから完全に分岐しています。
aelguindy

1
ここでは、Q&Aスタイルに固執するのではなく、進行中のディスカッションのスタイルで追加してください。私はこの質問に回答済みのマークを付け、別の質問として、私の償却が失敗したことを定式化しようO1append操作の私の現在の分析で。
George Hawkins、

この質問の大幅に拡張されたバージョンは編集履歴に委託されています。@ gnasher729からの回答に大いに感謝していますが、質問がバイナリ検索ツリーではなくバイナリツリーに関するものであるため、投票数が非常に多いことに少し驚いています。どちらか一方の複雑さを混同しても、それは変わりません。同様に、質問はバイナリツリーから正しくないように見える検索ツリーに再タグ付けされました。
ジョージホーキンス

回答:


7

私があなたの質問を正しく理解していれば、もちろんはい、あなたはバランスのとれた二分木を O時間。ここに簡単な疑似コードがあります:

L = [2, 4, 1, 3, 5, 6, 8]
q = Queue()
node root{value = L[0]}
q.add(root)
k = 1
while !q.isEmpty:
  n = q.pop
  if k < L.size:
     n.left = node{value=L[k]}
     k++
     q.add(n.left)
  if k < L.size:
     n.right = node{value=L[k]}
     k++
     q.add(n.right)

このコードが線形時間で実行され、バランスのとれたバイナリツリーが構築されることは、簡単に理解できます。

あなたができないことは、バランスのとれた二分探索(順序付け)ツリーをO時間(値の比較のみを使用)。上記のアルゴリズムは、ルートの値がすべてのサブツリーについて、左側のサブツリーのすべての値以上であり、右側のサブツリーのすべての値以下であることを保証しません。

上記のアルゴリズムはそれを保証せず、conc-treeも保証しません(アペンドとプリペンドを使用)。ウィキペディアのページから、それは保証するだけですO1アペンドプリペンドの償却時間。インサートの場合、保証できるのはOログ 時間。


20年前の半分記憶されていた講義に基づいて、ここで間違いであると確信していることを自信を持って主張するのは、何日かで2度目と言っても、あまりに愚かです。あなたの例では、葉だけに値があるが、それでもノード(葉と内部ノード)の数を増やすだけの、やや異なる種類のツリーをコンクツリーに構築します。21 複雑さはあなたの場合と同じです O。さて、conc-treeのappend操作について何か賢いことはあるかと思いました。もう長い質問の最後に別のセクションを追加しました。
ジョージホーキンス

@GeorgeHawkinsは心配ありません、それはよくある混乱です:)。私の例では、ノードを葉に配置するのではなく、ツリーのすべてのノードに値を配置します。コンクツリーについてはいくつかの非常に賢いことがあり、同じ境界を実現するデータ構造を考え出そうとすると、それが賢い理由がわかるはずです。たとえば、高速な追加が必要な場合、リンクリストを使用したくなるかもしれませんが、内部要素にすばやくアクセスするにはどうすればよいでしょうか。
aelguindy 2016年

ようやく私の質問に更新を追加しました。しかし、この段階では、コンクツリーデータ構造の賢さというあなたの意見に最も興味があると思います。ツリーにはリスト(特定の特性が必要な場合)にプラスがあることがわかりますが、他のツリーの実装に比べてコンクツリープラスにはそれほど明確ではありません。私の質問の最後に、これらの線に沿っていくつかの考えを追加しました。しかし、同じくらい重要なことには、私はまだ償却されたものを見ることができませんO1 追加時間:(の場合に何が起こっているかの私の分析 2k アペンドはまだ私を不正確な償却に導きます Oログ
ジョージホーキンス、

2
あなたの質問は本当に大きくなり、あなたの質問のタイトルから逸脱しています。いくつか個別に質問したいと思うかもしれません。
aelguindy 2016年

2
コンクツリーの賢さについて、追加と前置でバランスを保つツリーを実装してみてください O1時間を償却すると、コンクツリーが賢い理由がわかります。また、2つのバイナリツリーにconcatを実装する方法を考えてみてください。
aelguindy

6

aelguindyの答えに追加:並べ替えられていないn個のアイテムを任意の種類のデータ構造に入れてから、それらをO(n log n)の合計時間よりも並べ替えられた順序で列挙することはできません-可能であれば並べ替えることができるためO(n log n)時間より良い配列。

「ソートされた」データ構造を、O(n)時間でソートされた順序で列挙できるデータ構造として定義すると、O(n log n)よりも速くソートされたデータ構造を作成できません。これには、バランスとアンバランスの両方のソート済みツリーが含まれます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.