1. 程式人生 > >氣泡排序與快排演算法

氣泡排序與快排演算法

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~