- C++ による Apter Trees
- ノード値と親インデックスの 2 つのベクタだけを使ってシンプルに表現したツリー
- ほとんどのツリーは二分木のように実装され、各ノードが自分の値と左/右の子ノードへのポインタを含む
- このようなデータ構造は再帰で実装する必要があり、キャッシュ挙動や頻繁な
malloc() のために遅くなることがある
- どのツリーノードを誰が「所有」するのかという概念は、マルチレイヤーのソフトウェアでは複雑になりうる
- Apter ツリーははるかに高速で、推論しやすく、実装もしやすい
仕組み
- 同じサイズの 2 つの配列で実装する
- データのベクタ(配列)
d
- 親インデックスのベクタ
p。d ベクタのインデックスがキーとして使われる (c)
- 多くの場合、キー/インデックス
c は整数型
- Coco が Molly と Arca の親で、Arca に Cricket という子がいるなら、構造は次のようになる
tree.d = ["Coco", "Molly", "Arca","Cricket"]
tree.p = [0,0,0,2]
- 親が 0 で、かつキーが 0 のノードがルートノード(Apter ツリーではルートノードが必須、または -1 が「親なし」を意味するが、ここでは無視する)
- コンピュータはベクタを非常に高速に操作できる。ポインタ演算よりはるかに速いため、アルゴリズムのビッグ O 記法を比較しても実際にはあまり意味がない
重要性
- この実装方式は、これまで見たツリー実装の中で最もエレガント
- 適切なベクタ演算ライブラリを使えば理解しやすく、バグも見つけやすい
- シンプルなので、ほかの利用シナリオにも簡単に適用できる
- 親インデックスベクタを無視して値を高速に反復でき、これは追加コストなしで使える Deep Map のようなもの
- GPU フレンドリーで、組み込み環境でも使いやすい
- ベクタのサイズが一定以上に増えないようにすることで、セキュリティを維持しやすい
起源
- この技術の発明者を探しているところで、60 年代から 70 年代のベクタ指向の時代にはすでに名前があったのではないかと推測している
- Apter が説明した形で初めて完全な説明を見たが、K3 でも広く文書化されていた
- APL は伝統的な方法でツリーを実装するが、ベクタグラフについては似た技術を使っている
- J ユーザーにも知られており、Rosetta Code には J 言語によるツリー実装の説明がある
- John Earnest はベクタツリー実装についてさらに詳しく説明しており、「オフセットインデックス」方式を含めて削除項目について解説している
- より複雑なアプローチとして、各項目の深さを追跡する方法もある
その他の一般的なツリー実装
- FreeBSD のカーネルツリー実装、klib のツリー、Ruby のツリークラス、Python の宣言的ツリークラスなどがある
- これらは Apter ツリーとまったく同じ機能を提供するわけではなく、一部は汎用化のためにはるかに大きい
このコードの現状
- C++17 を学ぶために、これを実装してみる試み
- まだ実運用の準備はできておらず、C++ についてさらに学ぶ必要がある
GN⁺の見解
- Apter Trees は既存の複雑なツリー構造を単純化し、高速で効率的なデータ管理を可能にする
- ベクタベースのツリー実装はメモリオーバーヘッドを最小限に抑え、線形アクセスによって性能を向上させられる
- この記事は、ソフトウェアエンジニアリングにおけるデータ構造への革新的なアプローチを探るうえで興味深い内容
1件のコメント
Hacker Newsの意見