氣泡排序與快排演算法
Hello,同志們,今天分享有關氣泡排序和快排的演算法思想以及程式碼實現。
一、氣泡排序
1、氣泡排序是什麼?
氣泡排序是一種相對穩定的排序演算法,時間複雜度0(N*N ), 氣泡排序就是通過兩兩比較,(以升序為例),從開頭比較,一個數與它後面的比較,如果比後面的小,不動,如果比後面的數大,把它倆交換,這樣一次排序後最大的數就在最大下標處,每比完一輪,縮小比較範圍,N個數比較,總的比較次數為N-1輪。
注意:每比完一輪,縮小比較範圍!!!
2、程式碼優化:
如果資料本身就是有序的,而比較每次都拿出兩個比較,看是否需要交換,總共要比N-1輪,每輪內部也會比較多次,第i輪需要比較(N-i)次,消耗較大;
在每輪比較中可以置一個ex 布林變數為false;如果發生交換,置為true;
一輪比較下來,如果資料有序就不會發生交換,每輪比較完後判斷ex的真假,為假說明沒交換,直接退出,後面的比較也不用做了, 剩下幾輪的比較也只是在浪費時間,空間而已,沒有任何意義
這樣可以提高程式碼的效率。
比較圖示:
3、程式碼如下:
可以用兩個for迴圈巢狀寫;也可以用while迴圈來控制比較輪數,內嵌一個for迴圈來比較資料大小
void BubbleSort(int* a, int len)
{
for (size_t i = 0; i < len-1; i++)//外圍控制總比較輪數
{
bool ex = false;
for (size_t j = 0;j<len-i-1; j++)//哪兩個資料比較?
{
if (a[j] > a[j + 1])
{
ex = true;
swap(a[j], a[j + 1]);
}
}
if (ex == false)
{
break;
}
}
}
//while()巢狀for()迴圈
void BuBBleSort(int* a, int len)
{
assert(a);
int sq = len;//sq控制比較輪數
while (sq > 0)
{
bool ex = false;
for (int j = 0; j < sq - 1; ++j)
{
if (a[j]>a[j + 1])
{
swap(a[j], a[j + 1]);
ex = true;
}
}
if (ex == false)
{
break;
}
--sq;
}
}
二、快排演算法&優化
1、快速排序是什麼?
採用分治策略,一次排序後,將資料劃分為兩半,一半比某一個數小,另一半比某個數大。
*利用遞迴,完成對陣列的排序。
2、實現快排有三種方法:
(1)左右指標法:
兩個指標,指向陣列下標,找一個定值,讓其它數與它比較,在兩個指標相遇之前,左邊指標找比這個數大的,右邊指標找比這個數小的,交換這兩個指標指向的值;返回相遇下標值,這樣將資料劃分為兩部分,然後對左半邊進行quickSort,對右半邊進行quickSort。
程式碼如下:
#include <iostream>
#include <assert.h>
using namespace std;
int PartSort(int *a, int begin, int end)//左右指標法
{
//int key = GetMid(a, begin, end);//選取資料的優化
int key = end;
while (begin < end)
{
while (a[begin] <= a[key] && begin<end)
{
begin++;
}
while (a[end] >= a[key] && begin<end)
{
end--;
}
if (begin < end)
{
swap(a[begin], a[end]);
}
}
swap(a[begin], a[key]);
return begin;
}
void QuickSort(int* a, int start, int final)
{
assert(a);
if (start < final)
{
int div = PartSort(a, start, final - 1);
QuickSort(a, start, div);
QuickSort(a, div + 1, final);
}
}
int main()
{
int arr[] = { 3, 6, 8, 1, 7, 9, 5, 2,4 };
int len = sizeof(arr) / sizeof(arr[0]);
QuickSort(arr, 0, len);
for (int i = 0; i <len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
快排時間複雜度:0(n*logn)
最差情況:每次選取的數都是最小的或者最大的數,像氣泡排序一樣,此時時間複雜度0(N*N),出現機率較小,但是不排除這種可能性。
當陣列是有序的時候,每次選出來的那個數就是最大或者最小的,此時最壞情況出現。
優化演算法:三數取中
選取一個剛好不大不小的數來和其他數作比較,採用三數取中法 用這個下標對應數來做key(劃分資料值)。
程式碼如下:
int GetMid(int *a,int left, int right)
{
int middle = ((left + right) >> 1);
//int middle = left+((right-left)>>1);
if (a[left] < a[middle])
{
if (a[middle] < a[right])
{
return middle;
}
else if (a[left]<a[right])
{
return right;
}
else
{
return left;
}
}
else
{
if (a[middle] > a[right])
{
return middle;
}
else if (a[left] > a[right])
{
return right;
}
else
{
return left;
}
}
}
利用上面的函式,可以避免像取到的數最大或最小,導致快排發揮不了作用的情況。
(2)前後指標法
兩個指標,一前一後指向陣列資料,前面指標先走,cur起始位置0,prev起始位置-1。
如圖:
程式碼實現如下:
int PartSort1(int *a, int left, int right)
{
int prev = left - 1;
int cur = left;
int key = a[right];
while (cur < right)
{
while (a[cur] <= key)
{
cur++;
prev++;
}//cur大
while (++cur < right)
{
if (a[cur] < key&&++prev!=cur)
{
swap(a[cur], a[prev]);
}
}
}
swap(a[++prev], a[right]);
return prev;
}
(3)挖坑法
左右指標輪流做坑,記錄key=a[right]最後一個數據的值,如果左指標找到比右指標大的,右邊的相當於一個坑,讓左指標指向的值覆蓋右指標指向的值,此時左邊就相當於一個坑,然後再在右邊找比key小的數,覆蓋左指標,迴圈尋找,最後剩下的這個坑裡填的就是key。
如圖:
程式碼如下:
int PitSort(int* a, int left, int right)//left和right輪流做坑
{
int key = a[right];
while (left < right)
{
while (a[left] <= key&&left<right)
{
++left;
}
a[right] = a[left];
while (a[right] >= key&&left < right)
{
--right;
}
a[left] = a[right];
}
a[left] = key;
return left;
}
好了,今天的氣泡排序和快速排序就分享到這裡啦,氣泡排序是一種穩定的演算法,快排一般情況下效率較高,但是不穩定,在排序過程中,知道什麼資料和什麼資料相比較非常重要,路漫漫其修遠兮,吾將上下而求索。
加油!Have a nice day~