HOME»基本情報技術者試験掲示板»重点対策解説お願いいたします(ヒープ)
投稿する

重点対策解説お願いいたします(ヒープ) [5031]

 まきさん(No.1) 
P282のヒープのトレースするあたりに混乱してしまいトレースできません。
教えてください。
要素番号  1 2 3  4  5
値       10 8 4  1  7
これの10と7を入れ替えたいのですが、
if(right<=bottom)and(list[max]<=list[right])
    7       7             1           5
max←right  これで入れ替えになったのかが分かりません
  5    5
2023.08.27 15:24
 まきさん(No.2) 
そもそも論rightは要素番号3の4じゃないの?
2023.08.27 15:25
まーぼさん(No.3) 
FE シルバーマイスター
要素番号と要素の値を混同しているような気がします。

>if(right<=bottom)

これは配列の範囲外アクセスを防ぐための記述だと思うので、bottomは5な気がします。

>max←right  これで入れ替えになったのかが分かりません

これだけでは入れ替えてはいないと思います。探索範囲の最大値の要素の要素番号を変数maxに代入する処理ですかね。

>そもそも論rightは要素番号3の4じゃないの?

parent = 1の場合はright = 3で、list[right] = 4だと思います。このifのブロックがwhileのブロックの中にあってwhileブロックの中でparentやrightの値を更新していないでしょうか。

#基本的なデータ構造の質問であれば、変数の説明などを書いて頂ければ書籍を持っていなくても回答できる可能性が高いと思います。
2023.08.27 17:19
 まきさん(No.4) 
PG
整数型配列heap(整数型の配列:list 整数型:root,整数型  bottom)
整数型left←root*2
整数型left←root*2+1
整数型max

if(left<bottom)and(list[left]>list{root})
max←left
else
max←right
endif

if((right<=bottom)and(list[right]>list[max])
max←right
if(max≠root)
list[root]とlist[max]を入れ替える
list←heap(list,max,bottom)
endif
return list

以上です
2023.08.27 18:05
 まきさん(No.5) 
right←root×2+1
は間違えました
2023.08.27 18:16
 まきさん(No.6) 
right←root×2+1
は間違えました
2023.08.27 18:16
まーぼさん(No.7) 
FE シルバーマイスター
初期状態がNo.1の
>要素番号  1 2 3  4  5
>値       10 8 4  1  7

でよろしいでしょうか?

heapは再帰関数ですかね?heapに最初に与える引数はなんでしょうか。プログラムのendifが1つ足りない気がします。
2023.08.27 18:41
 まきさん(No.8) 
heapsort ( 10 8 4 1 7)
>要素番号  1 2 3  4  5"
">値       10 8 4  1  7"

G
整数型配列heap(整数型の配列:list 整数型:root,整数型  bottom)
整数型left←root*2
整数型left←root*2+1
整数型max

if(left<bottom)and(list[left]>list{root})
max←left
else
max←right
endif

if((right<=bottom)and(list[right]>list[max])
max←right
endif

if(max≠root)
list[root]とlist[max]を入れ替える
list←heap(list,max,bottom)
endif
return list
2023.08.27 18:46
 まきさん(No.9) 
お願いいたします。
2023.08.27 18:47
まーぼさん(No.10) 
FE シルバーマイスター
heapsortとheapは別の関数ですか?

だとしたら

>これの10と7を入れ替えたい

これは関数heapsortの処理だと思いますよ。
2023.08.27 19:19
 まきさん(No.11) 
>heapsortとheapは別の関数ですか?

すみません別です
2023.08.27 19:46
まーぼさん(No.12) 
FE シルバーマイスター
{10,8,4,1,7}は親>=子の関係が成り立っています。

10と7を入れ替えて
{7,8,4,1,10}
先頭と入れ替えて末尾に来た10はヒープ木から切り離して考えます。

{7,8,4,1}をヒープ化します。
{7,8,4,1}→{8,7,4,1}
8と1を入れ替えて
{1,7,4,8}
末尾の8はヒープ木から切り離す。

{1,7,4}をヒープ化します。
{1,7,4}→{7,1,4}
7と4を入れ替えて
{4,1,7}
末尾の7はヒープ木から切り離す。

{4,1}をヒープ化します。(ここはすでにヒープになっている)
4と1を入れ替えて
{1,4}
末尾の4はヒープ木から切り離す。

これでソートが終了し、1,4,7,8,10と昇順ソートできますね。
2023.08.27 19:50
 まきさん(No.13) 
この投稿は投稿者により削除されました。(2023.08.27 19:55)
2023.08.27 19:55
 まきさん(No.14) 
12の投稿はheapsortですね。
それはそれで分かるのですが。

if(left<bottom)and(list[left]>list{root})
max←left
else
max←right
endif

if((right<=bottom)and(list[right]>list[max])
max←right
endif

if(max≠root)
list[root]とlist[max]を入れ替える
list←heap(list,max,bottom)
endif
return list 

このPGを見た時に値がどうなるのか読めないんです。
そこからなんです。すみません
2023.08.27 20:00
 まきさん(No.15) 
PGを1つ1つ読まないとわからないんです。
色々値が混乱して値の流れが分かりません。ごめんなさい
2023.08.27 20:02
 まきさん(No.16) 
このPGの下に値入れていただけないですか。一行一行開けていきますので
本当に分からないのでごめんなさい。私も悩んでます

if(left<bottom)and(list[left]>list{root})

max←left

else

max←right

endif

if((right<=bottom)and(list[right]>list[max])

max←right

endif

if(max≠root)

list[root]とlist[max]を入れ替える

list←heap(list,max,bottom)

endif

return list
2023.08.27 20:05
まーぼさん(No.17) 
FE シルバーマイスター
heapはヒープを再構築する関数だと思います。

list = {7,8,4,1,10}

heap(list,1,4)を実行すると、

left = 2
right = 3

left = 2,bottom=4で条件式がtrueなので
max←left
max=2

right=3,bottom=4でright<=bottomはtrue
list[right] = 4,list[max]=8なのでlist[right]>list[max]はfalseなのでendifまで飛ぶ

max=2,root=1なのでmax≠rootはtrue
list[root]とlist[max]を入れ替えて
list = {8,7,4,1,10}

heap(list,2,4)を実行(続
2023.08.27 20:39
 まきさん(No.18) 
ありがとうございます。
しっかり追いかけます
2023.08.27 21:31
まーぼさん(No.19) 
FE シルバーマイスター
この投稿は投稿者により削除されました。(2023.08.27 23:14)
2023.08.27 23:14
まーぼさん(No.20) 
FE シルバーマイスター
この投稿は投稿者により削除されました。(2023.08.27 23:14)
2023.08.27 23:14
まーぼさん(No.21) 
FE シルバーマイスター
私の勘違いだったら申し訳ないのですが、プログラムが間違っているかもしれないです。

この部分
 if(left<bottom)and(list[left]>list{root})
max←left
else
max←right
endif

left < bottomがfalseだとmaxにrightが代入されるのが怪しい気がします。

該当部分のプログラムを変えてみたので、読み変えてみるといいかもしれません。
 max←root

if((left<=bottom)and(list[left]>list[max]))
__max←left
endif

if((right<=bottom)and(list[right]>list[max]))
__max←right
endif
詳しく調べられてないので間違ってるかもです。明日また時間とります。
2023.08.27 23:13
まーぼさん(No.22) 
FE シルバーマイスター
正直元の
if(left<bottom)and(list[left]>list{root})
max←left
else
max←right
endif
は何をやっているか分かりません。maxが配列の範囲外の要素番号で更新されうるので、list[max]で配列の範囲外にアクセスしてしまいます。

整数型配列heap(整数型の配列:list 整数型:root,整数型  bottom)
整数型left←root*2
整数型right←root*2+1
整数型max←root

if((left<=bottom)and(list[left]>list[max]))
__max←left
endif

if((right<=bottom)and(list[right]>list[max]))
__max←right
endif

if(max≠root)
list[root]とlist[max]を入れ替える
list←heap(list,max,bottom)
endif
return list

ならば意味は分かります。
他の方の意見も聞きたいです。
2023.08.28 11:39
 まきさん(No.23) 
この投稿は投稿者により削除されました。(2023.08.28 22:03)
2023.08.28 22:03
 まきさん(No.24) 
list = {1,7,4,8,10}
heap(list,2,4)を実行する

left=2
right=3
max=1
bottom=2


if(left<=bottom)and(list[left]>list[root]) 
     2    2           (2) 7 (1) 1
max←left      成立したのでendifまで飛ぶ
2     2
------------------------------------------
else

max←right


endif

if((right<=bottom)and(list[right]>list[max])  不成立 endifまで飛ぶ
      3      2            (3)4    (1)7
max←right

endif

if(max≠root)
    2    1
list[root]とlist[max]を入れ替える
      1            7
list←heap(list,max,bottom)

endif

return list

list{7,1,4,8,10}

heapsortで入れ替え
list[4,1,7,8,10]

ということですね。ありがとうございます。
2023.08.28 22:03
まーぼさん(No.25) 
FE シルバーマイスター
>list = {1,7,4,8,10}
>heap(list,2,4)を実行する

これはどこから来たのですか?
2023.08.28 22:21
電タックさん(No.26) 
FE ブロンズマイスター
まきさん

No.23はheap(list,1,2)で呼び出した結果としてはlist{7,1,4,8,10}であっている気がしますが・・・

それとは別に
No.1での質問部分とNo.23のトレース結果も違う気がしますし、No.23の何が知りたいのか?とか、○○の部分が不明確とかの、質問ポイントを提示してあげないと答える側も何を書いてあげれば良いのかがわからないと思います。
2023.08.28 22:21
そもそもさん(No.27) 
IPAで公開された問題(ドットコム掲載の問題)で質問されたほうが良いかと。
2023.08.28 22:47
jjon-comさん(No.28) 
FE ゴールドマイスター
とりあえず。
No,4, No.8, No.14, No.16 で次のコードが繰り返し登場していますけれど。
if(left<bottom)and(list[left]>list{root}) //★1
max←left
else
max←right //★2
endif
★1★2の箇所は、その参考書に本当にそう書いてあるんですか?
また、本当にそう書いてある場合、出版社のホームページなどに正誤表が公開されたりなどしていないんですか。

ちなみに★1の行を、質問者はNo.24では次のように修正していますよね。
if(left<=bottom)and(list[left]>list[root])
2023.08.28 22:58
まーぼさん(No.29) 
FE シルバーマイスター
>jjon-comさん

ネットに正誤表は出ているんですが、該当ページに関しては記載がなかったですね。ただ正誤表には30個ほどの間違いがあったので、間違っていてもおかしくはないと思います。
2023.08.28 23:12
jjon-comさん(No.30) 
FE ゴールドマイスター
ちなみに。
★1の行は 質問者がNo.24で修正した行が正しく、
★2は max←root が正しいのであれば、
プログラムの意味はこうなると思います。

--------
//部分木の節(root)、その左側の子(left)と右側の子(right)、
//という3者の中から最大値を見つけ、親>子 の関係にする。

//左側の子が存在するなら、左側の子と部分木の節を比較する。
if(left<=bottom)and(list[left]>list[root])
max←left //左側の子が暫定最大値
else
max←root //部分木の節が暫定最大値
endif

//右側の子が存在するなら、右側の子と暫定最大値を比較する。
if((right<=bottom)and(list[right]>list[max])
max←right //右側の子が最大値
endif

//最大値が左側の子または右側の子であったなら
if(max≠root)
list[root]とlist[max]を入れ替える

//交換が発生したなら、左側の子または右側の子を
//新たな部分木の節(root)として、親>子 の関係を作り出す。
list←heap(list,max,bottom)
endif
return list
2023.08.28 23:21
jjon-comさん(No.31) 
FE ゴールドマイスター
No.30のコードは、No.22で まーぼ さんが
> ならば意味は分かります。
と提示したコードと同じ動きです。念のため。
2023.08.28 23:34
まーぼさん(No.32) 
FE シルバーマイスター
データ構造に関するプログラムはまず、データ構造の理解を深めてからだと思います。

・二分木の節がランダムに並べられているとき、どのようにヒープ化するか。

・二分木の先頭とその子以外が親>=子の関係を満たしているときどのようにヒープ化するか。

この2つは答えられますか。

この2つを理解していないとプログラムを読んでもよく分からないと思います。どのような処理をすればいいのか理解すれば格段に理解しやすくなると思います。
2023.08.29 00:58
 まきさん(No.33) 
みなさんありがとうございました。
私はただちゃんと理解できるかここでトレースを真似てみて出来ているのか見てほしかったんです。
色々と参考書を読んで見ましたが、この重点対策で自信をつけようとトライしてます。私も理解出来ないんで苦しいのは一緒です。

まーぼさんからの2つの質問はすみません答えられないのでまだ理解出来ないんだと思います。

素直に本に書いてあってもどういう風に理解できないです。説明お願い致します
2023.08.29 12:26
まーぼさん(No.34) 
FE シルバーマイスター
ところで参考書に載っていたプログラムはjjon-comさんが提示したプログラムで合っていたのでしょうか?

ちなみにNo.17の私の投稿

>list = {8,7,4,1,10}

>heap(list,2,4)を実行(続

とあるので、この続きからは
list{8,7,4,1,10}
でheap(list,2,4)をトレースすることになりますよ。これは要素番号2の節が根で、最後の要素番号が4の二分木が「親>=子の関係」であるかを調べています。listの1~4番目を切り出すと、{8,7,4,1}となり、これはすでにヒープになっているのですが、プログラムはまだ「親>=子の関係を満たしている二分木」とは分かっていないです。
2023.08.29 12:40
jjon-comさん(No.35) 
FE ゴールドマイスター
キーワード TXTAF0016 でGoogle検索すると,あるPDFがヒットします。

ヒープという二分木を完成させたら,後は,このPDFの3~4ページの動きで
大きな値から順に決定できる(ヒープソートが進んでいく)
というイメージはできていらっしゃるのでしたっけ?
2023.08.29 13:27
 まきさん(No.36) 
とりあえず整理して返答します


>まーぼさん
list = {1,7,4,8,10}
>heap(list,2,4)を実行する

これはどこから来たのですか?

重点対策P287の⑤の入れ替え完了のとこからです。

>jjon-comさん

ヒープという二分木を完成させたら,後は,このPDFの3~4ページの動きで
大きな値から順に決定できる(ヒープソートが進んでいく)
というイメージはできていらっしゃるのでしたっけ?

①1[80](根)と8[20]を交換して80が格納される
②1[20]と2[70]を交換して1[70] 2[20]になる     
③次は2[20]と4[50]と交換  これは親>子に基づくもの
④次は1[70]と7[40]と交換  
⑤1[80](根)と8[20]を交換して70が格納される
⑥というように根に取り出す値もって来て最後に一番大きい子に根を配置して値を取り出すという動作。

私の理解しているイメージはこういった感じです
2023.08.29 21:40
 まきさん(No.37) 
この投稿は投稿者により削除されました。(2023.08.29 21:46)
2023.08.29 21:46
 まきさん(No.38) 
>電タックさん
配慮が足らなくてすみません
2023.08.29 21:47
 まきさん(No.39) 
>まーぼさん
ところで参考書に載っていたプログラムはjjon-comさんが提示したプログラムで合っていたのでしょうか?

整数型の配列 heap(整数型の配列list,整数型:root,整数型bottom)

整数型:left←root*2
整数型:right←root*2+1
整数型 max

if(leftがbottom以下)and(list[left]がlist[root]より大きい)

max←left

else

max←right

endif

if((rightがbottom以下)and(list[right]がlist[max]より大きい)

max←right

endif

if(maxとrootが等しくない)

list[root]とlist[max]を入れ替える

list←heap(list,max,bottom)

endif

return list

整数型の配列heap_sort(整数型の配列:list)
for(iをlistの要素数から1まで1ずつ減らす)
list←heap(□)

endfor

return list

プログラムを全部書きました。これでいいですか?
2023.08.29 22:02
電タックさん(No.40) 
FE ブロンズマイスター
まきさん

書籍側の問題でまともにトレースしてもおかしな結果になる可能性もあるので不安になるのは仕方ないです。

ここでやり取りすと結構時間がかかるなーと思っていたのでお互いのためにも端的なポイントで質問したほうがと思ったぐらいです。

ちなみにトレースをする上でNo.24みたいに変数を紙に書き出して変化をどんどん下や右方向に書き足していくのは(消すのが面倒だから)実践的で良い方法だと思いました。
left、right、max
2、_3、__1
_______2

合格目指して頑張ってください!
2023.08.29 22:16
電タックさん(No.41) 
FE ブロンズマイスター
まきさん

No.39の
else
max←right

jjon-comさんの(No.30)
else
max←root
の誤植だと思うのでコレでトレースしたほうがいいです。
2023.08.29 22:20
まーぼさん(No.42) 
FE シルバーマイスター
念の為確認ですが、

if(leftがbottom以下)and(list[left]がlist[root]より大きい)

max←left

else

max←right 

endif

が参考書に載っていたのですよね。
 
max←rootではなく。
2023.08.29 22:20
 まきさん(No.43) 
間違えました。
max←root
です。すみません
2023.08.29 22:34
 まきさん(No.44) 
長い間ありがとうございました。
問題自体に不備があるんですね。やっていても気づきませんでした。トレース自体はこれでいいと分かっただけでも嬉しいです。不安でも少しずつでも慣れていくしかありません。
こういった問題ができるようになれば旧試験のヒープの問題に再度チャレンジします。ご指導ありがとうございました。
2023.08.29 22:42
まーぼさん(No.45) 
FE シルバーマイスター
とりあえずはある節に対して、その節自身と、左の子、右の子の内の3つの値の中で一番大きい数字を持つ節の要素番号を取得したいわけです。これは選択ソート(基本選択法)の考え方でできると思います。

ただ全ての節が子を持つわけではないので、(leftがbottom以下)や(rightがbottom以下)などの条件式が必要になります。

(leftがbottom以下)や(rightがbottom以下)
→ヒープの範囲外ではないことの条件

(list[left]がlist[root]より大きい)や(list[right]がlist[max]より大きい)
→大小比較のための条件式

と分けて考えると分かりやすいかも知れません。

“工業大学生ももやまのうさぎ塾”の”うさぎでもわかるヒープアルゴリズム”というサイトが私は分かりやすいと思います。
2023.08.29 23:03
java-shiさん(No.46) 
念の為ですが、、、、
この書籍に不備が多いのは事実ですが、
質問されている問題に不備は無いと思います。
単純に転記ミスが多くみなさんが混乱されていると思います。

関数: heap_sortの内容は下記ですので
★マークの所が抜けています。

〇 整数型の配列: heap_sort( 整数型の配列: list ) 
 for ( i を list の要素数 から 1まで1ずつ減らす ) 
  list[ 1 ] と list[ i ] を入れ替える★
  list ← heap( list, 1, i - 1 )
 endfor 
 return list 

質問されている「10と7」の入れ替えは、関数:heap_sortの★マークで行われています。
また、関数:heapの内容についても「max←root」などの転記ミスにより誤植のように勘違いが発生しています。

重点対策は、トレースや各行の説明も細かに説明があり、とても良い書籍ですよ♪
(ただ、、、誤植が修正されるまでは、初心者には厳しいと思いますけどね。。。)
2023.08.30 08:36
まーぼさん(No.47) 
FE シルバーマイスター
No.24の正しいトレースは以下のようになります。

>list = {1,7,4,8,10}
>heap(list,2,4)を実行する

根の8と末尾の1を入れ替えた後ならheap(list,1,3)が正しい。

>left=2
>right=3

heap(list,1,3)なら正しいが、heap(list,2,4)では誤り。

>max=1

参考書通りならmaxはここでは代入されない。

>bottom=2

bottomへの代入は行われていない。

>if(left<=bottom)and(list[left]>list[root]) 
>   2    2           (2) 7 (1) 1

leftは2,bottomは3なのでandの前半の条件はtrue
list[2]は7、list[1]は1なので後半の条件もtrue

全体の条件式もtrueなのでif文の中を実行する

>max←left      成立したのでendifまで飛ぶ
maxに2が代入される。elseは実行されない。

>if((right<=bottom)and(list[right]>list[max])  不>成立 endifまで飛ぶ
>    3      2            (3)4    (1)7
rightは3,bottomは3なので前半の条件式はtrue
list[3]は4、list[2]は7なので後半の条件式はfalse

全体の条件式はfalseなのでif文の中は実行されない。

>if(max≠root)
>    2    1
maxは2,rootは1なので条件式はtrue
if文の中を実行する。

>list[root]とlist[max]を入れ替える
>     1            7
list[1]は1、list[2]は7なので1と7を入れ替えて、listは{7,1,4,8,10}になる。

>list←heap(list,max,bottom)
heapの再帰呼び出し
list={7,1,4,8,10}、maxは2,bottomは3なので
heap(list,2,3)が呼び出される。

再帰部分は自分でやってみてください。
2023.08.30 14:34
 まきさん(No.48) 
最後までありがとうございます。
2023.08.30 20:03
返信投稿用フォームスパム防止のためにスレッド作成日から30日経過したスレッドへの投稿はできません。
© 2010-2024 基本情報技術者試験ドットコム All Rights Reserved.

Pagetop