ソートアルゴリズム
一般的な並べ替えアルゴリズム
ソートアルゴリズムの時間計算量
ソートアルゴリズム | 平均時間 | 最悪の時期 | 安定 | 空間の複雑さ | 述べる |
---|---|---|---|---|---|
バブルソート | O(n2) | O(n2) | 安定させる | ○(1) | n が小さいほど良い |
並べ替え | O(n2) | O(n2) | 不安定な | O(1) n | 小さいときは良い |
選択ソート | O(n2) | O(n2) | 不安定な | O(1) n | 小さいときは良い |
挿入ソート | O(n2) | O(n2) | 安定させる | ○(1) | ほとんど順番通りに |
基数ソート | O(n*k) | O(n*k) | 安定させる | の上) | 2次元配列(バケット)、1次元配列(バケット内の最初の要素の位置) |
ヒルソート | O(nlogn) | O(ns)(1<s<2) | 不安定な | ○(1) | s は選択されたグループです |
クイックソート | O(nlogn) | O(n2) | 不安定な | O(ログン) | nが大きいほど良い |
マージソート | O(nlogn) | O(nlogn) | 安定させる | ○(1) | nが大きいほど良い |
ヒープソート | O(nlogn) | O(nlogn) | 不安定な | ○(1) | nが大きいほど良い |
バブルソート
1 はじめに
バブル ソートは、コンピューター サイエンスの分野における比較的単純な並べ替えアルゴリズムです。
ソート対象の要素の列を繰り返し訪問し、隣接する 2 つの要素を順番に比較し、順序 (大から小、頭文字 Z から A など) が間違っている場合は要素を交換します。要素を訪問する作業は、隣接する要素を交換する必要がなくなるまで、つまり要素列がソートされるまで繰り返されます。
このアルゴリズムの名前は、ちょうど炭酸飲料の二酸化炭素の泡が最終的に上部に浮かぶのと同じように、より小さい要素が交換によってシーケンスの上部に (昇順または降順で) ゆっくりと「浮く」という事実に由来しています。したがって、「バブリング」という名前が付けられています。
2. 思考分析
- 2 つの隣接する要素を比較し、最初の要素が 2 番目の要素より大きい場合は、位置を交換します。
- 最後の要素が最初のサイクルを終了するまで、後続の各要素に対してこの操作を実行します。これにより、最後の要素は次のようになります。最大の要素したがって、後続のループ比較で最後の要素を比較する必要はありません。
- 除外するには上記の手順を繰り返します前のループの最後の要素、それで内側のループますます少なくなるでしょう
- 比較する数値のペアがなくなるまで
- 外側のループ回数は配列要素の数 - 1であり、 == 内部ループの比較の数は回を重ねるごとに小さくなります –
- 最適化: 特定の場合要素は外側のループ内で交換されません。、すでに順序付けられた配列であることが証明されたら、ループを終了できます。
3. 図表
1. 最初のサイクル (黄色は交換位置、赤色は最終位置を表します)
2. 2 番目のサイクル
3. 3 番目のサイクル
4. 4番目のサイクル
エンドループ
4. コードの実装
/**
* 冒泡排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Bubbling {
public static void main(String[] args) {
int[] arr = {
3,9,-1,7,21};
// 外层循环次数为数组的长度-1
for (int i = 0; i < arr.length - 1; i++) {
// 内层循环次数,每次都会减少
for (int j = 0; j < arr.length - 1 - i; j++) {
// 交换位置
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
最適化: 特定の外側ループの終了後に配列要素の位置が変わっていないことが判明した場合、ループは終了し、すでに順序付けされた配列になります。
コード:
/**
* 冒泡排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Bubbling {
public static void main(String[] args) {
int[] arr = {
3,9,-1,7,21};
// 外层循环次数为数组的长度-1
for (int i = 0; i < arr.length - 1; i++) {
// 如果内层循环没有交换位置,那么已经是有序数组,结束循环
boolean flag = true;
// 内层循环次数,每次都会减少
for (int j = 0; j < arr.length - 1 - i; j++) {
// 交换位置
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if (flag){
break;
}
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
選択ソート
1 はじめに
選択ソートは、シンプルで直感的なソート アルゴリズムです。その動作原理は次のとおりです。最初に並べ替えるデータ要素から最小 (または最大) 要素を選択し、それをシーケンスの開始位置に格納し、その後、並べ替えられていない残りの要素から最小 (最大) 要素を見つけます。そしてそれをソートされたシーケンスの最後に置きます。ソートされるすべてのデータ要素の数がゼロになるまで、同様に続きます。選択ソートは不安定なソート方法です。
2. 思考分析
2.1 初めてデータを交換する
/**
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Deduction {
public static void main(String[] args) {
int[] arr = {
8,3,2,1,7,4,6,5};
// 记录最小数的下标
int min;
// 假设min=0开始
min = 0;
// 既然我们都假设下标为0的是最小,那么就从他后面开始比较
for (int i = 1; i < arr.length; i++) {
// 如果后面的元素中有小于的元素,记住的他下标
if (arr[min] > arr[i]){
min = i;
}
}
// 交换
int temp = arr[0];
arr[0] = arr[min];
arr[min] = temp;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 打印获取到 1 3 2 8 7 4 6 5
}
}
2.2 2回目はi+1から開始
/**
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Deduction {
public static void main(String[] args) {
// int[] arr = {8,3,2,1,7,4,6,5};
int[] arr = {
1,3,2,8,7,4,6,5};
// 记录最小数的下标
int min;
// 假设min=1开始
min = 1;
// 既然我们都假设下标为1的是最小,那么就从他后面开始比较
for (int i = 2; i < arr.length; i++) {
// 如果后面的元素中有小于的元素,记住的他下标
if (arr[min] > arr[i]){
min = i;
}
}
// 交换
int temp = arr[1];
arr[1] = arr[min];
arr[min] = temp;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 打印获取到 1 2 3 8 7 4 6 5
}
}
等々
2.3 概要
- 私は0から始めると仮定しますmin は最小値のインデックスを表します、当初想定した分 = 私、 それから次の配列の最小要素の添え字を見つけます。min = minIndex とし、位置を交換します。最小のインデックス添え字を探す場合、他の要素の位置は移動できないことに注意してください。
- 次に、配列は逆方向に移動します。最初の数値はすでに最小の数値であるため、i+1 から開始して比較する必要はありません。
- 並べ替えが終了するまで上記の手順を繰り返します
- 配列の長さの合計 1 回の走査が必要です。
3. 図表
4. コードの実装
/**
* 选择排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Choice {
public static void main(String[] args) {
int[] arr = {
8,3,2,1,7,4,6,5};
// 记录最小数的下标
int min;
// 外层循环次数为数组长度 - 1
for (int i = 0; i < arr.length - 1; i++) {
min = i;
// 内层循环每次都是从i+1开始
for (int j = i+1; j < arr.length; j++) {
// 找出最小数的下标
if (arr[min] > arr[j]){
min = j;
}
}
// 如果不是同一个数,那么就交换位置
if (min != i){
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
挿入ソート
1 はじめに
挿入ソートは、一般に直接挿入ソートとも呼ばれます。これは、少数の要素を並べ替える場合に効率的なアルゴリズムです。挿入ソートは最も単純なソート方法であり、その基本的な考え方はレコードをソートされた順序付きリストで, これにより、レコード数が 1 ずつ増加する新しい順序付きリストが作成されます。実装処理では2層ループを使用しており、外側のループで最初の要素を除くすべての要素を検索し、内側のループで現在の要素の前の順序付きリストに挿入する位置を検索して移動します。 。
2. 思考分析
- なぜなら元の配列は最初の要素として順序付きリストの最初の要素したがって、順序付きリストの最後の要素と比較する要素として 1 が挿入される場合、インデックス 1 の要素から直接開始します。
- もしも以下の要素を挿入します、次に順序付きリストに最後の要素は 1 ビット後方にシフトされます順序付けされたリスト内で要素が挿入された要素以下の位置が見つかるまで、またはインデックスが 0 より小さい、比較を終了します
- 次に、挿入した要素を割り当てます
3. 図表
ここでの赤い配列は、すでに順序付けられたリスト要素を表していることに注意してください。
3.1 第 1 ラウンド
3.2 第 2 ラウンド
3.3 第 3 ラウンド
3.4 第 4 ラウンド
4. コードの実装
/**
* 插入排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/9
*/
public class InsertSorted {
public static void main(String[] args) {
int[] arr = {
3, 1, 6, 10, 2};
for (int i = 1; i < arr.length; i++) {
// 保留即将插入元素的值
int insertValue = arr[i];
// 当前索引
int index = i;
// 1.如果索引大于0,说明还没遍历完
// 2.如果插入的值小于有序列表中的值,那么久有序列表中大于插入元素的元素,就要后移
while (index > 0 && insertValue < arr[index-1]){
arr[index] = arr[index-1];
index --;
}
// 直到找到插入元素不大于有序列表中元素的位置
arr[index] = insertValue;
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
ヒルソート
1 はじめに
シェルのソートは、「ディミニシング インクリメント ソート」としても知られる挿入ソートの一種で、直接挿入ソート アルゴリズムのより効率的かつ改良されたバージョンです。ヒル ソートは不安定なソート アルゴリズムです。
ヒル ソートでは、添字の特定の増分によってレコードをグループ化し、直接挿入ソート アルゴリズムを使用して各グループをソートします。増分が徐々に減少するにつれて、各グループにはますます多くのキーワードが含まれます。増分が 1 に減少すると、データ全体が 1 つのグループに分割された時点で、アルゴリズムは終了します。
2. 思考分析
- インクリメンタルシーケンス t1 (通常、配列の長さ/2)、t2 (通常、グループの長さ/2)、...、tk を選択します。ここで、ti > tj、tk = 1。
- 増分シーケンス番号 k に従って、シーケンスを k 回ソートします。
- 各ソートでは、対応する増分 ti に従って、ソート対象の列が長さ m のいくつかのサブシーケンスに分割され、各サブリストに対して直接挿入ソートがそれぞれ実行されます。インクリメント係数が 1 の場合のみ、シーケンス全体がテーブルとして扱われ、テーブルの長さがシーケンス全体の長さになります。
3. 図表
3.1 第 1 ラウンド
増分は 3 で、比較は arr[3] から直接開始され、arr[3] > arr[0]、位置を変更する必要がなく、arr[4] < arr[1] であることがわかります。位置を変更する必要があるので、
比較を続行してください
arr[6]<arr[3] まで位置を交換する
と、index-gap >= 0 であれば比較を継続できるため、arr[3] を arr[0] と比較できることがわかります。
3.2 第 2 ラウンド
arr[1] から比較を開始し、arr[6] < arr[5] になるまで 1 つずつ逆方向に比較します。
位置を交換した後、arr[5]とarr[4]を比較し、位置を交換します
終了
4. コードの実装
/**
* 希尔排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/9
*/
public class ShellInsert {
public static void main(String[] args) {
int[] arr = {
23,34,21,31,18,98,10};
// 增量
int gap = arr.length/2;
// 只要增量大于等于1就继续分组
while (gap >= 1){
// 从索引=增量开始,依次往后
for (int i = gap; i < arr.length; i++) {
// 定义一个变量,防止下面代码影响原 i 的值
int j = i;
// 只有 arr[j] < arr[j-gap] 交换位置 ,而且可能一次不一定能比较完,需要多次比较 j-gap >= 0
while (j-gap >= 0 && arr[j] < arr[j-gap]){
// 交换
int temp = arr[j];
arr[j] = arr[j-gap];
arr[j-gap] = temp;
// 假设 j = 6 时,可以多次执行
j -= gap;
}
}
// 控制增量
gap /= 2;
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}