目次
ソートアルゴリズム
バブルソート
原理
バブル ソートは基本的なソート アルゴリズムです。基本的な考え方は、隣接する要素を比較して交換することによって、小さな要素を徐々に配列の上部に「浮かせ」、大きな要素を配列の下部に「沈ませる」ことです。具体的には、バブルソートのアルゴリズムフローは次のとおりです。
- 2 つの隣接する要素を比較します。最初のものが 2 番目のものよりも大きい場合は、位置を交換します。そうでない場合は、交換しません。
- 最初のペアから最後のペアまで、隣接する要素の各ペアに対して同じことを行い、ラウンド後に最後の要素が最大の数値になるようにします。
- 最後の要素を除くすべての要素に対して上記の手順を繰り返します。
- 比較する数値のペアがなくなるまで、要素の数を減らしながら上記の手順を繰り返します。
バブル ソートは、同じ要素の相対的な順序を変更しないため、安定したソート アルゴリズムです。ただし、時間の計算量が高いため、大規模なデータの並べ替えには適していません。
コード
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
選択範囲の並べ替え
原理
選択ソートは基本的なソート アルゴリズムです。基本的な考え方は、ソートされていない要素の中から最小 (最大) の要素を見つけて、それをソートされたシーケンスの先頭に格納し、その後引き続き残りの未ソートの要素から最小 (最大) の要素を見つけて、それをソートされたシーケンスに入れることです。シーケンスの終わり。具体的には、選択ソートのアルゴリズム フローは次のとおりです。
- ソートされていないシーケンス内で最小 (最大) の要素を見つけ、それをソートされたシーケンスの先頭に格納します。
- 次に、ソートされていない残りの要素から最小 (最大) の要素を検索し、それをソートされたシーケンスの最後に置きます。
- すべての要素が並べ替えられるまで、2 番目の手順を繰り返します。
選択ソートは、同じ要素の相対的な順序が変更される可能性があるため、不安定なソート アルゴリズムです。ただし、選択ソートの時間計算量は O(n^2)、空間計算量は O(1) で、バブル ソートよりわずかに高速ですが、大規模なデータをソートするにはまだ十分な効率が得られません。
コード
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i+1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr
挿入ソート
原理
挿入ソートは基本的なソート アルゴリズムです。基本的な考え方は、ソートされていない要素をソートされたシーケンスに 1 つずつ挿入し、新しいソートされたシーケンスを作成することです。具体的には、挿入ソートのアルゴリズム フローは次のとおりです。
- 最初の要素から始めて、要素は並べ替えられたセクションと見なすことができます。
- 次の要素をフェッチし、ソートされた一連の要素を後ろから前にスキャンします。
- (ソートされた) 要素が新しい要素より大きい場合は、要素を次の位置に移動します。
- 並べ替えられた要素が新しい要素以下になる位置が見つかるまで、手順 3 を繰り返します。
- その位置に新しい要素を挿入した後。
- 並べ替えが完了するまで手順 2 ~ 5 を繰り返します。
挿入ソートは、同じ要素の相対的な順序を変更しないため、安定したソート アルゴリズムです。挿入ソートの時間計算量は O(n^2)、空間計算量は O(1) で、バブル ソートや選択ソートよりもわずかに高速ですが、大規模なデータをソートするにはまだ十分な効率が得られません。
実装コード
def insertion_sort(arr):
n = len(arr)
for i in range(1, n):
key = arr[i]
j = i-1
while j >= 0 and key < arr[j]:
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
return arr
クイックソート
原理
クイックソートは基本的な並べ替えアルゴリズムです。基本的な考え方は、ソート パスを通じてソート対象のレコードを 2 つの独立した部分に分割し、レコードの一方の部分のキーワードがレコードのもう一方の部分のキーワードよりも小さく、その後 2 つの部分のソートを続けることです。シーケンス全体を順序付けるという目的を達成するために、それぞれのレコードを並べ替えます。具体的には、クイックソートのアルゴリズムフローは次のようになります。
- シーケンスから「ピボット」と呼ばれる要素を選択します。
- 「base」より小さい要素はすべて「base」の左側に配置され、「base」より大きい要素はすべて「base」の右側に配置され、同じ要素が配置できるように順序を並べ替えます。どちら側でも。この分割が終了すると、「ベースライン」がシーケンスの途中になります。これをパーティション操作と呼びます。
- 各サブシーケンスに要素が 1 つだけになるまで、「ベースライン」の左側のサブシーケンスと右側のサブシーケンスに対してステップ 1 と 2 を再帰的に繰り返します。
クイックソートは、同じ要素の相対的な順序が変更される可能性があるため、不安定な並べ替えアルゴリズムです。クイックソートの時間計算量は O(nlogn)、空間計算量は O(logn) です。ほとんどの場合、クイックソートは効率的な並べ替えアルゴリズムですが、最悪の場合、時間計算量は O( n^2) になります。これを避けるためには対処が必要です。
実装コード
def quick_sort(arr):
if len(arr) <= 1:
return arr
else:
pivot = arr[0]
left = []
right = []
for i in range(1, len(arr)):
if arr[i] < pivot:
left.append(arr[i])
else:
right.append(arr[i])
return quick_sort(left) + [pivot] + quick_sort(right)
マージソート
原理
マージ ソートは、ソート対象の配列を 2 つの部分に分割し、次に 2 つの部分を別々にソートし、最後にソートされた 2 つの部分を順序付けられた配列にマージする分割統治アルゴリズムです。
具体的な実装プロセスは次のとおりです。
1. ソート対象の配列を中央から左半分と右半分に分割します。
2. 各部分に 1 つの要素だけが残るまで、左半分と右半分をそれぞれ結合して並べ替えます。
3. ソートされた左半分と右半分を、順序付けられた配列にマージします。
4. 配列全体が並べ替えられるまで、手順 2 と 3 を繰り返します。
マージ ソートの計算量は O(nlogn) であり、安定したソート アルゴリズムです。
マージ ソートの空間計算量は O(n) です。ここで、n はソートされる配列の長さです。マージ ソートには、マージ プロセス中に中間結果を格納するための追加のスペースが必要で、元の配列と同じサイズのスペースを占有する必要があります。したがって、マージ ソートの空間計算量は O(n) です。
実装コード
def merge_sort(arr):
if len(arr) <= 1:
return arr
else:
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]
left = merge_sort(left)
right = merge_sort(right)
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
検索アルゴリズム
線形探索
def linear_search(arr, x):
for i in range(len(arr)):
if arr[i] == x:
return i
return -1
二分探索
原理
二分探索 (Binary Search) は、ターゲット値と配列の中間要素の比較に基づく検索アルゴリズムです。その基本的な考え方は、検索プロセス中に、ターゲット要素が見つかるか検索範囲が空になるまで、検索範囲を継続的に狭めていくというものです。
具体的な実装プロセスは次のとおりです。
1. 検索対象の配列を要素サイズの小さい順にソートします。
2. 検索範囲の左右の境界を設定します。初期状態では、左が配列の最初の要素の添字、右が配列の最後の要素の添字です。
3. 中央の要素の添え字 Mid、mid = (左 + 右) / 2 を計算します。
4. ターゲット要素 target と中間要素 arr[mid] のサイズを比較します。
a.如果target等于arr[mid],则查找成功,返回mid。
b.如果target小于arr[mid],则在左半部分继续查找,将右边界right设为mid-1。
c.如果target大于arr[mid],则在右半部分继续查找,将左边界left设为mid+1。
5. 目的の要素が見つかるか、検索範囲が空になるまで、手順 3 と 4 を繰り返します。
対象の要素が配列内に存在しない場合、最終的な検索結果は -1 を返します。
二分探索の時間計算量は O(log n) です。ここで、n は探索される配列の長さです。
実装コード
def binary_search(arr, x):
low = 0
high = len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == x:
return mid
elif arr[mid] < x:
low = mid + 1
else:
high = mid - 1
return -1
補間ルックアップ
原理
補間検索 (Interpolation Search) は、二分探索に基づく最適化アルゴリズムであり、探索範囲を推定することで目的の要素の位置を高速に特定します。補間探索では、対象要素と探索範囲の最大値・最小値の比率に応じて探索範囲内における対象要素のおおよその位置を推定し、推定結果に応じて探索範囲を調整します。そして最後に目的の要素を見つけます。
具体的な実装プロセスは次のとおりです。
1. 検索対象の配列を要素サイズの小さい順にソートします。
2. 検索範囲の左右の境界を設定します。初期状態では、左が配列の最初の要素の添字、右が配列の最後の要素の添字です。
3. 検索範囲内のターゲット要素の推定位置 pos を計算します。pos = left + (right - left) * (target - arr[left]) / (arr[right] - arr[left]) です。
4. ターゲット要素 target と推定位置 pos の要素 arr[pos] のサイズを比較します。
a.如果target等于arr[pos],则查找成功,返回pos。
b.如果target小于arr[pos],则在左半部分继续查找,将右边界right设为pos-1。
c.如果target大于arr[pos],则在右半部分继续查找,将左边界left设为pos+1。
5. 目的の要素が見つかるか、検索範囲が空になるまで、手順 3 と 4 を繰り返します。
対象の要素が配列内に存在しない場合、最終的な検索結果は -1 を返します。
内挿検索の時間計算量は O(log log n) ~ O(log n) です。ここで、n は検索対象の配列の長さです。配列内の要素が均等に分散されている場合、内挿検索の効率は非常に高くなりますが、要素が均等に分散されていない場合、内挿検索の効率は二分探索ほど良くない可能性があります。
実装コード
def interpolation_search(arr, x):
low = 0
high = len(arr) - 1
while low <= high and x >= arr[low] and x <= arr[high]:
pos = low + ((x - arr[low]) * (high - low)) // (arr[high] - arr[low])
if arr[pos] == x:
return pos
elif arr[pos] < x:
low = pos + 1
else:
high = pos - 1
return -1
フィボナッチルックアップ
原理
フィボナッチ検索は、黄金分割原理に基づいた検索アルゴリズムです。シーケンス内の隣接する 2 つの数値の比率を使用して黄金分割比を近似し、目的の要素の位置を迅速に特定します。フィボナッチ検索では、まずフィボナッチ数列を使用して増加する添字シーケンスを生成し、次にその添字シーケンスに従ってターゲット要素を見つけます。
具体的な実装プロセスは次のとおりです。
1. 検索対象の配列を要素サイズの小さい順にソートします。
2. フィボナッチ数列を使用して、fib[k] >= n となるように増加する添字シーケンス fib を生成します。ここで、n は検索する配列の長さです。
3. 検索範囲の左右の境界を左と右に設定します。初期状態では、left は配列の最初の要素の添字、right は配列の最後の要素の添字です。
4. f が現在の検索範囲の長さ以上になるように、フィボナッチ数列の k-1 番目の数値と k-2 番目の数値の合計 f を計算します。つまり、f = fib[k- 1] + fib[k -2] >= 右 - 左 + 1。
5. 探索範囲を f に応じて 2 つに分割し、前半の長さを fib[k-2]、後半の長さを fib[k-1] とします。
6. ターゲット要素 target と前半の最後の要素 arr[left+fib[k-2]-1] のサイズを比較します。
a.如果target等于arr[left+fib[k-2]-1],则查找成功,返回left+fib[k-2]-1。
b.如果target小于arr[left+fib[k-2]-1],则在前半部分继续查找,将右边界right设为left+fib[k-2]-2,同时将k减小1,f减小fib[k-1]。
c.如果target大于arr[left+fib[k-2]-1],则在后半部分继续查找,将左边界left设为left+fib[k-2],同时将k减小2,f减小fib[k-2]和fib[k-1]。
7. 目的の要素が見つかるか、検索範囲が空になるまで、手順 4 ~ 6 を繰り返します。
対象の要素が配列内に存在しない場合、最終的な検索結果は -1 を返します。
フィボナッチ検索の時間計算量は O(log n) です。ここで、n は検索対象の配列の長さです。
実装コード
def fibonacci_search(arr, x):
n = len(arr)
fib2 = 0
fib1 = 1
fib = fib2 + fib1
while fib < n:
fib2 = fib1
fib1 = fib
fib = fib2 + fib1
offset = -1
while fib > 1:
i = min(offset+fib2, n-1)
if arr[i] < x:
fib = fib1
fib1 = fib2
fib2 = fib - fib1
offset = i
elif arr[i] > x:
fib = fib2
fib1 = fib1 - fib2
fib2 = fib - fib1
else:
return i
if fib1 and offset < n-1 and arr[offset+1] == x:
return offset + 1
return -1