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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

1807閲覧

クイックソートの再帰呼び出し回数について

Angela_Nakasugi

総合スコア3

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2021/10/14 13:48

python3.xを用いてクイックソートの再起呼び出しの回数を調べる以下のコードを作りました。(リストの長さは10)

def simple_qsort(lst): global n n +=1 if len(lst) <=1: return lst pivot =lst[0] lst1 =[x for x in lst if x < pivot] lst2 =[x for x in lst if x == pivot] lst3 =[x for x in lst if x > pivot] return simple_qsort(lst1) + lst2 + simple_qsort(lst3) n=0 simple_qsort([10,2,6,1,3,4,5,8,7,9]) print(n)

上の数字の配列だとn=13となり再帰回数が13回であることを示しています。

現在再起呼び出し回数のできるだけ多いリストと少ないリストの配列を考えなければいけないのですが
どういった解き方をすればよいのか分かりません。ご教授いただければ幸いです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

まじめに理屈を考えるのには時間がかかるので、手抜きをして実験的にやってみました。

Angela_Nakasugiさんのコードを修正して、リストを与えると、それの再帰呼び出しの回数と結果を返す関数を作りました。

python

1def simple_qsort(lst): 2 if len(lst) <=1: 3 return 1, lst 4 pivot =lst[0] 5 lst1 =[x for x in lst if x < pivot] 6 lst2 =[x for x in lst if x == pivot] 7 lst3 =[x for x in lst if x > pivot] 8 n1, sq1 = simple_qsort(lst1) 9 n3, sq3 = simple_qsort(lst3) 10 return n1+n3+1, sq1 + lst2 + sq3

実行例

python

1>>> print(simple_qsort([10,2,6,1,3,4,5,8,7,9])) 2(13, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

次に、長さがlengthのリストを与えた時にその順列のそれぞれに対して再帰呼び出しの回数を計算して分類する関数を作ってみました。
戻り値は辞書で、再帰呼び出しの回数をキーとして、値はその回数となる順列のリストです。

python

1import itertools 2 3def count_qs(length): 4 counter = {} 5 for lst in itertools.permutations(list(range(1, length+1))): 6 n, sq = simple_qsort(lst) 7 if n in counter: 8 counter[n].append(lst) 9 else: 10 counter[n] = [lst] 11 return counter

結果が長くなって読みにくいので、リストを値として持つ辞書に対して、同じキーに対して値のリストの長さを返す関数を作りました。

python

1def counter_count(counter): 2 return {key: len(counter[key]) for key in counter}

実行例

python

1>>> counter_count(count_qs(5)) 2{9: 16, 7: 88, 5: 16}

これは、[1,2,3,4,5]の順列を並べ替えるときの再帰呼び出しの回数が9となる順列は16通り、7となる順列は88通り、5となる順列は16通りであることを示しています。

2から8までの結果を並べてみると以下になります。

python

1>>> counter_count(count_qs(2)) 2{3: 2} 3>>> counter_count(count_qs(3)) 4{5: 4, 3: 2} 5>>> counter_count(count_qs(4)) 6{7: 8, 5: 16} 7>>> counter_count(count_qs(5)) 8{9: 16, 7: 88, 5: 16} 9>>> counter_count(count_qs(6)) 10{11: 32, 9: 416, 7: 272} 11>>> counter_count(count_qs(7)) 12{13: 64, 11: 1824, 9: 2880, 7: 272} 13>>> counter_count(count_qs(8)) 14{15: 128, 13: 7680, 11: 24576, 9: 7936}

ここから、10の場合にはもっとも多い再帰呼び出しの回数が19でもっとも多い再帰呼び出しの回数が11となることが予想されます。

この予想が正しいとして、19と11となるリストを一つ出せるようにcount_qsを少し改造した以下の関数を作りました。

python

1def count_qs_sample(length, m): 2 counter = {} 3 for lst in itertools.permutations(list(range(1, length+1))): 4 n, sq = simple_qsort(lst) 5 if n == m: 6 return lst 7

これを使って実行してみると、

python

1>>> count_qs_sample(10,19) 2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 3>>> count_qs_sample(10,11) 4(1, 3, 2, 5, 4, 7, 6, 9, 8, 10)

あとは、「10の場合にはもっとも多い再帰呼び出しの回数が19でもっとも多い再帰呼び出しの回数が11となることが予想されます。」は数値的には以下のように証明できています。

python

1>>> counter_count(count_qs(10)) 2{19: 512, 17: 128512, 15: 1304832, 13: 1841152, 11: 353792}

しかし、一般化するためにはちゃんと説明する論理が必要ですね。

投稿2021/10/14 16:05

編集2021/10/14 16:13
ppaul

総合スコア24670

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

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

Angela_Nakasugi

2021/10/18 07:04

私が想像していたよりも煩雑なものだったのですね・・・ 流れが分かりやすい丁寧な説明、ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問