前段時間因為項目需要,做了個用來對數組排序的類,順便把以前學過的幾種排序算法用C#實現一下。用C#的一些機制來诠釋了一下算法的是實現。在閱讀本之前,需要一些對C#的有些基本的了解,了解方法參數中out ,ref的作用,掌握面向對象的一些基本思想。
1.插入排序
1.1.基本思想:
每次將一個待排序的數據元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序數據元素全部插入完為止。
1.2.排序過程:
【示例】:
[初始關鍵字] [49] 38 65 97 76 13 27 49
(38) [38 49] 65 97 76 13 27 49
(65) [38 49 65] 97 76 13 27 49
(97) [38 49 65 97] 76 13 27 49
(76) [38 49 65 76 97] 13 27 49
(13) [13 38 49 65 76 97] 27 49
(27) [13 27 38 49 65 76 97] 49
(49) [13 27 38 49 49 65 76 97]
1.3.程序實現
<summary>
/// 插入排序算法
/// </summary>
/// <param name="dblArray"></param>
static void InsertSort(ref double[] dblArray)
{
for(int i = 1 ; i < dblArray.Length ; i++)
{
int frontArrayIndex = i-1 ;
int CurrentChangeIndex = i ;
while(frontArrayIndex>=0)
{
if(dblArray[CurrentChangeIndex] < dblArray[frontArrayIndex])
{
ChangeValue(ref dblArray[CurrentChangeIndex],ref dblArray[frontArrayIndex]);
CurrentChangeIndex = frontArrayIndex ;
}
frontArrayIndex--;
}
}
}
/// <summary>
/// 在內存中交換兩個數字的值
/// </summary>
/// <param name="A"></param>
/// <param name="B"></param>
static void ChangeValue (ref double A ,ref double B)
{
double Temp = A ;
A = B ;
B = Temp ;
}
2.選擇排序
2.1.基本思想:
每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到全部待排序的數據元素排完。
2.2.排序過程:
【示例】:
初始關鍵字 [49 38 65 97 76 13 27 49]
第一趟排序後 13 [38 65 97 76 49 27 49]
第二趟排序後 13 27 [65 97 76 49 38 49]
第三趟排序後 13 27 38 [97 76 49 65 49]
第四趟排序後 13 27 38 49 [49 97 65 76]
第五趟排序後 13 27 38 49 49 [97 97 76]
第六趟排序後 13 27 38 49 49 76 [76 97]
第七趟排序後 13 27 38 49 49 76 76 [ 97]
最後排序結果 13 27 38 49 49 76 76 97
2.3.程序實現
/// <summary>
/// 選擇排序
/// </summary>
/// <param name="dblArray"></param>
private static void SelectSort(ref double[] dblArray)
{
for(int i =0 ; i< dblArray.Length; i++)
{
double MinValue = dblArray[i] ;
int MinValueIndex = i ;
for(int j = i; j< dblArray.Length; j++)
{
if(MinValue > dblArray[j] )
{
MinValue = dblArray[j] ;
MinValueIndex = j ;
}
}
ExChangeValue(ref dblArray[i], ref dblArray[MinValueIndex]);
}
}
/// <summary>
/// 交換數據
/// </summary>
/// <param name="A"></param>
/// <param name="B"></param>
private static void ExChangeValue(ref double A , ref double B)
{
double Temp = A ;
A = B ;
B = Temp ;
}
3.冒泡排序
3.1.基本思想:
兩兩比較待排序數據元素的大小,發現兩個數據元素的次序相反時即進行交換,直到沒有反序的數據元素為止。
3.2.排序過程:
設想被排序的數組R[1..N]垂直豎立,將每個數據元素看作有重量的氣泡,根據輕氣泡不能在重氣泡之下的原則,從下往上掃描數組R,凡掃描到違反本原則的輕氣泡,就使其向上"漂浮",如此反復進行,直至最後任何兩個氣泡都是輕者在上,重者在下為止
【示例】:
49 13 13 13 13 13 13 13
38 49 27 27 27 27 27 27
65 38 49 38 38 38 38 38
97 65 38 49 49 49 49 49
76 97 65 49 49 49 49 49
13 76 97 65 65 65 65 65
27 27 76 97 76 76 76 76
49 49 49 76 97 97 97 97
3.3.程序實現
程序支持順序和倒序排列。
/// <summary>
/// 冒泡算法
/// </summary>
/// <param name="abarray"></param>
/// <param name="IsAscending">是否順序排序</param>
/// <returns></returns>
private static double[] BubbleArithmetic(double[] abarray ,bool IsAscending)
{
if(abarray.Length > 0 )
{
for(int i = abarray.Length-1 ;i >=0 ;i--)
{
for(int j = i-1 ; j>=0 ; j--)
{
if(CheckAccordCondition(abarray[i],abarray[j],IsAscending))
{
ExChangeValue(ref abarray[i],ref abarray[j]);
}
}
}
}
return abarray;
}
/// <summary>
/// 交換數據
/// </summary>
/// <param name="A"></param>
/// <param name="B"></param>
private static void ExChangeValue(ref double A , ref double B)
{
double Temp = A ;
A = B ;
B = Temp ;
}
/// <summary>
/// 是否符合條件
/// </summary>
/// <returns></returns>
private static bool CheckAccordCondition(double data1 ,double data2, bool IsAscending)
{
if(data1 > data2)
{
return IsAscending == true ? true :false;
}
else
{
return IsAscending == true ? false :true ;
}
}
4.快速排序
4.1.基本思想:
在當前無序區R[1..H]中任取一個數據元素作為比較的"基准"(不妨記為X),用此基准將當前無序區劃分為左右兩個較小的無序區:R[1..I-1]和R[I+1..H],且左邊的無序子區中數據元素均小於等於基准元素,右邊的無序子區中數據元素均大於等於基准元素,而基准X則位於最終排序的位置上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),當R[1..I-1]和R[I+1..H]均非空時,分別對它們進行上述的劃分過程,直至所有無序子區中的數據元素均已排序為止。
4.2.排序過程:
【示例】:
初始關鍵字 [49 38 65 97 76 13 27 49]
第一次交換後 [27 38 65 97 76 13 49 49]
第二次交換後 [27 38 49 97 76 13 65 49]
第三次交換後 [27 38 13 97 76 49 65 49]
第四次交換後 [27 38 13 49 76 97 65 49]
[27 38 13 49 76 97 65 49]
(一次劃分過程)
初始關鍵字 [49 38 65 97 76 13 27 49]
一趟排序之後 [27 38 13] 49 [76 97 65 49]
二趟排序之後 [13] 27 [38] 49 [49 65]76 [97]
三趟排序之後 13 27 38 49 49 [65]76 97
最後的排序結果 13 27 38 49 49 65 76 97
各趟排序之後的狀態
4.3.程序實現
/// <summary>
/// 快速排序法
/// </summary>
/// <param name="dbArray"></param>
/// <param name="StartIndex"></param>
/// <param name="EndIndex"></param>
private static void QuickSort( ref double[] dbArray ,int StartIndex ,int EndIndex)
{
//基數
int CurrentIndex = StartIndex ;
//順序查找
bool IsOrderSearched = true ;
//反序查找
bool IsDisOrderSearched = true ;
while(IsOrderSearched || IsDisOrderSearched)
{
IsDisOrderSearched = false ;
IsOrderSearched = false ;
for(int i =EndIndex ; i>CurrentIndex ;i--)
{
if(dbArray[i] < dbArray[CurrentIndex])
{
ExChangeValue(ref dbArray[i] ,ref dbArray[CurrentIndex]);
CurrentIndex = i ;
IsDisOrderSearched = true ;
break ;
}
}
for(int i = StartIndex ; i < CurrentIndex ; i++)
{
if(dbArray[i] > dbArray[CurrentIndex])
{
ExChangeValue(ref dbArray[i] ,ref dbArray[CurrentIndex]);
CurrentIndex = i ;
IsOrderSearched = true ;
break ;
}
}
}
if( EndIndex - StartIndex > 0 )
{
if(CurrentIndex != StartIndex )
{
QuickSort(ref dbArray ,StartIndex,CurrentIndex -1);
}
if(CurrentIndex != EndIndex)
{
QuickSort(ref dbArray ,CurrentIndex+1,EndIndex);
}
}
}
/// 交換數據
/// </summary>
/// <param name="A"></param>
/// <param name="B"></param>
private static void ExChangeValue(ref double A , ref double B)
{
double Temp = A ;
A = B ;
B = Temp ;
}
5.堆排序
5.1.基本思想:
堆排序是一樹形選擇排序,在排序過程中,將R[1..N]看成是一顆完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系來選擇最小的元素。
5.2.堆的定義:
N個元素的序列K1,K2,K3,...,Kn.稱為堆,當且僅當該序列滿足特性:Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])。
堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉子結點的關鍵字均大於等於其孩子結點的關鍵字。例如序列10,15,56,25,30,70就是一個堆,它對應的完全二叉樹如上圖所示。這種堆中根結點(稱為堆頂)的關鍵字最小,我們把它稱為小根堆。反之,若完全二叉樹中任一非葉子結點的關鍵字均大於等於其孩子的關鍵字,則稱之為大根堆。
5.3.排序過程:
堆排序正是利用小根堆(或大根堆)來選取當前無序區中關鍵字小(或最大)的記錄實現排序的。我們不妨利用大根堆來排序。每一趟排序的基本操作是:將當前無序區調整為一個大根堆,選取關鍵字最大的堆頂記錄,將它和無序區中的最後一個記錄交換。這樣,正好和直接選擇排序相反,有序區是在原記錄區的尾部形成並逐步向前擴大到整個記錄區。
【示例】:對關鍵字序列42,13,91,23,24,16,05,88建堆。
5.4.程序實現
/// <summary>
/// 小根堆排序
/// </summary>
/// <param name="dblArray"></param>
/// <param name="StartIndex"></param>
/// <returns></returns>
private static void HeapSort(ref double[] dblArray )
{
for(int i = dblArray.Length -1 ; i >= 0; i--)
{
if(2*i+1<dblArray.Length)
{
int MinChildrenIndex = 2*i+1 ;
//比較左子樹和右子樹,記錄最小值的Index
if(2*i+2 < dblArray.Length )
{
if(dblArray[2*i+1]>dblArray[2*i+2])
MinChildrenIndex = 2*i+2;
}
if(dblArray[i] > dblArray[MinChildrenIndex])
{
ExchageValue(ref dblArray[i],ref dblArray[MinChildrenIndex]);
NodeSort(ref dblArray ,MinChildrenIndex);
}
}
}
}
/// <summary>
/// 節點排序
/// </summary>
/// <param name="dblArray"></param>
/// <param name="StartIndex"></param>
private static void NodeSort(ref double[] dblArray,int StartIndex)
{
while(2*StartIndex+1 < dblArray.Length)
{
int MinChildrenIndex = 2*StartIndex+1 ;
if(2*StartIndex+2 < dblArray.Length )
{
if(dblArray[2*StartIndex+1]>dblArray[2*StartIndex+2])
{
MinChildrenIndex = 2*StartIndex+2;
}
}
if(dblArray[StartIndex] > dblArray[MinChildrenIndex])
{
ExchageValue(ref dblArray[StartIndex],ref dblArray[MinChildrenIndex]);
StartIndex = MinChildrenIndex ;
}
}
}
/// <summary>
/// 交換值
/// </summary>
/// <param name="A"></param>
/// <param name="B"></param>
private static void ExchageValue(ref double A , ref double B)
{
double Temp = A ;
A = B ;
B = Temp ;
}
總結:
人常說算法是程序的靈魂,在作項目的過程中時常注意且不可靈魂出竅。時常去回顧一下以前的數據重要性就如同基督徒每周要做禮拜一樣。不能因為有了C# 和Java這種平台之後,就忽略了基礎的重要性。
我用C#的控制台程序 把這幾個算法實現了一下,代碼在附件中,如有寫的不好的地方,敬請指正。