前言
參考文章:http://blog.csdn.net/hguisu/article/details/7776068
文章中對算法的解釋非常詳細,這裏只做個人總結和部分算法代碼 使用的平臺爲unity,用c#編寫 ,其中代碼中涉及的數學方法爲unity封裝後的方法
插入排序
直接插入排序
/// <summary>
/// 直接插入排序 (使用List結構)
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
List<int> Sort_Zhijiecharu(List<int> data)
{
//從小到大
for (int i = 1; i < data.Count; i++)
{
int temp = data[i];
int j = i - 1;
if (data[i]< data[i-1])// 如果有調整需要
{
while (temp < data[j])//向前遍歷,一直找到比當前元素小的數的下標
{
j--;
if (j < 0) break;//防止下標越界
}
data.RemoveAt(i);
data.Insert(j+1, temp);//將當前元素,插入到後面
}
}
return data;
}
希爾排序
/// <summary>
/// 希爾排序
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
int[] Sort_Sell(int[] data)
{
int dk = data.Length;
while (true)
{
dk = Mathf.CeilToInt(dk / 2f);
data = Sort_Sell_Zhijiecharu(data, dk);
if (dk == 1) break;
}
return data;
}
/// <summary>
/// 希爾排序中使用到的直接插入
/// </summary>
/// <param name="data"></param>
/// <param name="dk">下標的增量 直接插入排序dk=1</param>
/// <returns></returns>
int[] Sort_Sell_Zhijiecharu(int[] data,int dk)
{
//從小到大
int temp = 0;
for (int x = 0; x < dk; x++)//遍歷 通過dk分成的子序列
{
for (int i = x + dk; i < data.Length; i += dk)//遍歷子序列
{
int j = i - dk;
temp = data[i];
for (; j >= 0 && temp < data[j]; j -= dk)//向前遍歷 如果前面元素>當前元素
{
data[j + dk] = data[j];//前面元素後移
}
data[j + dk] = temp;//將當前元素插入到目標位置
}
}
return data;
}
選擇排序
簡單選擇排序
/// <summary>
/// 簡單排序
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
int[] Sort_Jiandan(int[] data)
{
int pos = 0;
int temp = 0;
for (int i = 0; i < data.Length; i++)
{
temp = data[i];
pos = i;
//遍歷後面的數據,從中找出一個最小的
for (int j = i+1; j < data.Length; j++)
{
if (data[j]<temp)
{
temp = data[j];
pos = j;
}
}
//交換位置
data[pos] = data[i];
data[i] = temp;
}
return data;
}
堆排序
/// <summary>
/// 調整爲大頂堆(或 小頂堆)
/// </summary>
/// <param name="H">數組</param>
/// <param name="parent">父節點</param>
/// <param name="length">數組長度</param>
void HeapAdjust(int[] H, int parent, int length)
{
//構建一個大頂堆,即堆頂爲最大元素
int tmp = H[parent];
int child = 2 * parent + 1; //左孩子結點的位置。(i+1 爲當前調整結點的右孩子結點的位置)
while (child < length)//經過循環,保證以H[parent]爲根結點的子數爲一個大頂堆
{
if (child + 1 < length && H[child] < H[child + 1])
{ //如果右孩子大於左孩子(找到比當前待調整結點大的孩子結點)
child++;
}
if (H[parent] < H[child])
{ //如果較大的子結點大於父結點
H[parent] = H[child]; // 那麼把較大的子結點往上移動,替換它的父結點
parent = child; // 重新設置parent,即待調整的下一個結點的位置
child = 2 * parent + 1;
}
else
{ //如果當前待調整結點大於它的左右孩子,則不需要調整,直接退出
break;
}
H[parent] = tmp;//當前待調整的結點放到比其大的孩子結點位置上
}
}
/// <summary>
/// 創建初始堆
/// </summary>
/// <param name="H"></param>
/// <param name="length"></param>
void BuildingHeap(int[] H, int length)
{
//最後一個有孩子的節點的位置 i= (length -1) / 2
for (int i = (length - 1) / 2; i >= 0; --i)
{
HeapAdjust(H, i, length);
}
}
/// <summary>
/// 堆排序
/// </summary>
/// <param name="H"></param>
/// <param name="length"></param>
void Sort_Heap(int[] H, int length)
{
//初始堆
BuildingHeap(H, length);
//從最後一個元素開始對序列進行調整
for (int i = length - 1; i > 0; --i)
{
//交換堆頂元素H[0]和堆中最後一個元素
int temp = H[i]; H[i] = H[0]; H[0] = temp;
//每次交換堆頂元素和堆中最後一個元素之後,都要對堆進行調整
HeapAdjust(H, 0, i);
}
}
交換排序
冒泡排序
/// <summary>
/// 冒泡排序
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
int[] Sort_MaoPao(int[] data)
{
//從小到大排序
DateTime start = DateTime.Now;
int count = data.Length;
//冒泡
for (int i = 0; i < count - 1; i++)
{
for (int j = 0; j < count - 1 - i; j++)
{
if (data[j] > data[j + 1])
{
int temp = data[j + 1];
data[j + 1] = data[j];
data[j] = temp;
}
}
}
TimeSpan dur = DateTime.Now - start;
print(dur.Milliseconds);
return data;
}
快速排序
/// <summary>
/// 快速排序
/// </summary>
/// <param name="a"></param>
/// <param name="low"></param>
/// <param name="high"></param>
void Sort_Quick(int[] a, int low, int high)
{
if (low < high)
{
int privotLoc = Partition(a, low, high); //將表一分爲二
Sort_Quick(a, low, privotLoc - 1); //遞歸對低子表遞歸排序
Sort_Quick(a, privotLoc + 1, high); //遞歸對高子表遞歸排序
}
}
int Partition(int[] a, int low, int high)
{
int privotKey = a[low];//基準元素
int temp = 0;
while (low < high)
{
//從表的兩端交替地向中間掃描
while (low < high && a[high] >= privotKey) --high;//從high 所指位置向前搜索,至多到low+1 位置。將比基準元素小的交換到低端
//位置互換
temp = a[high];
a[high] = a[low];
a[low] = temp;
while (low < high && a[low] <= privotKey) ++low;
//位置互換
temp = a[high];
a[high] = a[low];
a[low] = temp;
}
return low;
}
時間複雜度
穩定性
排序算法的穩定性:若待排序的序列中,存在多個具有相同關鍵字的記錄,經過排序, 這些記錄的相對次序保持不變,則稱該算法是穩定的;
若經排序後,記錄的相對次序發生了改變,則稱該算法是不穩定的。
穩定性的好處:排序算法如果是穩定的,那麼從一個鍵上排序,然後再從另一個鍵上排序,第一個鍵排序的結果可以爲第二個鍵排序所用。
基數排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,如果排序算法穩定,可以避免多餘的比較;
如何選擇排序算法
排序算法簡單的講分爲兩種 空間換時間,時間換空間
根據數據量的多少,數據量的大小,排序速度要求,內存空間大小,穩定性要求,
具體內容 上述文章最後有講,比較詳細