みなさん、こんにちは、私は、時間の選択リニア電流シェアでも人間ではないんです。
線形時間の選択が基づいている高速の注文拡張アプリケーション、同様の場所で自然と速く行の1種類。その目的は、kの小さな値のこの配列を見つけることです。
今だけ値を見つける必要があり、我々はないソート配列全体になります。分割統治とパーティション(パーティション)で検索する場所の範囲kの値のみができます。
もちろん、あなたは、kの範囲を確立するための二分法を使用することができ、しかしので、今日は私の本を議論していないではありません。
ランダムに選択し、中央の選択:ここでは、2つのアルゴリズムがあります。
ランダム選択
ランダム選択は、ランダムにK <= pは、現在の動作のために放置した場合、この数pの位置kとの間の関係を決定する、パーティションアレイ動作のこの数と、数で現在のプロセスアレイにおいて選択され、その逆れます操作の右側には、パーティションのアイデアを具現化しています。
たとえば。
3番目に小さいデジタルを探します
1,5,7,2,4,8,6
基準として選んだ7
パーティションの後:
1,5,6,2,4,7,8
6,3位置7が<6であり、それがあろう
1,5,6,2,4,7
この操作は、アレイは、ただ1つの数は、所望されるまで
すなわち、ランダムに再びすべての要素をトラバースするのに必要な(最大値を探している場合、例えば、常に最小値で割った)最悪の場合に選択することができ、Oは、(N-必要と2回)。それにも関わらず、アルゴリズムの平均パフォーマンスは非常に良いです。ランダム選択アルゴリズムは、平均時間はO(n)におけるk小さい入力エレメントのn番目の要素を見つけることができることを示すことができます。
彼は、はい、スパイシーが、とにかく、私は許さないだろうと述べています。
以下のコードを貼り付けます。
import random
def partition(a, left, right):
i = left
j = right
key = a[left]
while i < j:
while a[j] >= key and i < j:
j -= 1
a[i] = a[j]
while a[i] <= key and i < j:
i += 1
a[j] = a[i]
a[i] = key
return i
def randomized_partition(a, left, right):
if left > right: # 为了保护randint函数的
i = random.randint(left, right)
a[i], a[left] = a[left], a[i]
return partition(a, left, right)
def randomized_select(a, left, right, k):
if left == right:
return a[left]
i = randomized_partition(a, left, right)
j = i - left + 1
if k <= j:
return randomized_select(a, left, i, k)
else:
return randomized_select(a, i + 1, right, k)
number = random.randint(60, 80)
array = []
for i in range(0, number):
array.append(random.randint(0, 2*number))
print("一共生成了" + str(number) + "个数")
print("他们是:")
print(array)
k = input("你要查找第几小的数字?")
print(randomized_select(array, 0, number - 1, int(k)))
中央値の選択
このアルゴリズムは、最悪の場合、O(n)の時間で完了タスクを選択することができます。
このアルゴリズムは、以下の工程によって達成されます。
5のグループにいくつかのグループに分け①アレイ、各々が、最後のグループは、5未満であってもよいです。
②各グループをソート、中央値を除去しました。
③標準としてこの結果を分割するためにこれらの中央値の中央値を識別します。
私は75以上の中央値の配列が再び中央値はまだ第三のステップで動作して取っていた持っています。
このアルゴリズムについては、我々は別の例を与えます。
1,4,2,5,10,7,3,11,6,14,18,8,9,13
最初の数14の場合は、理解を容易にします。
まず、これらの14の数は、5のグループに分類されています。記載されている最後のグループは4白羽。
{1,4,2,5,10}、{7,3,11,6,14}、{18,8,9,13}
各グループの並べ替え操作が与えるために
{1,2,4,5,10}、{3,6,7,11,14}、{8,9,13,18}
各グループの中央値が取り出され、得た(通常はフロントまでの平均為替スイッチングのスペースを節約するために使用)
4,7,9
そして、ソートの中央値(この例では、自動的に並んでいるが)
7の中央値は、基準となる元のパーティションアレイ7によって、除去されます。
場所と関係K 7を決定し、kはイデオロギー分割統治を反映し、左側の左側に選択し続け、そして選択の権利のためにその逆になります。
中央値濃度が、私は、しかし、新しくオープンしたの配列「最前線の中央値の変更」を使用していなかった場合は、これは、コードをより理解しやすくすることができますが、欠点は、スペースの消費量を増やすことです。
import random
def sort(a, l, r): # 冒泡排序
for i in range(l, r + 1):
for j in reversed(range(i, r + 1)):
if a[i] >= a[j]:
a[i], a[j] = a[j], a[i]
def partition(a, left, right, x): # 分区,这里不解释了
i = left
j = right
while i < j:
while a[j] > x and i < j:
j -= 1
while a[i] < x and i < j:
i += 1
a[i], a[j] = a[j], a[i]
return i
def find_mid(a, l, r):
if r - l < 75:
sort(a, l, r)
return a[(l + r) // 2]
else:
b = [] # 存储中位数的数组
i = l
while True:
if 5 * i + 4 <= r: # 判断是否为最后一组
sort(a, 5 * i, 5 * i + 4)
b.append(a[5 * i + 2])
else:
sort(a, 5 * i, r)
b.append(a[(5 * i + r) // 2])
break
i += 1
return find_mid(b, 0, len(b) - 1)
def select(a, l, r, k):
if r - l < 75:
sort(a, l, r)
return a[l + k - 1]
else:
mid_number = find_mid(a, l, r)
mid_position = partition(a, l, r, mid_number)
if k > mid_position:
return select(a, mid_position + 1, r, k)
else:
return select(a, l, mid_position, k)
number = random.randint(150, 200)
array = []
for i in range(0, number):
array.append(random.randint(0, number * 2))
print(array)
print("生成了" + str(number) + "个数")
k = input('输入想要第几小的数字')
print(select(array, 0, number - 1, int(k)))
再現は、ソースを示します。