InsertSort:(以升序爲例)
插入排序的基本思想是:
每次將一個待排的記錄,按照其關鍵字的大小,插入到前面已經排好序的有序區中適當的位置,直到全部記錄插入完畢爲止。
假設待排序的記錄存放在數組R[0..n]中,初始時R[0]是一個有序區,R[1..n]是無序區,從i=1開始,依次將R[i]插入到有序區R[0..i-1]中,生成一個包含n個記錄的有序區
void InsertSort(int *arr, int len)
{
int i = 0;
int j = 0;
int tmp = 0;
for (i = 1; i < len; i++)
{
tmp = arr[i];
for (j = i; j>0 && arr[j - 1]>tmp; j--) //在有序區找到一個正確的位置
{
arr[j] = arr[j - 1]; //將當前記錄後移
}
arr[j] = tmp; //將tmp插入到找到的位置
}
}
優化:折半插入
既然有序區已經有序,那麼我們在尋找合適位置的時候,可以使用折半查找的思想在有序區尋找這個位置。
穩定性
直接插入排序是穩定排序,即相同的數據元素在排序前後不會改變二者之間的相對順序。
希爾排序
希爾排序又叫縮小增量排序,其實希爾排序就是插入排序的一種,只不過對插入排序做了優化。
在插入排序中,我們每次相當於每隔一個的再插入,希爾排序的思想是:
設待排序元素有n個,首先取一個整數gap<n作爲間隔,將全部元素分爲gap組,所有距離爲gap的元素都在同一個組裏,然後對每一個組都進行插入排序。然後縮小增量,直到gap==1的時候整個序列都會變成有序的。
希爾排序與插入排序的比較:
插入排序在什麼情況下效率最高呢???
如果當要排序的序列大致上接近於有序的時候,插入排序的效率最高,基本上接近O(N)。因爲當數據基本上接近於有序的時候,元素向有序區插入的時候比較的次數會很少,同樣有序區元素向後移動的次數也是很少的。
如果當一組數據接近的有序的話,我們優先使用插入排序,效率高。如果當一組數據接近於逆序的話,我們使用希爾排序會更優。插入情況最好的情況就是希爾排序最壞的情況,因爲這時候希爾排序的預排序起不到作用。插入排序最壞的情況則是希爾排序最高的情況,因爲這時候預排序的效果是非常明顯的。
穩定性
希爾排序是不穩定的排序,因爲我們將原序列分組了,不能保證兩個相同的數據在同一組,所以導致其是不穩定排序。
選擇排序
選擇排序的基本思想:初始時,有序區爲0,每一趟在無序區中選出一個關鍵字最小的元素,然後與無序區第一個元素交換,然後無序區減1,有序區加1,直到記錄全部排完
優化
既然每一次我們都會遍歷待排序序列,那何嘗不同時將最大值,最小值都找出來,分別放入待排序序列的頭和尾呢?
穩定性
選擇排序是不穩定的排序方法。
冒泡排序
它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。
冒泡排序的優化
我們已經知道當走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成,所以我們可以設置一個標誌位來判斷是否已經排序完畢。
void BubbleSort(int *arr, int len)
{
assert(arr);
int i = 0;
int j = 0;
int flag = 0;
int tmp = 0;
for (i = 0; i < len - 1; i++)
{
flag = 1; //flag初始時爲1
for (j = 0; j < len - i - 1; j++) //每排序一趟,則必然後面有一個已經有序,可以縮小排序的範圍
{
if (arr[j]>arr[j + 1]) //只要要交換數據,則flag就會被修改
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0; //只要這組數還未完全有序,則一定會修改flag爲0
}
}
if (flag) //如果排序一趟,發現已經有序,則不進入if,flag沒被修改
{
break;
}
}
}
穩定性
冒泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改變,所以冒泡排序是一種穩定排序算法。
堆排序
是用數組模擬樹的形式進行的排序。但是堆數據結構只保證父節點的值大於或者小於子節點的值,並不保證整體的順序。但是我們可以利用根節點的值永遠是最大,或者最小的這個特性,利用根節點找出最值,再與尾位置互換,即可排序成功。
穩定性
因爲每次根節點的值都是不確定的,所以我們也不能保證相同元素的父節點是相同的,所以堆排序是不穩定的
歸併排序
是一種基於分治法的一種排序方法。它將要排序的序列分成兩個長度相等的子序列,爲每一個子序列進行排序,然後再將子序列合併成一個有序的序列。
優化:
當劃分的子區間的元素小於13個元素左右時,再使用歸併的話會效率不會很高,相當於多增加了二叉樹的後面幾層的結點。這時候我們改用直接插入排序來進行優化
穩定性
歸併排序是把序列遞歸地分成短序列,遞歸出口是短序列只有1個元素(認爲直接有序),然後把各個有序的段序列合併成一個有 序的長序列,是穩定排序。