回転の実装

 ここではAVL木のように完全なバランスを目指すのはさておき、単純に回転してみましょう。右回転をPHPで書いてみます(図3-1)。

 いかがでしょうか?図2-8で示したことを素直に実行しています。最終的なrootに元の左側のノードが来ることがわかると思います。同様に左回転も作れますがここでは省きます。

 さて部分的な理屈ばかり書いてきましたので、全体的かつ実践的なことをしましょう。前回、リスト構造にデータを追加して、後でそこから探索をしました。ここでも同様に、次のことをします。

(1)木構造に要素を追加する
(2)その構造から要素を探す

 はじめに、要素を追加するプログラムを作りますが、追加した結果を目に見えるようにしないとわかりません。それをprintNode()としましょう。図3-2のようになるでしょう。ノードのレベルを表すためにスペースを印字している点にだけ注意していただければ、再帰呼び出しをしているだけです。

挿入と探索

 これで木を印刷することができるようになりましたので、アプリケーションを作りましょう。リンクトリストのときと同様に、はじめにデータを登録して、後でそれを探索します。

 リンクトリストのときのサンプルプログラムとほとんど同じですが、図3-3のようなテスト用プログラムを作りました。$rootの代わりに$anchorすればリンクトリスト版と同じです。木構造を操作する関数(insert() など)は、別のモジュールbtree.phpで定義されています。

 これを実行すると図3-4のようになります。首を左に傾けて見ると、木に見えませんか?この結果を印刷して「枝」を手で書き込んだものを図3-5に示します。この結果を見た限りでは、そこそこバランスのとれた木になっていますね。たまたまですがmodula-2を根とする木になりました。

 ここで「たまたま」と言ったのにはわけがあります。

 二分探索木へ要素を追加(挿入)する場合、挿入するものの順番によっては結果が異なります。要素がソートされているという条件は保証されますが、AVL木を構成しない限り、データの発生順序によってはバランスの崩れ方が変わるためです。

 試しに、データを挿入する前にシャッフルしてから同じことをしてみます(元の「順序」の意味がメチャメチャになりますが...)。上のテストプログラム(図3-3)のforループの前にshuffle($langs)を入れるだけです。結果は図3-6の通りです。今度はlispが根になりました。このプログラムのソースコードはこちら(http://www.thinkit.co.jp/images/article/159/2/15921.zip)からダウンロードできます(15921.zip/3 KB)。みなさんも試してみてください。実行するたびに表示が変わるはずです。shuffleのためにどの順序で木への挿入が起こるかわからないためです。

 では、最後にこの木の探索をしましょう。

 根から探し始めますが、キーの値を比較して小さければ左の枝へ、大きければ右へ進みます。それをプログラムにすると図3-7のようになります。プログラム自体はとても単純ですね。キーが一致するまで探します(見つからないこともありますが)。

 さて、もうお気づきかもしれませんが、木がバランスよくなっていれば、この探索は二分探索と同様の性能が出ます。木が偏っていると、一方の側をひたすら探すことになりますので、最悪の場合はリンクトリストをたどるのと同じように線形探索の性能しか出ません。

 つまり、二分探索木はその名の通り、二分探索とほぼ同等の性能ができることがわかります。動的に増減するデータを扱いの基本的な構造と言えます。データベースの索引部などには、二分木ではありませんがバランス木が使われます。アプリケーションで直接このような構造をプログラミングすることはあまりないと思いますが、基本ソフトウエアのさまざまな場面で使われていることを少しばかり、知っていただけると幸いです。

 前回と今回で、動的に増減するデータに対する線形探索と二分探索を取り上げました。オーダーはそれぞれO(n^2)とO(log2(n))です。次回は、O(1)であるアルゴリズムを取り上げましょう。O(1)であるということは、データ量にかかわらず一定の時間で目的のものが見つかるというものです。そんな夢のような方法があるのでしょうか?それは次回のお楽しみ。

 なお、本稿の執筆にあたって、以下を参考にしました。

Niklaus Wirth『Algorithms + Data Structures = Programs』Prentice-Hall,(発行年:1976)

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30