バブルソートに加えて、Python の組み込みソートアルゴリズムをご存知ですか?

バブルソートに加えて、Python の組み込みソートアルゴリズムをご存知ですか?

プログラミング アルゴリズムに関して、多くの読者が学校で最初に学ぶのはバブル ソートかもしれませんが、Python の組み込みソート アルゴリズム list.sort() の原理を本当にご存知ですか? これは、時間計算量が O(n log n) の高速で安定したソート アルゴリズム Timsort を使用します。このアルゴリズムの目的は、大規模な実データを処理することです。

Timsort は、実際のデータに対して非常に効率的なソート アルゴリズムです。 Tim Peters は 2001 年に Python プログラミング言語用に Timsort を作成しました。 Timsort は、まずソートしようとしているリストを分析し、その分析に基づいて適切なソリューションを選択します。

Timsort は発明されて以来、Python、Java、Android プラットフォーム、GNU Octave のデフォルトのソート アルゴリズムとなっています。

画像ソース: http://bigocheatsheet.com/

Timsort のソート時間は Mergesort と似ており、他のほとんどのソート アルゴリズムよりも高速です。 Timsort は、実際には挿入ソートとマージソートの手法を借用しています。その具体的な処理については、後ほど詳しく説明します。

Peters 氏は、実際のデータ セットに存在する「自然実行」と呼ばれる多数の順序付けられた要素を利用するために Timsort を設計しました。要約すると、Timsort は最初にすべてのデータを走査し、データ内のソートされたパーティションを見つけます。各パーティションは実行と呼ばれ、次にルールに従ってこれらの実行を 1 つにマージします。

配列の要素数が 64 未満です。

ソートする配列の要素数が 64 未満の場合、Timsort は挿入ソートを実行します。挿入ソートは、小さなリストに対して最も効率的な単純なソートです。大きなリストでは遅くなりますが、小さなリストでは速くなります。挿入ソートの考え方は次のとおりです。

  • 要素を一つずつ表示する
  • 正しい位置に要素を挿入してソートされたリストを作成します

次のトレーステーブルは、挿入ソートがリスト[34, 10, 64, 51, 32, 21]をどのようにソートするかを示しています。

この例では、左から右へのソートを開始します。太字の数字は、新しくソートされたサブ配列を表します。元の配列の各要素をソートする際に、ソートされたサブ配列を右から左に比較し、適切な位置に挿入します。挿入ソートを説明するために動画を使用します。

自然に順序付けられたブロック: 実行

リストが 64 要素より大きい場合、Timsort アルゴリズムは最初にリストを走査し、「厳密に」昇順または降順の部分を探します (実行)。セクションが減少している場合、Timsort はそのセクションを反転します。したがって、run が減少している場合は、次のようになります (run は太字で表示されます)。

減少がない場合は、次のようになります。

minrun のサイズは配列のサイズに基づいて決定されます。 Timsort アルゴリズムは、ランダム配列内のほとんどの実行が minruns になるようにこれを選択します。実行の長さ N が 2 の倍数と等しいかわずかに小さい場合、2 つの配列を結合する方が効率的です。 Timsort は、minrun が 2 の倍数と等しいか、わずかに小さいことを保証するために minrun を選択します。

アルゴリズムは minrun の範囲を 32 ~ 64 に選択します。 minrun で割ると、元の配列の長さは 2 の倍数と等しくなるか、わずかに小さくなります。

実行の長さが minrun より短い場合は、minrun から実行の長さを引いた値が計算されます。実行後に新しい要素を run (minrun - run) の外側に配置し、挿入ソートを実行して、長さが minrun と同じ新しい実行を作成できます。

minrun が 63 で、run の長さが 33 の場合、63 - 33 = 30 個の新しい要素を取得できます。そして、これらの30個の新しい要素はrunの末尾に新しい要素として追加されるため、runの34番目の要素であるrun[33]には30個の子要素があります。 ***長さ 63 の新しい実行を作成するには、最後の 30 要素に対して挿入ソートのみが必要です。

この部分が完了すると、リスト内に並べ替えられた実行セットが作成されます。

マージ

Timsort は、実行をマージするためにマージ ソートを実行する必要があり、マージ ソートの実行中に安定性とバランスが維持されるようにする必要があります。安定性を維持するために、等しい値を持つ 2 つの要素は交換しないでください。これにより、リスト内の元の位置が維持されるだけでなく、アルゴリズムも高速化されます。

Timsort が実行を見つけると、それらはスタックに追加されます。単純なスタックは次のようになります。

皿が積み重ねられているところを想像してください。皿を下から取ることはできません。上から取る必要があります。積み重ねた場合も同様です。

異なる実行をマージする場合、Timsort は 2 つの競合する要件のバランスを取ろうとします。一方では、後で出現する可能性のあるパターンを活用するために、マージをできるだけ遅らせたいと考えています。しかし、メモリ階層でまだ高いランクにある、先ほど発見した実行を活用するために、できるだけ早くマージすることを希望します。また、マージされていない実行を記憶するとメモリが消費され、スタックのサイズが固定されているため、マージを「あまり」遅らせることもできません。

妥協案を見つけるために、Timsort はスタック上の最新の 3 つの項目を追跡し、それらのスタック項目に当てはまる必要がある 2 つのルールを作成します。

  • A > B + C
  • B > C

ここで、A、B、C はスタック内の最新の 3 つの項目です。

ティム・ピーターズ自身の言葉:

良い妥協策は、スタック項目に対して 2 つの不変量を維持することです。ここで、A、B、C は、右端の 3 つのマージされていないフラグメントの長さです。

通常、長さの異なる隣接するランを結合することは困難です。さらに難しいのは、安定性を維持しなければならないことです。この問題を解決するために、Timsort は一時メモリを設定します。 2 つの実行 (runA と runB を同時に呼び出す) のうち小さい方をこの一時メモリに配置します。

GALLOPING(ギャロッピングモード)

Timsort が A と B をマージすると、1 回の実行が複数回連続して「勝利」したことに気付きます。実行 A の値が実行 B の値よりも大幅に小さい場合、実行 A は元の位置に戻ります。これら 2 つの実行をマージすると、膨大な作業量になり、何の結果も得られません。

通常、データには事前に設定された内部構造があります。 Timsort は、実行 A の値が実行 B の値よりもほとんど低い場合、A の値は B よりも低くなる可能性が高いと想定します。

その後、ティムソートはギャロップモードに入ります。 A[0]とB[0]をチェックする代わりに、TimsortはA[0]内でのB[0]の適切な位置をバイナリ検索で探します。このようにして、Timsort はセクション A 全体を所定の位置に移動できます。次に、TimsortはBでA[0]の適切な場所を検索します。その後、Timsort は B 全体を直ちに所定の位置に移動します。

TimsortはB[0](値は5)をチェックし、バイナリ検索を使用してA内の正しい位置を見つけます。

現在、B[0]はAのリストの最後にあり、TimsortはBの正しい位置にA[0](1)があるかどうかをチェックし、1の位置を確認します。この数字は B の前にあります。これで、B は A の後ろにあり、A は B の前にあることがわかります。

B[0]がAの先頭に非常に近い位置にある場合(またはその逆)、この操作は不要です。 Timsort もこれに気づき、連続する A または B の数を増やすことで、ギャロップ モードに入るしきい値を上げます。ギャロッピング モードが意味をなす場合、Timsort を使用すると、そのモードに再び入るのが簡単になります。

簡単に言うと、Timsort は次の 2 つの非常に優れた機能を備えています。

  • 内部構造があらかじめ設定されている配列はパフォーマンスが良好です
  • 安定した選別を維持できる

これまでは、安定したソートを実現するために、リスト内の項目を整数に圧縮し、タプルの配列にソートする必要がありました。

コード

以下のソース コードは、私と Nanda Javarma の作業に基づいています。ソースコードは完全ではなく、Python の公式 sort() ソースコードとも似ていません。これは私が実装した単純化された Timsort ですが、これにより Timsort の全体像を把握することができます。さらに、Python に組み込まれている Timsort アルゴリズムは C で正式に実装されているため、パフォーマンスが向上します。

Timsort のオリジナル ソース コード:

https://github.com/python/cpython/blob/master/Objects/listobject.c をご覧ください。

  1. # このコードに基づいています https://gist.github.com/nandajavarma/a3a6b62f34e74ec4c31674934327bbd3
  2. #ブランドン・スケリット
  3. # https://skerritt.tech
  4.  
  5. def binary_search(配列、項目、開始、終了):
  6. 開始== 終了の場合:
  7. the_array[start] > itemの場合:
  8. 戻る 開始
  9. それ以外:
  10. 開始 + 1 を返す
  11. 開始>終了の場合:
  12. 戻る 開始
  13.  
  14. 中間=ラウンド((開始 + 終了) / 2)
  15.  
  16. 配列[mid] <  アイテム:  
  17. バイナリ検索(配列、項目、中間 + 1、終了)を返します
  18.  
  19. elif the_array[mid] >項目:
  20. binary_search(the_array, item, start, mid - 1) を返します
  21.  
  22. それ以外:
  23. 戻る途中
  24.  
  25. 「」
  26. 配列のサイズが小さい場合や、
  27. 「実行」のサイズが小さい
  28. 「」
  29. def inserting_sort(配列):
  30. l = len (配列)
  31. 範囲(1, l)内のインデックスの場合:
  32. = the_array [インデックス]
  33. pos = binary_search (配列、値、0、インデックス - 1)
  34. the_array the_array = the_array[:pos] + [値] + the_array[pos:index] + the_array[index+1:]
  35. 配列を返す
  36.  
  37. def merge(左、右):
  38. 「2つのソートされたリストを受け取り、それらを比較して1つのソートされたリストを返します。
  39. 要素を 1 つずつ選択します。
  40. [1、2、3、4、5、6]
  41. 「」
  42. 残っていない場合:
  43. 右に戻る
  44. 正しくない場合:
  45. 左に戻る
  46. 左[0]の場合<  [0]:
  47. [left[0]] + merge(left[1:], right) を返す
  48. [right[0]] + merge(left, right[1:]) を返す
  49.  
  50. def timsort(配列):
  51. 実行、 sorted_runs = []、[]
  52. len長さ= len(配列)
  53. new_run = [the_array[0]]
  54.  
  55. # 1から配列の長さまでの範囲のすべてのiについて
  56. iが範囲(1, 長さ)内にある場合:
  57. # i がリストの末尾にある場合
  58. i == 長さ - 1 の場合:
  59. new_run.append(配列[i])
  60. 実行します。追加(new_run)
  61. 壊す
  62. # 配列のi番目の要素がその前の要素より小さい場合
  63. 配列[i] <  配列[i-1]:
  64. # new_run が None (NULL) に設定されている場合
  65. new_runでない場合は:
  66. 実行します。追加([the_array[i]])
  67. new_run.append(配列[i])
  68. それ以外:
  69. 実行します。追加(new_run)
  70. 新しい実行= []
  71. # そうでない場合、等しいかそれ以上の場合
  72. それ以外:
  73. new_run.append(配列[i])
  74.  
  75. # 実行中のすべての項目に対して、挿入ソートを使用して追加します
  76. 実行中のアイテムの場合:
  77. sorted_runs.append(挿入ソート(アイテム))
  78.  
  79. # sorted_runs 内の各実行をマージします
  80. ソートされた配列= []
  81. sorted_runs 内の実行の場合:
  82. sorted_array = merge (sorted_array, 実行)
  83.  
  84. print(ソートされた配列)
  85.  
  86. timsort([2, 3, 1, 5, 6, 7])

Timsort は実際には Python に組み込まれているため、このコードは概念的な説明としてのみ機能します。 Timsort を使用するには、Python で次のように記述するだけです。

  1. リスト.ソート()

または:

  1. ソート済み(リスト)

Timsort がどのように動作するかを把握し、理解したい場合は、ぜひ自分で実装してみることをお勧めします。

オリジナルリンク:

https://hackernoon.com/timsort-the-fastest-sorting-algorithm-youve-never-heard-of-36b28417f399

[この記事は51CTOコラム「Machine Heart」、WeChatパブリックアカウント「Machine Heart(id:almosthuman2014)」によるオリジナル翻訳です]

この著者の他の記事を読むにはここをクリックしてください

<<:  二足歩行ロボットは撮影以外にも応用シーンが多すぎて問題になっている

>>:  GoogleのAIオープンソース成果物は3年前に誕生し、想像もつかないような多くの場所で使用されている。

ブログ    
ブログ    
ブログ    

推薦する

人工知能は人間に取って代わるでしょうか?将来、誰もがスーパーパワーを持つようになると思いますか?

ここ数十年、人類の技術は驚くほど急速に発展してきました。多くの映画、テレビ番組、小説などの影響で、多...

2019年、AI技術は製造業が小さな努力で大きな成果を達成するのを助けるだろう

[[251579]] 2019 年には、新世代の人工知能 (AI) ソリューションが注目を集めるでし...

新しい特許は、Appleのリサイクルロボットが爆発するバッテリーから身を守ることができることを示している

Appleの分解ロボットとiPhoneのリサイクルプロセス全体は非常に複雑な取り組みであり、バッテリ...

人工知能の7つの主要技術、ついに誰かがわかりやすく説明してくれた

[[345456]]企業による AI の利用を複雑にする要因の 1 つは、このトピックに複数の異なる...

調査によると、2024年は「AIメガネ」市場元年となる

AppleのVision Proヘッドセットは2024年第1四半期に発売される予定だが、業界の専門家...

ドローン空気検知器は環境保護にどのように役立つのでしょうか?

大気汚染は常に国家経済と国民の健康を悩ませる重要な要因となっている。大気中の汚染物質をタイムリーかつ...

ファーウェイ、2025年のトップ10トレンドを発表:大企業の97%がAIを導入

世界の人口の58%が5Gネットワ​​ークにアクセスできるようになり、14%の家庭に「ロボット執事」が...

スマートビルディングにおけるAIの活用

[[428910]]人工知能は、スマートビルディングパズルの最も重要なピースの 1 つです。これがな...

LSTM の父は Llama 2 に中傷されて激怒しました。メタは32年前にアイデアトレーニングモデルを盗用し、ルカンに責任を求めた。

LSTM の父はまた機嫌が悪いです!何が起こっているのか?今日、ユルゲン・シュミットフーバー氏はソ...

製造業における自動化の長所と短所を探る

自動化の統合は、進化する製造業界において決定的な力となり、従来のパラダイムを再構築し、前例のない進歩...

データと人工知能の整合性をどのように確保するか?

2022 年、データと AI はデジタル革命の新たな章の基盤を築き、ますます多くのグローバル企業に...

Google の大きな動き!新しくリリースされた Cloud AutoML により、コードを書かずに AI トレーニングを完全自動化

これは大問題だ! Google が大きな動きを見せました!昨日、フェイフェイ・リーとジェフ・ディーン...

大規模機械学習フレームワークの4つのレベル

[[208759]] 1. 背景Google が GFS、MapReduce、BigTable に関...

自動運転の体験はクールで、将来的には多くの交通アルゴリズムが登場するだろう

[[229949]]若い観客が自動運転車「ファントム」を体験[[229950]] [[229951]...

IBMの人工知能システム「プロジェクト・ディベーター」が両討論会で勝利

海外メディアの報道によると、IBMは人工知能システム「プロジェクト・ディベーター」をリリースし、経験...