質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

3188閲覧

二分木探索の実装の削除メソッドについて

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2016/08/20 13:37

二分木探索の実装の削除メソッドでわからないところがあります。
こちらの実装についてです。
http://d.hatena.ne.jp/g940425/20101211/1292088124

以下に示しますコードは二分木探索の実装です。

Java

1public class BinarySearchTree<T> { 2 public int key; 3 public T value; 4 public BinarySearchTree<T> left; 5 public BinarySearchTree<T> right; 6 public BinarySearchTree<T> parent; 7 8 //コンストラクタ:木を作成 9 BinarySearchTree(){ 10 this.value = null; 11 this.key = 0; 12 this.left = null; 13 this.right = null; 14 this.parent = null; 15 } 16 17 //コンストラクタ:ノードを作成 18 BinarySearchTree(int key,T value,BinarySearchTree<T> p){ 19 this.value = value; 20 this.key = key; 21 this.left = null; 22 this.right = null; 23 this.parent = p; 24 } 25 26 //木に挿入 27 public void insert(int key,T value){ 28 if(this.parent == null && this.value == null){ 29 //根が空の場合 30 this.value = value; 31 this.key = key; 32 return; 33 }else if(this.key > key){ 34 //左に挿入 35 if(this.left == null){ 36 //左に子がない 37 this.left = new BinarySearchTree<T>(key,value,this); 38 }else { 39 //左に部分木あり 40 this.left.insert(key,value); 41 } 42 }else if(this.key < key){ 43 //右に挿入 44 if(this.right == null){ 45 //右に子がない 46 this.right = new BinarySearchTree<T>(key,value,this); 47 }else { 48 //右に部分木あり 49 this.right.insert(key,value); 50 } 51 }else{ 52 //既存のキーの場合:上書きする 53 this.value = value; 54 } 55 return; 56 } 57 58 //キーを指定して検索 59 public BinarySearchTree<T> search(int key){ 60 if(this.key == key && this.value != null)return this; 61 if(this.key > key && this.left != null)return this.left.search(key); 62 if(this.key < key && this.right != null)return this.right.search(key); 63 return null; 64 } 65 66 //最小の値を削除 67//木から切り取るだけなので、この関数から返ったノードへのアドレスを呼び出し側で受けることで削除したノードへのアクセスが可能 68//なお、削除操作での使用を想定しているため、削除ノードが根だった場合を考慮していない 69 public BinarySearchTree<T> extractMin(){ 70 if(this.left == null){ 71 //左に子を持たない場合:これが最小ノードなので、削除 72 if(this.right == null){ 73 //孤立した(子がない)場合:削除ノードを切り離す 74 if(this.parent.left == this){ 75 this.parent.left = null; 76 }else { 77 this.parent.right = null; 78 } 79 }else{ 80 //右に子を持つ場合:このノードの代わりに右の子を親の子とする 81 if(this.parent.left == this){ 82 this.parent.left = this.right; 83 }else { 84 this.parent.right = this.right; 85 } 86 this.right.parent = this.parent; 87 } 88 return this; 89 }else{ 90 //左に子を持つ場合:左の部分木の最小ノードを取り除く 91 return this.left.extractMin(); 92 } 93 } 94

メソッドextractMin()についてなのですが、

Java

1if(this.parent.left == this){ 2 this.parent.left = null; 3 }else { 4 this.parent.right = null;

の部分でelseとあるのですが、このelseがどういう状況なのかイメージできません。
このメソッドでは根の削除は考慮していません。
また、一番左にあるノードに到達した時に、

Java

1(!this.parent.left == this)

という条件が成り立つのでしょうか?
ここで詰まっています。
わかる方、ご助力ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下でやろうとしているのは、親から自分へのリンク切り離す作業です。
自分を削除することは決定しています。

2分木なので、自分は、自分の親にとって左の子か、右の子か、どちらでしかありえません。
親の左の子==自分ならば、親の左の子はないものとする。
それいがいなら親の右の子はないものとする。(=親の左の子が自分じゃないなら、自分は親の右の子のはずだから)

if(this.parent.left == this){ this.parent.left = null; }else { this.parent.right = null; }

また、一番左にあるノードに到達した時に、(!this.parent.left == this)という条件が成り立つのでしょうか?

細かいですけど(this.parent.left != this)こうか(!(this.parent.left == this))ですね。

この最小を削除する段階において、自分が親にとって右の子であった場合、
自分が最小でないことが確定して矛盾するのでないと思います。
elseブロック側も同じですかね。

投稿2016/08/20 14:09

flied_onion

総合スコア2604

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/08/21 00:01

回答ありがとうございます。 そうすると、以下のコードの方が良いのですかね? if(this.left == null){ //左に子を持たない場合:これが最小ノードなので、削除 if(this.right == null){ //孤立した(子がない)場合:削除ノードを切り離す this.parent.left = null; }else{ //右に子を持つ場合:このノードの代わりに右の子を親の子とする this.parent.left = this.right; this.right.parent = this.parent; } return this; }else{ //左に子を持つ場合:左の部分木の最小ノードを取り除く return this.left.extractMin(); この方が分かりやすくて、いいと思うのですが。
flied_onion

2016/08/21 03:35

分かりやすさというのはいろんな見方があるのでそう一言では言えないです。 ここの(最小の削除)コードの最適化だけならそうかもしれませんが、パターンとして自ノードの切り離しだけを考えれば親ノードの双方と自分を比べれば他の条件での削除も似た形になって、同様の処理をしていることに気づきやすいメリットがあります(削除処理のメソッド化などにもつながる)。元のコードも「最小」という条件抜きで、切り離しや入れ替えのパターンをコードに書いただけじゃないですかね。 変更するなら、私なら矛盾する条件にはいったらthrowさせることを検討します。 自分の考えが間違っている可能性や他の部分コードが間違ってそこに入る可能性もあるので。 比較をなくすならコードコメントの修正はします。
退会済みユーザー

退会済みユーザー

2016/08/21 03:59

回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問