8種排序演算法
首先來看看排序演算法有哪八種:
1.直接插入排序
原理 :每次從無序表中取出第一個元素,把它插入到有序表的合適位置,使有序表仍然有序。
穩定的排序,最壞時間複雜性為O(n^2),空間複雜度為O(1)。
public void InsertSort<T>(T[] arry,Comparison<T> comparison)
{
//直接插入排序是將待比較的數值與它的前一個數值進行比較,所以外層迴圈是從第二個數值開始的
for (int i = 1; i < arry.Length; i++)
{
T temp = arry[i];
int j = i - 1;
// 在已排好序的數列段中找到比新數值小的數值
while (j >= 0 && comparison(arry[j] , temp) == 1)
{
//將比新數值大的數值向後移
arry[j + 1] = arry[j];
j--;
}
// 如果在已排好序的數列段中找到了比新數值小的數值
// 將數值替換到此位置
arry[j + 1] = temp;
}
}
2.希爾排序(有點疑惑網上的希爾排序都只用三個迴圈,博主是沒有理解透徹,按照原理 應該至少有四個迴圈,因為插入排序就有兩個迴圈,希望各位看官有知道的能夠為博主解惑)
原理 : 將待排序陣列按照步長gap進行分組,然後將每組的元素利用直接插入排序的方法進行排序;每次將gap折半減小,迴圈上述操作;當gap=1時,利用直接插入,完成排序。
是非穩定排序演算法
public void ShellSort<T>(T[] arry,Comparison<T> comparison)
{
int Length = arry.Length;
for (int gap = Length / 2; gap > 0; gap = gap / 2) //分組,得到組數
{
for (int i = gap; i < gap * 2; i++)//對每一組進行插入排序
{
for (int j = i; j < Length; j += gap)
{
T temp = arry[j];
int k = j - gap;
while (k >= 0 && comparison(temp , arry[k]) == -1)
{
arry[k + gap] = arry[k];
k = k - gap;
}
arry[k + gap] = temp;
}
}
}
}
---------------------
3.簡單選擇排序
原理 : 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
進行移動操作的時間複雜度為O(n)。進行比較操作的時間複雜度為O(n^2)
public void SimpleSelectSort<T>( T[] arry , Comparison<T> comparison)
{
int k = 0;
for (int i=0;i<arry.Length;i++)
{
k = i;
for (int j = i + 1;j<arry.Length;j++)
{
if(comparison(arry[k] , arry[j]) == 1)
{
k = j;
}
}
Exchange(ref arry[i],ref arry[k]);
}
}
4.堆排序
原理 : 是利用一種被稱作二叉堆的資料結構進行排序的排序演算法。
二叉堆中,有兩個與所維護陣列相關的屬性。Length表示陣列的元素個數,而HeapSize則表示二叉堆中所維護的陣列中的元素的個數(並不是陣列中的所有元素都一定是二叉堆的有效元素)。因此,根據上述定義有: 0 <= HeapSize <= Length。
二叉堆可分為最大堆和最小堆兩種型別。在最大堆中,二叉樹上所有的節點都不大於其父節點,即 A[Parent(i)] >= A[i]。最小堆正好相反:A[Parent(i)] <= A[i]。
因為在呼叫MaxHeapify(MinHeapify)方法使根節點為A[i]的二叉堆滿足最大(小)堆性質時我們有其左右子堆均已滿足最大(小)堆性質這個假設,所以如果我們在將一個待排序的陣列構造成最大(小)堆時,需要自底向上地呼叫 MaxHeapify(MinHeapify)方法。
在利用最大堆進行排序時,我們先將待排序陣列構造成一個最大堆,此時A[0](根節點)則為陣列中的最大元素,將A[0]與A[n - 1]交換,則把A[0]放到了最終正確的排序位置。然後通過將HeapSize減去1,將(交換後的)最後一個元素從堆中去掉。然後通過MaxHeapify方法將餘下的堆改造成最大堆,然後重複以上的交換。重複這一動作,直到堆中元素只有2個。則最終得到的陣列為按照升序排列的陣列。
public void HeapSort<T>(T[] array, Comparison<T> comparison)
{
BuildMHeap<T>(array, comparison);
for (int i = array.Length - 1; i > 0; i--)
{
Exchange(ref array[i], ref array[0]);
MHeapify<T>(array, 0, i, comparison);
}
}
//計算節點的父節點和子節點
private int Parrent(int i)
{
return (i - 1) / 2;
}
private int Left(int i)
{
return 2 * i + 1;
}
private int Right(int i)
{
return 2 * i + 2;
}
//構建最大堆/最小堆
private void BuildMHeap<T>(T[] array, Comparison<T> comparison)
{
for (int i = array.Length / 2 - 1; i >= 0; i--)
{
MHeapify<T>(array, i, array.Length, comparison);
}
}
private void MHeapify<T>(T[] array, int i, int heapSize, Comparison<T> comparison)
{
int left = Left(i);
int right = Right(i);
int extremumIndex = i;
if (left < heapSize && comparison(array[left], array[i]) > 0)
{
extremumIndex = left;
}
if (right < heapSize && comparison(array[right], array[extremumIndex]) > 0)
{
extremumIndex = right;
}
if (extremumIndex != i)
{
Exchange<T>(ref array[extremumIndex], ref array[i]);
MHeapify<T>(array, extremumIndex, heapSize, comparison);
}
}
5.氣泡排序
原理 : 首先將一個記錄的關鍵字和第二個關鍵字進行比較,若為逆序,則將兩個記錄交換,然後比較第2個記錄和第3個記錄的關鍵字。依次類推,直至第N-1個記錄和第n個記錄的關鍵字進行過比較為止。上述過程稱為第一趟氣泡排序,執行n-1次上述過程後,排序完成。
優缺點 :
優點:穩定 時間複雜度:理想情況下(陣列本來就是有序的),此時最好的時間複雜度為o(n),最壞的時間複雜度(資料反序的),此時的時間複雜度為o(n*n) 。 氣泡排序的平均時間負責度為o(n*n).
缺點:慢,每次只移動相鄰的兩個元素。
public void BubbleSort<T>( T[] array,Comparison<T> comparison)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - 1 - i; j++)
{
//比較相鄰的兩個元素,如果前面的比後面的大,則交換位置
if (comparison(array[j] , array[j + 1]) == 1)
{
Exchange(ref array[j],ref array[j + 1]);
}
}
}
}
6.快速排序
原理 : 快速排序法是採用遞迴的方式對待排序的數列進行若干次的操作,每次操作使得被操作的數列部分以某個元素為分界值分成兩部分,一部分小於該分界值,另一部分大於該分界值.該分界值一般被稱為"樞軸". 一般先以左邊第一個數作為分界值,將數列按該分界值分成左右兩部分,左邊部分小於該分界值,右邊部分大於該分界值,然後再對左右兩部分做重複的操作,直到最後完成排序。
快速排序是一種不穩定的排序演算法
public void QuickSort<T>(T[] array, Comparison<T> comparison, int left, int right)
{
//左邊小於右邊說明排序還沒有完成
if (left < right)
{
T middle = array[(left + right) / 2];
//注意初始化
int j = right + 1;
int i = left - 1;
while (true)
{
while (comparison(middle, array[++i]) > 0 && i < right) ;//左邊,先加的原因是防止找到的最左邊會超出界限
while (comparison(middle, array[--j]) < 0 && j > 0) ; //右邊
if (i >= j)
break;
Exchange<T>(ref array[i], ref array[j]);
}
for (int m = 0; m < array.Length; m++)
{
Console.Write(array[m] + " ");
}
Console.ReadLine();
QuickSort<T>(array, comparison, left, i - 1);
QuickSort<T>(array, comparison, j + 1, right);
}
}
7.歸併排序
是分治法(Divide and Conquer)的一個非常典型的應用
原理 : 設歸併排序的當前區間是R[low..high],分治法的三個步驟是:
①分解:將當前區間一分為二,即求分裂點
②求解:遞迴地對兩個子區間R[low..mid]和R[mid+1..high]進行歸併排序;
③組合:將已排序的兩個子區間R[low..mid]和R[mid+1..high]歸併為一個有序的區間R[low..high]。
遞迴的終結條件:子區間長度為1(一個記錄自然有序)。
public void MergeSortFunction<T>(T[] array, Comparison<T> comparison, int first, int last)
{
try
{
if (first < last) //子表的長度大於1,則進入下面的遞迴處理
{
int mid = (first + last) / 2; //子表劃分的位置
MergeSortFunction(array,comparison, first, mid); //對劃分出來的左側子表進行遞迴劃分
MergeSortFunction(array, comparison, mid + 1, last); //對劃分出來的右側子表進行遞迴劃分
MergeSortCore(array, comparison, first, mid, last); //對左右子表進行有序的整合(歸併排序的核心部分)
}
}
catch (Exception ex)
{ }
}
//歸併排序的核心部分:將兩個有序的左右子表(以mid區分),合併成一個有序的表
private void MergeSortCore<T>(T[] array, Comparison<T> comparison, int first, int mid, int last)
{
try
{
int indexA = first; //左側子表的起始位置
int indexB = mid + 1; //右側子表的起始位置
T[] temp = new T[last + 1]; //宣告陣列(暫存左右子表的所有有序數列):長度等於左右子表的長度之和。
int tempIndex = 0;
while (indexA <= mid && indexB <= last) //進行左右子表的遍歷,如果其中有一個子表遍歷完,則跳出迴圈
{
if (comparison(array[indexA] , array[indexB]) <= 0) //此時左子表的數 <= 右子表的數
{
temp[tempIndex++] = array[indexA++]; //將左子表的數放入暫存陣列中,遍歷左子表下標++
}
else//此時左子表的數 > 右子表的數
{
temp[tempIndex++] = array[indexB++]; //將右子表的數放入暫存陣列中,遍歷右子表下標++
}
}
//有一側子表遍歷完後,跳出迴圈,將另外一側子表剩下的數一次放入暫存陣列中(有序)
while (indexA <= mid)
{
temp[tempIndex++] = array[indexA++];
}
while (indexB <= last)
{
temp[tempIndex++] = array[indexB++];
}
//將暫存陣列中有序的數列寫入目標陣列的制定位置,使進行歸併的陣列段有序
tempIndex = 0;
for (int i = first; i <= last; i++)
{
array[i] = temp[tempIndex++];
}
}
catch (Exception ex)
{ }
}
8.基數排序
屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,演算法的時間複雜度是O(n)
public static void RadixSort( int[] array, int array_x = 10, int array_y = 100)
{
/* 最大數字不超過999999999...(array_x個9) */
for (int i = 0; i < array_x; i++)
{
int[,] bucket = new int[array_x, array_y];
foreach (var item in array)
{
int temp = (item / (int)Math.Pow(10, i)) % 10;
for (int l = 0; l < array_y; l++)
{
if (bucket[temp, l] == 0)
{
bucket[temp, l] = item;
break;
}
}
}
for (int o = 0, x = 0; x < array_x; x++)
{
for (int y = 0; y < array_y; y++)
{
if (bucket[x, y] == 0) continue;
array[o++] = bucket[x, y];
}
}
}
}
輔助函式:
#region 交換值
public void Exchange<T>(ref T x, ref T y)
{
T temp = x;
x = y;
y = temp;
}
#endregion
#region 比較兩個int的值
public int ComparisonInt(int x,int y)
{
if(x > y)
{
return 1;
}
else if(x == y)
{
return 0;
}
else
{
return -1;
}
}
#endregion
原始碼地址:
https://github.com/webloverand/Interview
參考列表:
1.資料結構常見的八大排序演算法(詳細整理): https://www.cnblogs.com/hokky/p/8529042.html
2.堆排序——C#實現 : https://blog.csdn.net/zhuo_wp/article/details/78251777
3.歸併排序演算法(C#實現): https://www.cnblogs.com/mingmingruyuedlut/archive/2011/08/18/2144984.html
相關文章
- nyoj 8 一種排序排序
- 7種排序演算法排序演算法
- 用 Java 實現常見的 8 種內部排序演算法Java排序演算法
- C#常用8種排序演算法實現以及原理簡介C#排序演算法
- 八種常用排序演算法排序演算法
- 幾種常用的排序演算法排序演算法
- 三種快速排序演算法以及快速排序的優化排序演算法優化
- php實現4種排序演算法PHP排序演算法
- JavaScript中的多種排序演算法JavaScript排序演算法
- 幾種經典的排序演算法排序演算法
- php常用的四種排序演算法PHP排序演算法
- Python各種排序演算法整理Python排序演算法
- PHP四種基本排序演算法示例PHP排序演算法
- 多種排序演算法的效率觀察排序演算法
- 【演算法】Java實現七種常用排序演算法演算法Java排序
- 漫畫:三種 “奇葩” 的排序演算法排序演算法
- 九種排序演算法的 JavaScript 實現排序演算法JavaScript
- JavaScript實現的7種排序演算法JavaScript排序演算法
- 三種高階比較排序演算法排序演算法
- 簡述幾種常用的排序演算法排序演算法
- 幾種常見排序演算法總結排序演算法
- PHP實現四種基本排序演算法PHP排序演算法
- js實現兩種實用的排序演算法——冒泡、快速排序JS排序演算法
- 快速掌握Java幾種排序演算法的區別與排序演算法的應用Java排序演算法
- Swift實現八種經典排序演算法Swift排序演算法
- 35.幾種常見的排序演算法排序演算法
- 帶你掌握4種Python 排序演算法Python排序演算法
- python實現常用五種排序演算法Python排序演算法
- 10種python常見的排序演算法!Python排序演算法
- 幾種常見的排序演算法總結排序演算法
- javascript排序各種演算法例項程式碼JavaScript排序演算法
- 用 python 實現各種排序演算法Python排序演算法
- 5種排序演算法效能比較總結排序演算法
- 聽聽各種排序演算法的聲音排序演算法
- 【資料結構與演算法】內部排序總結(附各種排序演算法原始碼)資料結構演算法排序原始碼
- 關於js陣列的六種演算法---水桶排序,氣泡排序,選擇排序,快速排序,插入排序,希爾排序的理解。JS陣列演算法排序
- 複習資料結構:排序演算法(五)——快速排序的各種版本資料結構排序演算法
- 幾種常用的排序演算法之JavaScript實現排序演算法JavaScript