一.交換排序
1.冒泡排序
基本思路:1.對相鄰的兩個進行比較,如果前者比後者大,則進行交換,一輪比較後,找到最大值,而且最大值就會排在尾端
2.對出去最大值意外的剩餘部分,重複1操作,直到找完,即完成排序
1)經典冒泡
private static void BubbleSortFun(List<int> list)
{
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j <list.Count -i-1; j++)
{
if (list[j ] > list[j+1]) //如果第二個小於第一個數
{
//交換兩個數的位置
Swap(list, j , j+1);
}
}
}
}
2)減少計算優化,減少了j判斷的計算
private static void BubbleSortFun1(List<int> list)
{
for (int i = 0; i < list.Count; i++)
{
for (int j = list.Count-1; j >i; j--)
{
if (list[j-1] > list[j]) //如果第二個小於第一個數
{
//交換兩個數的位置
Swap(list, j - 1, j);
}
}
}
}
3)優化冒泡,設置標誌位,對已經排序好的,不再進行排序
private static void BubbleSortFun2(List<int> list)
{
bool flg = true; //設置排序標誌位
for (int i = 0; i < list.Count && flg; i++)
{
flg = false; //設置爲false ,如果無排序發生則證明已經排序好了
for (int j = list.Count - 1; j > i; j--)
{
if (list[j - 1] > list[j]) //如果第二個小於第一個數
{
//交換兩個數的位置
Swap(list,j-1,j);
flg = true;
}
}
}
}
2.快速排序
基本思路:1.在已有序列中設置一個“基準”,一般設置第一個元素
2.進行分區,即將所有小於基準的數移動到基準的組邊,將所有大於基準的數放在基準的右邊
3.對左右分區分別重複1,2操作,直到無法分區爲止,即完成排序
private static void QuickSortFun(List<int> list, int left, int right)
{
if (left < right)
{
int i = Division(list, left, right);
//對樞軸的左邊部分進行排序
QuickSortFun(list, i + 1, right);
//對樞軸的右邊部分進行排序
QuickSortFun(list, left, i - 1);
}
}
//獲取按樞軸值左右分流後樞軸的位置
private static int Division(List<int> list, int left, int right)
{
while (left < right)
{
int num = list[left]; //將首元素作爲樞軸
if (num > list[left + 1])
{
list[left] = list[left + 1];
list[left + 1] = num;
left++;
}
else
{
int temp = list[right];
list[right] = list[left + 1];
list[left + 1] = temp;
right--;
}
}
return left; //指向的此時樞軸的位置
}
二.插入排序
1.直接插入排序
基本思路:1.從已有序列開始找到一個較小值,並用臨時變量保存它
2.將較小值前面比它大的數向後移動
3.當它前面無數字或比前面的數比它小,將它插入
4.以它後邊的數爲開始重複以上操作直到尾部,即完成排序
private static void InsortSortFun(List<int> list)
{
int temp = 0;
for (int i = 0; i < list.Count-1; i++)
{
if (list[i] <= list[i + 1])
continue;
temp = list[i + 1];//temp保存要向前移動的數字,防止數字被覆蓋掉
for (int j = i; j >= 0; j--)//numbers從第i個元素到第0個元素爲可能要向後移動的元素
{
if (temp <= list[j])//numbers[j]需要向後移動一個位置
list[j + 1] = list[j];//numbers[j+1]已經移動過,或者保存在temp中了,所以不會丟失數據
else
{
list[j + 1] = temp;//j+1是要插入的位置
break;
}
if (j == 0)//值最小的情況
list[0] = temp;
}
}
}
2.希爾排序
基本思路:1.得到一個步長,一般進行二分
2.按步長進行分組,並組內數據進行比較,交換
3.縮小步長,重複1,2操作,直到步長爲0即完成排序
private static void ShellSortFun(List<int> list)
{
for (int step = list.Count / 2; step > 0; step /= 2) //得到步長
{
for (int i = step; i < list.Count; i++) //分組
{
int j = 0;
int temp = list[i];
for (j = i - step; j >= 0 && temp < list[j]; j -= step) //對組內按步長比較後插入
{
list[j + step] = list[j];
}
list[j + step] = temp;
}
}
}
三.選擇排序
1.簡單選擇排序
基本思路:1.在已有的序列中,設置一個臨時索引
2.在未排序的序列中找到最小值的索引,並用臨時索引記錄
3.如果臨時索引值不等於未排序序列的最小索引,則進行交換
4.對未排序的序列重複以上操作,直到序列尾部,即完成排序
private static void SelectSortFun(List<int> list)
{
for (int i = 0; i < list.Count; i++)
{
int key = i; //保存key
for (int j = i + 1; j < list.Count; j++)//
{
if (list[j] < list[key]) key = j;
}
if (key != i)
{
int temp = list[i];
list[i] = list[key];
list[key] = temp;
}
}
}
2.堆排序
基本思路:1.對未排序的序列,以二叉樹的方式創建堆
2.對堆內數據進行比較,將最大值置於堆頂
3.將交換第一個元素和最後一個元素(因爲第一個元素即爲堆頂)
4.堆的大小減1,重複1,2,3操作,直到堆大小減少到0爲止,即完成排序
private static void HeapSortFun(List<int> list)
{
int count = list.Count;
CreatHeap(list, count);
for (int i = count - 1; i >= 0; i--) //交換第一個元素和最後一個元素後,堆的大小減1
{
//最後一個元素和第一個元素進行交換
Swap(list, 0, i);
CreatHeap(list, i);
}
}
private static void CreatHeap(List<int> list,int count)
{
int parent=count / 2 - 1;
for (int i =parent; i >=0; i--)
{
int left = i * 2 + 1; //左子樹節點
int right = i * 2 + 2; //右子樹節點
//選出左右子節點中最大的
int max = 0;
if (right < count)
{
max = list[left] > list[right] ? left : right;
}
else
max = left;
if (list[max] > list[i]) //交換子節點與父節點
{
Swap(list, max, i);
}
}
}
/// <summary>
/// 交換
/// </summary>
/// <param name="numbers"></param>
/// <param name="i"></param>
/// <param name="j"></param>
private static void Swap(List<int> numbers, int i, int j)
{
int number = numbers[i]; //把大的數放在一個臨時存儲位置
numbers[i] = numbers[j]; //然後把小的數賦給前一個,保證每趟排序前面的最小
numbers[j] = number; //然後把臨時位置的那個大數賦給後一個
}
四.歸併排序
基本思路:1.對已有序列進行拆分,直到拆分到足夠小,一半左右都是1
2.設置一個臨時序列,大小等於拆分好的序列大小
3.將拆分好的序列內進行比較,並存入臨時序列,臨時序列即爲有序
4.將臨時序列合併到原序列即完成排序
private static void MergeSortFun(int[] array, int first, int last)
{
if (first < last)
{
//表拆分
int mid = (first + last) / 2;
MergeSortFun(array, first, mid); //左側子表
MergeSortFun(array, mid + 1, last); //右側子表
//比較合併
MergeSortCore(array, first, mid, last);
}
}
/// <summary>
/// 子表比較,合併
/// </summary>
/// <param name="array"></param>
/// <param name="first"></param>
/// <param name="mid"></param>
/// <param name="last"></param>
private static void MergeSortCore(int[] array, int first, int mid, int last)
{
int leftIndex = first;
int rightIndex = mid + 1;
int[] temp = new int[last - first + 1];
int tempIndex = 0;
//把較小的數值放入臨時數組,有一側子表遍歷完後,跳出循環
while (leftIndex <= mid && rightIndex <= last)
{
if (array[leftIndex] <= array[rightIndex])
{
temp[tempIndex++] = array[leftIndex++];
}
else
{
temp[tempIndex++] = array[rightIndex++];
}
}
//將另外一側子表剩下的數一次放入暫存數組中(有序)
while (leftIndex <= mid)
{
temp[tempIndex++] = array[leftIndex++];
}
while (rightIndex <= last)
{
temp[tempIndex++] = array[rightIndex++];
}
//將暫存數組中有序的數列寫入目標數組的制定位置,使進行歸併的數組段有序
tempIndex = 0;
while (first <= last)
{
array[first++] = temp[tempIndex++];
}
}
以上完整代碼:https://download.csdn.net/download/shu19880720/11001823
總結
排序算法的穩定性是指排序前後具有相同關鍵字的記錄,相對順序保持不變。形式化的定義就是,排序之前有ri=rj,ri在rj之前,而在排序之後ri仍然在rj之前,就說這種算法是穩定的。各排序算法的比較如下所示: