はじめに:
アルゴリズムをソートする私たちが遭遇したほとんどのプログラミングアルゴリズムです。現在主流のアルゴリズムの8種類があります。
平均時間複雑さの降順は、次のとおりです。
バブルソート(O(N 2))、選択ソート(O(N 2))、挿入ソート(O(N 2))、ヒープソート(O(nlogn))、
マージソート(O(nlogn))、クイックソート(O(nlogn))、ヒルソーティング(O(N 1.25))、基数ソート(O(N))
免責事項:すべての配列{25、1、5、2、9、11、2、4}について以下の順序、 ノートを使用して、すべてのテストは、単にユーザが理解した後に削除することができる結果、より意識を参照できるようにします。
まず、バブルソート:
アイデア:配列、各要素およびその次の比較、ループの各反復は、位置を決定することができた後に、バックに大きな変化から最初のスタート。効率を改善する(交換が直接サイクルの終了後に行われない場合は、マークを定義します)
コード:
静的 ボイドmaopao() { INT [] = 新しい INTを [] { 25、1、5、2、9、11、2、4 }。 ブール記号= 偽; 以下のために(INT iが= 0 ; I <a.Length - 1 ; I ++ ) { ため(INT J = 0 ; J <a.Length - 、I - 1、J ++ ) { IF(A [J]> A [J + 1 ]) { (A、OUTPUTS " 切り替え前の"); // テストが使用 Console.Writeを(String.Formatの(" {0:}のD2 < -交換- > {1 :}のD2 "、A [J]、A [+ J 1。 ])); // テスト用途 INT B = ; A [J] A [J] = A [+ J 1。]、 A [J + 1 ] = B; ・サイン = trueに。 出力(A、" スワッピングの後に"); // 使用してテストし ます。Console.WriteLineを(); // テスト用途 } } のIF(チェック!)BREAK ; } ; Console.WriteLineを()// テストを使用して 、出力(Aを」、そして最後にデータ" ); Console.ReadKey(); } プライベート 静的 ボイド出力(INT [] A、文字列STR) { Console.Write(STR + " :"); foreachの(VARの項目で) { Console.Write(項目 + " " )。 } }
結果:
第二に、ソートを選択:
バブルソート一方のみが位置を決定することができ、その後、どのように周期交換を達成するために、結果は、25回連続のために交換することによって見ることができる、最適化されていますか?
思想:(最初のパスは、アレイを介して検索が最小値を見つけるために最小の例、すなわちここで昇順または最大)、次いで配列番号0内の位置に配置され、第二のパス、N-1の検索アレイに次に、最小を見つけるレコード(配列全体が小さい時間である)、と第1アレイ位置に置か。(i番目の小アレイ全体のために、それが)、次いでI-1アレイの(音符0からアレイまでその位置に配置されたi番目の時間、N-I + 1つのレコードの検索配列が、最小レコードを検索する場合)から始まります。
コード:
private static void xuanze() { int[] a = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; for (int i = 0; i < a.Length - 1; i++) { int sign = i; for (int j = i + 1; j < a.Length; j++) { if (a[sign] > a[j]) { sign = j; } } if (sign != i) { outPuts(a, "交换之前");//测试使用 Console.Write(String.Format(" {0:D2}<-交换->{1:D2} ", a[i], a[sign]));//测试使用 int b = a[i]; a[i] = a[sign]; a[sign] = b; outPuts(a, "交换之后");//测试使用 Console.WriteLine();//测试使用 } } Console.WriteLine();//测试使用 outPuts(a, "最后数据"); Console.ReadKey(); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
结果:
三、插入排序:
插入排序是一种对于有序数列高效的排序。非常聪明的排序。只是对于随机数列,效率一般,交换的频率高。
思想:数组下标1开始,和前面下标为0的数据作比较,如果下标0的数据大于(或小于即从大到小排序)下标1的数据则后移,下标1的数据插入到0的位置,否则插入当前位置。数组下标m开始,和所以前面数据作比较,即下标为n(m-1>=n>=0)的数据作比较,如果下标n的数据大于(或小于即从大到小排序)下标m的数据则后移,直到n=-1,将下标为m得到数据插入到下标为0的位置,否则插入当前位置,
代码:
private static void charu() { int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; for (int i = 1; i < data.Length; i++) { int d = data[i]; bool result = true;//标记,表示已经比较到第一个位置 for (int j = i - 1; j >= 0; j--) { if (data[j] > d) { outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" 从下标{0}开始 {1}<-移动->{2} ",i, j, j+1));//测试使用 data[j + 1] = data[j]; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 } else { outPuts(data, "插入之前");//测试使用 Console.Write(String.Format(" 从下标{0}开始 数据{1}<-插入到->{2} ", i, d, j + 1));//测试使用 data[j + 1] = d; result = false; outPuts(data, "插入之后");//测试使用 Console.WriteLine();//测试使用 break; } } if (result) { outPuts(data, "插入之前");//测试使用 Console.Write(String.Format(" 数据{0}<-插入到->{1} ", d, 0));//测试使用 data[0] = d; outPuts(data, "插入之后");//测试使用 Console.WriteLine();//测试使用 } } Console.WriteLine();//测试使用 outPuts(data, "最后数据"); Console.ReadKey(); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
//方法二 private static void charu2(int[] data) { int j; for (int i = 1; i < data.Length; i++) { int d = data[i]; for (j = i - 1; j >= 0 && data[j] > d; j--) { data[j + 1] = data[j]; } data[j + 1] = d; } }
结果:
四、快速排序:
快速排序是一种高效排序。它包含了“分而治之”以及“哨兵”的思想。
思想:从数组中挑选一个数(一般为第一个数据)作为“哨兵”,使比它小的放在它的左侧,比它大的放在它的右侧。
说明:25为哨兵,定义变量保存,0位置为待处理位置,从right向前找直到找到比哨兵小的,将其放入到待处理位置,left++,并设置当前为待处理位置,从left开始向后找比哨兵大的放入待处理位置,right--,并设置当前为待处理位置。直到left>right结束,此时第一个哨兵位置确定。并以哨兵为点,将数组分为两段分别继续递归实现该方法。
代码:
private static void kuaisu(int[] data, int left, int right) { if (left >= right) return; int x = data[left]; int i = left; int j = right; try { while (i < j) { while (i < j && data[j] >= x) { j--; } if (i == j) break; outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" {0}<-移动到->{1} ", j, i));//测试使用 data[i++] = data[j]; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 while (i < j && data[i] <= x) { i++; } if (i == j) break; outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" {0}<-移动到->{1} ", i, j));//测试使用 data[j--] = data[i]; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 } outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" 数据{0}<-移动到->{1} 数据区间{2}--{3} ", x, i,left,right));//测试使用 data[i] = x; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 kuaisu(data, left, i - 1); kuaisu(data, i + 1, right); } catch (Exception e) { Console.WriteLine(e); } } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
结果:
五、归并排序:
使用递归方法。
思想:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
那么如何确定一个子序列有序呢?当然子序列个数为1时自然有序。所以将数组分为两段,一直分段递归下去,直到数组长度为1返回,此时将其归并直到结束。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
代码:
int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; guibing(data, 0, data.Length - 1); outPuts(data, "最后数据"); Console.ReadKey();
private static void guibing(int[] data, int left, int right) { if (left < right) { int mid = (left + right) / 2; guibing(data, left, mid); guibing(data, mid + 1, right); arrayAdd(data, left, mid, right); } } private static void arrayAdd(int[] data, int left, int mid, int right) { int[] d = new int[right - left + 1]; int i = left; int j = mid + 1; int k = 0; while (i <= mid && j <= right) { if (data[j] < data[i]) d[k++] = data[j++]; else d[k++] = data[i++]; } while (i <= mid) { d[k++] = data[i++]; } while (j <= right) { d[k++] = data[j++]; } i = left; for (k = 0; k < d.Length; k++) { outPuts(data, "赋值之前");//测试使用 Console.Write(" ");//测试使用 data[i++] = d[k]; outPuts(data, "赋值之后");//测试使用 Console.Write(String.Format(" 赋值下标位置范围{0}--{1} 临时数组:",left,right));//测试使用 foreach (int f in d) //测试使用 { Console.Write(f + " "); } Console.WriteLine();//测试使用 } } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
结果:
六、希尔排序:
希尔排序是插入排序的一种更高效的改进版本。
思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个数列恰被分成一组,算法便终止。
增量算法有:https://blog.csdn.net/foliciatarier/article/details/53891144
本文以:Hibbard 增量序列为例
代码:
int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; xier(data);
private static void xier(int[] data) { List<int> garArry = new List<int>(); int m = 0; while (Math.Pow(2,m) - 1 <= data.Length / 2) { m++; garArry.Add((int)Math.Pow(2, m) - 1); } for (int y = garArry.Count - 1; y >= 0; y--) { int gap = garArry[y]; int j; //比较次数 for (int i = gap; i < data.Length; i++) { int d = data[i]; for (j = i - gap; j >= 0 && data[j] > d; j -= gap) { outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" {0}<-移动到->{1} 步长{2} ", j, j + gap, gap));//测试使用 data[j + gap] = data[j]; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 } outPuts(data, "移动之前");//测试使用 Console.Write(String.Format(" 数据{0}<-移动到->{1} 步长{2} ", d, j + gap, gap));//测试使用 data[j + gap] = d; outPuts(data, "移动之后");//测试使用 Console.WriteLine();//测试使用 } } outPuts(data, "最后数据"); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
结果:
后续添加更多排序方法