排序演算法小結(冒泡排序、簡單選擇排序、快速排序)
1)冒泡排序bubble_sort
1.原理
假設對a[N]進行排序
依次比較相鄰兩個數,小數放前,大數放前。
*1 從頭開始進行第一輪比較,則得到最後一個位置是所有數中的最大的一個數;
需要比較的次數是N-1,為什麼是N-1?因為,總共是N個數,數組下標是從0開始,
如果比較最後兩個資料,判斷條件:if(a[N-1-1] > a[N-1]),a[N-1]就是數組的最後一個數了,
如果比較次數是N,則執行該論最後一對資料比較時就是if(a[N-1] > a[N]),
眾所都知,a[N]中是沒有a[N],所以次數會得到一個意想不到的排序,裡面會多一個垃圾值,垃圾值的產生就是a[N]。
所以此時必須用N-1。
*2 從頭開始進行第二輪比較,則得到倒數第二個位置是所有數中的次最大數;
需要比較的次數是(N-1)-1,為什麼是(N-1)-1?因為,解釋同上。
*3 從頭依次進行第三輪比較,則得到倒數第三個位置是所有數中的次次最大數;
需要比較的次數是N-1-1-1,為什麼是(N-1)-1-1?因為,解釋同上。
*N-1 依次從頭開始比較,直至比較完。
2.代碼實現過程
void bubble_sort(int a[], int N) //N是數組a的長度
{
int i, j, tmp;
for(i = 0; i < N-1; i++) //進行比比較的趟數,此時的N-1如果換成N,對程式影響不大,只不過多一次迴圈而已
{
for(j = 0; j < N-i-1; j++) //開始進行比較,此時的N-i-1不能換成N-i,如果寫成N-i,會產生一個垃圾值,解釋在*1中
{
if(a[j] > a[j+1])
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}
return;
}
2)簡單選擇排序select_sort
1.原理
假設對a[N]進行排序
假定選一個最小的,依次把後面的數與它進行比較,如果後面的比假定選的最小的還小,則進行交換這兩個數。每進行一輪就要找出一個最小的數。
*1 第一輪 假定第一個數是“最小的”,然後依次把後面的數與這個“最小的”的進行比較,如果比這個“最小的”小,首先標記該數為“最小的”,
然後把這個“最小的”與前面的“最小的”交換值,目的是保證第一個數是後面所有數中最小的一個。
*2 第二輪 因為已經知道第一個是最小的,這時從第二個開始尋找最小的,假定第二個是最小的,然後依次把後面的數與這個“最小的”的進行比較,
如果比這個“最小的”小,首先標記該數為“最小的”,然後把這個“最小的”與前面的“最小的”交換值,目的是保證第二個數是後面所有數中最小的一個。
*N 第N輪 步驟同上。
說明 是進行N輪比較還是N-1輪比較,影響不大,原因是:該數組中共有N個數,如果對N-1個數進行了排序處理,即第N-1個數是後面中最小的一個數,
剩餘的唯一的第N個數肯定是所有數中最大的,顯然它應該放在最後一個位置上,沒必要再進行一次迴圈。如果是進行N輪比較,無非是程式多執行一次迴圈,
其實實際上這次迴圈也沒有執行,因為在子迴圈中無法滿足迴圈條件,不能執行迴圈體。
2.代碼實現過程
void select_sort(int a[], int N) //N是數組a的長度
{
int i, j, min, tmp;
for(i = 0; i < N; i++) //從頭開始比較
{
min = i; //把第i個數當作最小的,把下標標記為min
for(j = i+1; j < N; j++) //把a[min]依次和它後面的數進行比較
{
if(a[j] < a[min]) //如果後面的某個值比a[min]小
{
min = j; //重新標記最小值下標
}
tmp = a[min]; //交換
a[min] = a[i]; //原來min = i的,如果沒有找到比a[min]小的,就不進行交換(如果沒找到,i還是和min一樣,執行該三條語句沒作用)
a[i] = tmp; //只有a[j] < a[min]成立,執行了min = j,這時才能交換(這時min的已經改為j,不再是i了,所以執行才有作用)
} //自己表達欠缺,上面三句表達不夠明確,只要自己研讀程式,因該能明白其中奧妙
}
return;
}
3)快速排序quick_sort
1.原理
假定對a[N]排序
快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)。
實現快速排序需要兩個函數,分別是:partition()和quick_sort()
函數: int partition(int a[], int i, int j)
函數功能: 把數組分為兩段,左段都是比基準小的數,但是左段的數是無序的;右段都是比基準大的數,但是右段的數是無序的。
函數大概實現過程:
*1 選取一個基準(pivot),基準一般選取第一個數a[0];
*2 定義兩個變數i、j;
令j從數組尾部向左掃描,直到遇到一個數比基準小的,進行交換。目的是:使比基準小的都放在基準左邊。
令i從數組開頭向右掃描,直到遇到一個數比基準大的,進行交換。目的是:使比基準大的都放在基準右邊。
進行多次迴圈後,最終i的值就是基準應該放的位置。
原因是:我們假定的基準是數組的第一個數a[0],a[0]也許既不是數組中最大的數也不是數組中最小的數,
也就是基準的位置應該在數組中的某個位置,經過多次迴圈後,i不斷往後遞增,當不滿足迴圈條件時,i就停止了,此時i就是基準的位置
(表達欠缺,還需要自己揣摩)
函數: void quick_sort(int a[], int left, int right)
函數功能: 實現排序
函數大概實現過程:
遞迴的對每一段進行排序
2.代碼實現過程
int partition(int a[], int i, int j)
{
int pivot; //基準
pivot = a[i];
while(i < j)
{
while(i < j && a[j] > pivot);
{
j--; //如果右邊的比基準大,左移j
}
a[i] = a[j]; //如果遇到了右邊的比基準小,和基準交換
while(i < j && pivot <= a[i]);
{
i++; //如果左邊的基準小,右移i
}
a[j] = a[i]; //如果遇到了左邊的比基準大,和基準交換
}
a[i] = pivot;
return i;
}
void quick_sort(int a[], int left, int right)
{
int pivottag;
if(left < right)
{
pivottag = partition(a, left, right);
quick_sort(a, 0, pivottag-1);
quick_sort(a, pivottag+1, right);
}
return;
}