Java プログラミング スキル - データ構造とアルゴリズム「バランス バイナリ ツリー」

Java プログラミング スキル - データ構造とアルゴリズム「バランス バイナリ ツリー」

[[390860]]

バイナリソートツリーで起こりうる問題

シーケンス {1,2,3,4,5,6} が与えられた場合、バイナリソートツリー (BST) を作成し、問題を分析する必要があります。

問題分析:

  1. 左のサブツリーはすべて空で、形式的には単一のリンク リストのように見えます。
  2. 挿入速度は影響しません。
  3. クエリ速度が大幅に低下し (1 回の比較が必要になるため)、BST の利点を活かすことができません。左のサブツリーを毎回比較する必要があるため、クエリ速度は単一のリンクリストよりも遅くなります。
  4. ソリューション - バランスバイナリツリー (ALV)

基本的な紹介

  1. バランスのとれたバイナリ ツリーは、自己バランス バイナリ サーチ ツリー (AVL ツリーとも呼ばれます) とも呼ばれ、高いクエリ効率を保証できます。
  2. 空の木であるか、左右のサブツリー間の高さの差の絶対値が 1 を超えず、左右のサブツリーが両方ともバランスの取れた二分木であるという特徴があります。バランスのとれた二分木の一般的な実装方法には、赤黒木、AVL、スケープゴート木、Treap、ストレッチ木などがあります。
  3. たとえば、下の図の最初の 2 つはバランスの取れた二分木です。最初の二分木は左右のサブツリー間の高さの差の絶対値が 1、2 番目の二分木は左右のサブツリー間の高さの差の絶対値が 0、3 番目の二分木は左右のサブツリー間の高さの差の絶対値が 2 なので、バランスの取れた二分木ではありません。

バランスのとれた二分木の左回転

ステップ

  1. 現在のルート ノードの値と同じ値を持つ新しいノード newNode を作成します。
  2. 新しいノードの左サブツリーを現在のノードの左サブツリーに設定します。
  3. 新しいノードの右サブツリーを、現在のノードの右サブツリーの左サブツリーに設定します。
  4. 現在のノードの値を現在の右の子ノードの値に置き換えます。
  5. 現在のノードの右サブツリーを右サブツリーの右サブツリーに設定します。
  6. 現在のノードの左のサブツリーを新しいノードに設定します。

バランスのとれた二分木の右回転

ステップ:

  1. 現在のルート ノードの値と同じ値を持つ新しいノードを作成します。
  2. 新しいノードの右サブツリーを現在のノードの右サブツリーに設定します。
  3. 新しいノードの左サブツリーを、現在のノードの左サブツリーの右サブツリーに設定します。
  4. 現在のノードの値をその左の子の値と交換します。
  5. 現在のノードの左サブツリーを左サブツリーの左サブツリーに設定します。
  6. 現在のノードの右サブツリーを新しいノードに設定します。

バランスのとれた二分木の二重回転

場合によっては、1 回の回転ではバランスの取れたバイナリ ツリーの変換を完了できず、2 回の回転が必要になります。

  1. 右サブツリーの左サブツリーの高さが右サブツリーの右サブツリーの高さよりも大きい場合は、最初に右サブツリーを右に回転してから、現在のノードを左に回転する必要があります。
  2. 左サブツリーの右サブツリーの高さが左サブツリーの左サブツリーの高さより大きい場合、
  3. まず左のサブツリーを左に回転し、次に現在のノードを右に回転する必要があります。

コード例

  1. パッケージ com.xie.avl;
  2.  
  3. パブリッククラス AVLTreeDemo {
  4. 公共 静的void main(String[] args) {
  5. int [] arr = {4, 3, 6, 5, 7, 8};
  6. AVLTree avlTree = 新しい AVLTree();
  7. ( int i = 0; i < arr.length; i++) {
  8. avlTree.add (新しいノード(arr[i]));
  9. }
  10. System.out.println ( "順序通りの走査" );
  11. avlTree.infixOrder();
  12. System.out.println ( "バランス処理前~~" );
  13. System.out.println ( "ツリーの高さ = " + avlTree.getRoot().height());
  14. System.out.println ( "ツリーの左サブツリーの高さ = " + avlTree.getRoot().leftHeight());
  15. System.out.println ( "ツリーの右サブツリーの高さ = " + avlTree.getRoot().rightHeight());
  16. }
  17. }
  18.  
  19. クラス AVLTree {
  20. プライベートノードルート;
  21.  
  22. パブリックノードgetRoot() {
  23. ルートを返します
  24. }
  25.  
  26. パブリックvoid setRoot(ノード ルート) {
  27. ルート
  28. }
  29.  
  30. //削除するノードの親ノードを見つける
  31. パブリックノードsearchParent(ノードノード) {
  32. ルートがnull場合
  33. root.searchParent(ノード)を返します
  34. }それ以外{
  35. 戻る ヌル;
  36. }
  37. }
  38.  
  39. // 削除するノードを見つける
  40. パブリックノード検索( int値){
  41. ルートがnull場合
  42. 戻る ヌル;
  43. }それ以外{
  44. root.search(値)を返します
  45. }
  46. }
  47.  
  48. /**
  49. * ノードをルートとする二分ソート木の最小値を見つけ、ノードをルートノードとする二分ソート木の最小ノードを削除します。
  50. *
  51. * @param node 入力ノード(バイナリソートツリーのルートノードとして)
  52. * @returnルートノードとしてノードを持つバイナリソートツリーの最小ノード値を返します
  53. */
  54. 公共  int delRightTreeMin(ノードノード) {
  55. ノードターゲット = ノード;
  56. //左のノードを見つけるためにループする
  57. while ( target.left != null ) {
  58. ターゲット = target.left ;
  59. }
  60. //最小のノードを削除
  61. delNode(ターゲット値);
  62. ターゲット値を返します
  63. }
  64.  
  65. /**
  66. * ノードをルートとする二分ソート木の最大値を見つけ、ノードをルートノードとする二分ソート木の最大ノードを削除します。
  67. *
  68. * @param node 入力ノード(バイナリソートツリーのルートノードとして)
  69. * @returnルートノードとしてノードを持つバイナリソートツリーの最大ノード値を返します
  70. */
  71. 公共  int delLeftTreeMax(ノードノード) {
  72. ノードターゲット = ノード;
  73. while ( target.right != null ) {
  74. ターゲット = target.right ;
  75. }
  76.  
  77. // 最大のノードを削除する
  78. delNode(ターゲット値);
  79. ターゲット値を返します
  80. }
  81.  
  82. //ノードを削除する
  83. パブリックvoid delNode( int値) {
  84. ルートがnull場合
  85. 戻る;
  86. }それ以外{
  87. ノード targetNode = search(値);
  88. ターゲットノードnullの場合
  89. 戻る;
  90. }
  91. ターゲットノード == ルートの場合 {
  92. ルート = null ;
  93. 戻る;
  94. }
  95. ノード parentNode = searchParent(targetNode);
  96.  
  97. targetNode.left == nullかつ targetNode.right == null場合{
  98. //削除するノードがリーフノードの場合
  99. 親ノードの左がnull で、親ノードのが targetNode の値の場合){
  100. 親ノード.left = null ;
  101. }
  102. 親ノードの右がnull != nullかつ親ノードの右がtargetNode の値 == の場合){
  103. 親ノード.right = null ;
  104. }
  105. }それ以外の場合( targetNode.left ! = null && targetNode.right ! = null ) {
  106. //削除するノードが2つのサブツリーを持つノードの場合
  107. int minValue = delRightTreeMin ( targetNode.right );
  108. ターゲットノードの値 = minValue;
  109. // 上位コードと下位コードを削除しても効果は同じです
  110. // int maxValue = delLeftTreeMax ( targetNode.left );
  111. //targetNode.value = maxValue;
  112. }それ以外{
  113. //削除するノードには左の子ノードのみがあります
  114. targetNode.left != null )の場合{
  115. 親ノードがnull場合
  116. 親ノードの左辺がターゲットノードの場合
  117. 親ノードの左=ターゲットノードの左 ;
  118. }それ以外{
  119. 親ノードの右=ターゲットノードの左 ;
  120. }
  121. }それ以外{
  122. //親ノードが空の場合は、ルートの位置を変更します
  123. ルート= targetNode.left ;
  124. }
  125. } else {//削除するノードには右の子ノードのみがある
  126. 親ノードがnull場合
  127. 親ノードの左辺がターゲットノードの場合
  128. 親ノードの左=ターゲットノードの右;
  129. }それ以外{
  130. 親ノードの右=ターゲットノードの右;
  131. }
  132. }それ以外{
  133. //親ノードが空の場合は、ルートの位置を変更します
  134. ルート = targetNode.right ;
  135. }
  136.  
  137. }
  138. }
  139. }
  140. }
  141.  
  142. //ノードを追加
  143. パブリックvoid add (Node ノード) {
  144. ルートがnull場合
  145. ルート = ノード;
  146. }それ以外{
  147. root.add (ノード);
  148. }
  149. }
  150.  
  151. // 順序通りの走査
  152. パブリックvoid infixOrder() {
  153. ルートがnull場合
  154. ルートの順序を固定します。
  155. }それ以外{
  156. System.out.println ( "バイナリソートが空なので走査できません" );
  157. }
  158. }
  159. }
  160.  
  161. クラスノード{
  162. int値;
  163. ノード;
  164. ノード;
  165.  
  166. パブリックノード( int値){
  167. this.value = 値;
  168. }
  169.  
  170. /**
  171. * 左サブツリーの高さを返します
  172. *
  173. * @戻る 
  174. */
  175. 公共  int左高さ() {
  176. if (== null ) {
  177. 0を返します
  178. }
  179. 戻る .height();
  180. }
  181.  
  182. /**
  183. * 右サブツリーの高さを返します
  184. *
  185. * @戻る 
  186. */
  187. 公共  int右高さ() {
  188. this.rightnull場合
  189. 0を返します
  190. }
  191. 戻る .height();
  192. }
  193.  
  194. /**
  195. * このノードをルートノードとするツリーの高さを返します
  196. *
  197. * @戻る 
  198. */
  199. 公共 整数高さ() {
  200. Math.max (this.left == null ? 0 : this.left .height(), this.right == null ? 0 : this.right .height()) + 1を返します
  201. }
  202.  
  203. /**
  204. * 左に回転
  205. */
  206. パブリックボイド左回転() {
  207. //現在のルートノードの値で新しいノードを作成します
  208. ノード newNode = 新しいノード(値);
  209. //新しいノードの左サブツリーを現在のノードの左サブツリーに設定します
  210. newNode.left =;
  211. //新しい右サブツリーを現在のノードの右サブツリーの左サブツリーに設定します
  212. newNode.right = right.left ;
  213. //現在のノードの値を右の子ノードの値に置き換えます
  214. 値 =.value;
  215. //現在のノードの右サブツリーを、現在のノードの右の子の右サブツリーに設定します
  216. =.;
  217. //現在のノードの左の子ノード(左のサブツリー)を新しいノードに設定します
  218. = newNode;
  219. }
  220.  
  221. /**
  222. * 右に回転
  223. */
  224. パブリックボイド右回転() {
  225. //現在のルートノードの値で新しいノードを作成します
  226. ノード newNode = 新しいノード(値);
  227. //新しいノードの右サブツリーを現在のノードの右サブツリーに設定します
  228. newNode.right =;
  229. //新しいノードの左サブツリーを現在のノードの左サブツリーの右サブツリーに設定します
  230. newNode.left = left.right ;
  231. //現在のノードの値を左の子ノードの値に置き換えます
  232. 値 =.value;
  233. //現在のノードの左サブツリーを左サブツリーの左サブツリーに設定します
  234. =.;
  235. //現在のノードの右サブツリーを新しいノードに設定します
  236. = newNode;
  237. }
  238.  
  239. /**
  240. * 削除するノードの親ノードを見つける
  241. *
  242. * @param node 削除するノード
  243. * @return削除するノードの親ノード
  244. */
  245. パブリックノードsearchParent(ノードノード) {
  246. //現在のノードが削除するノードの親ノードである場合は、
  247. if (( this.left != null && this.left .value == node.value) ||
  248. ( this.right != null && this.right .value == node.value)) {
  249. これを返します
  250. }それ以外{
  251. if ( this.left != null && node.value < this.value) {
  252. //検索対象のノードの値が現在のノードの値より小さい場合は、左のサブツリーを再帰的に検索します
  253. this.left.searchParent (ノード)を返します
  254. }そうでない場合 (this.right ! = null && value >= this.value) {
  255. //検索対象のノードの値が現在のノードの値より小さい場合は、左のサブツリーを再帰的に検索します
  256. this.right.searchParent (ノード)を返します
  257. }それ以外{
  258. 戻る ヌル;
  259. }
  260. }
  261. }
  262.  
  263. /**
  264. * 削除するノードを見つける
  265. *
  266. * @param value 削除するノードの値
  267. * @return削除されたノード
  268. */
  269. パブリックノード検索( int値){
  270. if (値 == this.value) {
  271. これを返します
  272. }それ以外の場合 (値 < this.value) {
  273. if ( this.left != null ) {
  274. this.left.search (値)を返します
  275. }それ以外{
  276. 戻る ヌル;
  277. }
  278. }それ以外{
  279. if ( this.right != null ) {
  280. this.right.search (値)を返します
  281. }それ以外{
  282. 戻る ヌル;
  283. }
  284. }
  285. }
  286.  
  287. // バイナリソートツリーの要件を満たすためにノードを再帰的に追加します
  288. パブリックvoid add (Node ノード) {
  289. if (ノード == null ) {
  290. 戻る;
  291. }
  292. (ノード値<this値)の場合{
  293. if ( this.left == null ) {
  294. this.left = ノード;
  295. }それ以外{
  296. // 左のサブツリーに再帰的に追加する
  297. this.left.add (ノード) ;
  298. }
  299. }それ以外{
  300. this.rightnull場合
  301. this.right = ノード;
  302. }それ以外{
  303. // 右の子ノードに再帰的に追加します
  304. this.right.add (ノード) ;
  305. }
  306. }
  307.  
  308. //ノードを追加した後、(右サブツリーの高さ - 左サブツリーの高さ) > 1 の場合は左回転を実行します
  309. 右の高さ() - 左の高さ() > 1 の場合 {
  310. // 右サブツリーの左サブツリーの高さが右サブツリーの右サブツリーの高さよりも大きい場合は、まず右サブツリーを右に回転してから、現在のノードを左に回転する必要があります。
  311. if( right != null && right .leftHeight() > right .rightHeight()){
  312. .rightRotate();
  313. 左回転();
  314. }それ以外{
  315. //左に回転するだけ
  316. 左回転();
  317. }
  318. 戻る;
  319. }
  320.  
  321. //ノードを追加した後、(左サブツリーの高さ - 右サブツリーの高さ) > 1 の場合は右回転を実行します
  322. (左の高さ() - 右の高さ() > 1)の場合{
  323. // 左サブツリーの右サブツリーの高さが左サブツリーの左サブツリーの高さよりも大きい場合は、まず左サブツリーを左に回転してから、現在のノードを右に回転する必要があります。
  324. if(!= null &&.rightHeight() >.leftHeight()){
  325. .leftRotate();
  326. 右回転();
  327. }それ以外{
  328. //右に回転するだけ
  329. 右回転();
  330. }
  331.  
  332. }
  333. }
  334.  
  335. // 順序通りの走査
  336. パブリックvoid infixOrder() {
  337. if ( this.left != null ) {
  338. this.left .infixOrder();
  339. }
  340. System.out.println (これ) ;
  341. if ( this.right != null ) {
  342. this.right .infixOrder();
  343. }
  344. }
  345.  
  346. @オーバーライド
  347. パブリック文字列toString() {
  348. 戻る  「ノード{」 +
  349. "値=" + 値 +
  350. '}' ;
  351. }
  352. }

【編集者のおすすめ】

  1. Dubbo はマイクロサービスの面接で必ず聞かれる質問です。こんなに詳しい情報では仕事が見つからないのではないかと心配ですか?
  2. 2021年に注目すべきIT業界の5つのトレンド
  3. 無料のセキュリティソフトは寂しい!ため息をつく
  4. インターフェースのUIが変わります! Windows 10 21H2 の最新プレビューを一足先にチェック
  5. マイクロソフト、エクスプローラー検索などの問題を修正するため、Windows 101909 の KB5000850 アップデートをリリース

<<:  新しい機械学習アプローチによりエネルギー消費を20%削減

>>:  一枚の紙で AI を騙せる。これが OpenAI の最も先進的な視覚モデルでしょうか?

ブログ    
ブログ    

推薦する

Siriは中国で禁止されるのでしょうか?国内AI企業がアップルを特許侵害で訴え、高等法院は中国の特許を有効と認定

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

GenAIがより良い回答を提供するためのヒント

GenAI は、ユーザーが独自の方法でデータをクエリし、ニーズに合わせた回答を受け取ることができるイ...

AIはDevOpsエクスペリエンスに目に見える以上の変化をもたらす

Cycode の共同創設者兼 CTO である Ronen Slavin 氏は、AI によって実現され...

...

コレクションにおすすめ!素晴らしい AWS 機械学習ツールキットの概要

[[330619]]テクノロジーとエコロジーの継続的な進化、およびアプリケーション シナリオの継続的...

空軍の最高データ・AI責任者がAIを通じて戦略的優位性を獲得する方法について語る

AI は、軍事への応用、脅威の監視、国家防衛の確保など、私たちの行動様式を変えています。 AIは軍事...

エッジAI: 人工知能の進化の次のステップ

[[422303]]人工知能(AI)は、かなり長い間、世界中のビジネスにおいて安定した存在となってい...

...

...

機械学習モデルは展開するには大きすぎますか? 3つの解決策をご紹介します

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式...

...

次世代交通におけるAI世代の影響

次世代の交通手段は、電子機器、持続可能性、経験を設計の中核としており、Gen AI は、想定される次...

SQL クエリ エンジンの自然言語として GPT を使用する方法

翻訳者 |李睿レビュー | Chonglou 今日では、 ChatGPTのような生成AI技術のおかげ...

IDCは、米国の人工知能への支出が2025年までに倍増すると予測している

米国のAIへの支出は2025年までに1,200億ドルに増加するだろう。 2021年から2025年の予...