算法基礎(chǔ):6種經(jīng)典排序算法的遞歸和非遞歸實現(xiàn)

本文的算法實現(xiàn)主要參考兩本書:
《算法導(dǎo)論》
《大話數(shù)據(jù)結(jié)構(gòu)》

接口

#ifndef _SORT_H
#define _SORT_H

#define true 1
#define false 0

typedef int bool;

typedef int elem_t;

typedef struct{
    elem_t *a;
    int len;
} List;

void printlist(elem_t *a, int n, int sps);
bool listCompare(List *a1, List *a2,int n);
// ==============常用內(nèi)部排序=================
// 冒泡排序(簡單交換排序的改進(jìn))
extern void bubbleSort_RE(elem_t *a, int len);
extern void bubbleSort_NRE(elem_t *a, int len);
// 選擇排序
extern void selectionSort_RE(elem_t *a, int n);
extern void selectionSort_NRE(elem_t *a, int n);
// 插入排序
extern void insertionSort_RE(elem_t *a, int n);
extern void insertionSort_NRE(elem_t *a, int n);
// 希爾排序(插入排序的改進(jìn))
extern void shellSort_RE(elem_t *a, int n);
extern void shellSort_NRE(elem_t *a, int n);
// 堆排序(簡單選擇排序的改進(jìn))
extern void heapSort_RE(elem_t *a, int n);
extern void heapSort_NRE(elem_t *a, int n);
// 歸并排序
extern void mergeSort_RE(elem_t *a, int n);
extern void mergeSort_NRE(elem_t *a, int n);
// 快速排序(冒泡排序的改進(jìn))
extern void quickSort_RE(elem_t *a, int n);
extern void quickSort_NRE(elem_t *a, int n);

#endif

測試代碼

注意

  • NRE表示非遞歸版本回右,RE表示遞歸版本
  • 部分排序算法提供了兩種版本的實現(xiàn)
// test_sort.c
#include "sort.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>


static const int n = 50;
static const int sps = 10;

int main(){
    List list;
    list.a = (elem_t *)malloc(sizeof(int)*n);
    list.len = n;
    printf("Random Number From 0 ~ %d\n", list.len);
    srand(time(0));
    for (int i = 0; i < list.len; ++i)
    {
        list.a[i] = rand() % list.len;
        printf("%d", list.a[i]);
        (i+1) % sps == 0 ? printf("\n") : printf("\t");
    }
    
    // bubbleSort_RE(list.a,list.len); // test pass
    // bubbleSort_NRE(list.a,list.len); // test pass

    // selectionSort_RE(list.a,list.len); // test pass
    // selectionSort_NRE(list.a,list.len); // test pass

    // insertionSort_RE(list.a,list.len); // test pass
    // insertionSort_NRE(list.a,list.len); // test pass

    // shellSort_NRE(list.a,list.len); // test pass
    
    // heapSort_NRE(list.a,list.len); // test pass

    // mergeSort_RE(list.a,list.len); // test pass

    quickSort_RE(list.a,list.len); // test pass

    printf("\nOrdered Sequence:\n");
    printlist(list.a, list.len, sps);

    free(list.a);

    exit(0);
}

接口的實現(xiàn)

#include "sort.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// #include <time.h>

// used for heapSort
#define PARENT(i) (i >> 1)
#define LEFT(i)   (i << 1)
#define RIGHT(i)  (i << 1 + 1)

static const int MAX_INT = ((unsigned)(-1))>>1;
// static const int MIN_INT = ~MAX_INT;

static inline int Parent(int i) {return i >> 1;}
static inline int Left(int i) {return i << 1;}
static inline int Right(int i) {return ((i << 1) + 1);} 

// declaration of inner function
static int elemCompare(elem_t a, elem_t b);
static void swap(elem_t *a, int i, int j);
static bool makeMinToBeHead_BUB(elem_t *a, int n);
static void makeMinToBeHead_INS(elem_t *a, int n);
static void insertNewElem(elem_t *a, int n);
static void HeapAdjust(elem_t *a, int s, int m);
// 使根節(jié)點為i的子樹維持最大堆的性質(zhì)(前提:節(jié)點為i的左右子樹都是最大堆)
static void MaxHeapify_RE(elem_t *a, int len, int i); 
static void MaxHeapify_NRE(elem_t *a, int len, int i);
static void BuildMaxHeap(elem_t *a, int len);
static void merge(elem_t *a,int p,int q,int r);
static void mergeSort(elem_t *a, int p, int r);
static void quickSort(elem_t *a, int p, int r);
static int patition(elem_t *a, int p, int r);

// ================================================================
// export function implementation
// ================================================================
extern void printlist(elem_t *a, int n, int sps){
    assert(a!=NULL);
    for (int i = 0; i < n; ++i)
    {
        printf("%d", a[i]);
        (i+1) % sps == 0 ? printf("\n") : printf("\t");
    }   
}
bool listCompare(List *a1, List *a2, int n){
    assert(a1!=NULL && a2!= NULL && n > 0);
    int index = 0;
    while(index++ < n && a1->a[index] == a2->a[index]){
        if (index == n-1)
        {
            return true;
        }
    }
    return false;
}
// 冒泡排序 最壞o(n^2)
extern void bubbleSort_RE(elem_t *a, int n){
    printf("\nUsing bubbleSort_RE Algorithm:\n");
    assert(a!=NULL);
    if (n < 2) return;
    else{
        if(true == makeMinToBeHead_BUB(a,n))
            bubbleSort_RE(a+1,n-1);
        else return;
    }
}

extern void bubbleSort_NRE(elem_t *a, int n){
    printf("\nUsing bubbleSort_NRE Algorithm:\n");
    assert(a!=NULL);
    bool flag = true; 
    // 檢測是否已排序完成的標(biāo)志顾画,避免無意義的比較
    for (int i = 0; i < n && flag == true; ++i)
    {
        flag = false; 
        // 若內(nèi)層循環(huán)無交換煌集,則說明序列已排序
        for (int j = n-1; j > 0; --j)
        {
            if (elemCompare(a[j-1],a[j]))
            {
                swap(a,j-1,j);
                flag = true;
            }
        }
        // printf("%d\n", a[i]);
    }
}
// 選擇排序 最壞o(n^2)
extern void selectionSort_RE(elem_t *a, int n){
    printf("\nUsing selectionSort_RE Algorithm:\n");
    assert(a!=NULL);
    if (n < 2) return;
    else{
        makeMinToBeHead_INS(a,n);
        selectionSort_RE(a+1,n-1);
    }
}
extern void selectionSort_NRE(elem_t *a, int n){
    printf("\nUsing selectionSort_NRE Algorithm:\n");
    assert(a!=NULL);
    for (int i = 0; i < n-1; ++i)
    {
        int min = i;
        for(int j = i+1; j < n; ++j)
        {
            if (elemCompare(a[min],a[j]))
            {
                min = j;
            }
        }
        if (min != i) //
        {
            swap(a,i,min);
        }
    }
}
// 插入排序 最壞o(n^2)
extern void insertionSort_RE(elem_t *a, int n){
    printf("\nUsing insertionSort_RE Algorithm:\n");
    assert(a!=NULL);
    if(n < 2) return;
    else{
        insertionSort_RE(a,n-1);// a[0]~a[n-2]為有序的
        insertNewElem(a,n); // 將a[n-1]插入到有序表
    }
}
extern void insertionSort_NRE(elem_t *a, int n){
    assert(a!=NULL);
    printf("\nUsing insertionSort_NRE Algorithm:\n");
    //=====================method 1====================
    for (int i = 1; i < n; ++i)
    {
        for(int j = i; j >= 1 && elemCompare(a[j-1],a[j]); --j)
            swap(a,j-1,j);
    }
    // =====================method 2====================
    // for (int i = 0; i < n; ++i)
    // {
    //  bool flag = true;
    //  for(int j = i+1; j > 0 && flag == true; --j)
    //  {
    //      flag = false;
    //      if (elemCompare(a[j-1],a[j]))
    //      {
    //          swap(a,j-1,j);
    //          flag = true;
    //      }
    //  }
    // }
}
// 希爾排序
extern void shellSort_RE(elem_t *a, int n){

}
extern void shellSort_NRE(elem_t *a, int n){
    printf("\nUsing shellSort_NRE Algorithm:\n");
    assert(a!=NULL);
    // int loopCnt = 0; // for debug
    for(int increment = n/2; increment >= 1; increment = increment/2){
        // printf("\nLoop %d, increment = %d:\n", loopCnt++, increment);
        for(int i = increment; i < n; ++i){
            // printf("\ni = %d\n", i);
            for(int j = i; j >= increment && elemCompare(a[j-increment],a[j]); j -= increment)
            {
                // printf("%d and %d will be swaped\n", a[j-increment],a[j]);
                swap(a,j-increment,j);
            }
            // printlist(a,n,10);
        }
    }
}
// 堆排序(簡單選擇排序的改進(jìn))
extern void heapSort_RE(elem_t *a, int n){
    
}
extern void heapSort_NRE(elem_t *a, int n){
    assert(a!=NULL && n > 0);
    printf("\nUsing heapSort_NRE Algorithm:\n");
    //===================method 2 算法導(dǎo)論==================
    BuildMaxHeap(a,n);  // 構(gòu)建最大堆
    for(int i = n-1; i >=1; i--){
        swap(a,0,i);
        MaxHeapify_NRE(a,i,0); 
        // 維護(hù)最大堆, 每循環(huán)一次,需要維護(hù)的堆的大小減一
        // 維護(hù)以偏移量為0的元素為根的大小為i的堆為最大堆
    }

    //===================method 1 大話數(shù)據(jù)結(jié)構(gòu)==================
    // for (int i = n/2; i > 0; i--)
    // {
    //  HeapAdjust(a,i,n);
    // } // 構(gòu)建最大堆// 維護(hù)最大堆
    // for(int i = n; i > 1; i--)
    // {
    //  swap(a,0,i-1);
    //  HeapAdjust(a,1,i-1);
    // }// 維護(hù)最大堆

}
// 歸并排序
extern void mergeSort_RE(elem_t *a, int n){
    printf("\nUsing mergeSort_RE Algorithm:\n");
    assert(a!=NULL && n >= 0);
    int p = 0, r = n-1;
    mergeSort(a,p,r);
}
extern void mergeSort_NRE(elem_t *a, int n){
    
}
// 快速排序(冒泡排序的改進(jìn))
extern void quickSort_RE(elem_t *a, int n){
    printf("\nUsing quickSort_RE Algorithm:\n");
    assert(a!=NULL && n >= 0);
    int p = 0, r = n-1;
    quickSort(a,p,r);
}
extern void quickSort_NRE(elem_t *a, int n){

}
// ================================================================
// inner function implementation
// ================================================================
static int elemCompare(elem_t a, elem_t b){
    return (a > b);
}

static void swap(elem_t *a, int i, int j){
    assert(a!=NULL);
    int temp = a[j];
    a[j] = a[i];
    a[i] = temp;
}

bool makeMinToBeHead_BUB(int *a, int n){
    assert(a!=NULL);
    bool flag = false;
    for (int i = n-1; i > 0; i--)
    {
        if (elemCompare(a[i-1],a[i]))
        {
            swap(a,i-1,i);
            flag = true;
        }
    }
    return flag;
}

static void makeMinToBeHead_INS(elem_t *a, int n){
    assert(a!=NULL);
    int min = 0;
    for (int i = 1; i < n; ++i)
    {
        if (elemCompare(a[min],a[i]))
        {
            min = i;
        }
    }
    if (min != 0)
    {
        swap(a,min,0);
        // printf("%d\n", a[0]);
    }
}

static void insertNewElem(elem_t *a, int n){
    assert(a!=NULL);
    // printf("\n%d will be inserted.\n", a[n-1]); // for debug
    bool flag = true; // 插入成功標(biāo)志
    for (int i = n-1; i > 0 && (flag == true); --i) // 再也不要用代碼自動生成功能 --i
    {
        flag = false;
        if (elemCompare(a[i-1],a[i]))
        {
            // printf("to swap %d and %d\n",a[i-1],a[i]); // for debug
            swap(a,i-1,i);
            flag = true;
        }
    }
    // printlist(a,n,10); // for debug
    // printf("\n"); 
}

static void HeapAdjust(elem_t *a, int s, int m){
    assert(a!=NULL && s > 0 && m > 0);
    int temp = a[s-1];
    for(int j = 2*s; j <= m; j *=2)
    {
        if(j < m && elemCompare(a[j],a[j-1]))
            ++j;
        if(elemCompare(temp,a[j-1]))
            break;
        a[s-1] = a[j-1];
        s = j;
    }
    a[s-1] = temp;
}
// 維持一個最大堆疆柔,最壞時間復(fù)雜度O(log(n))
static void MaxHeapify_RE(elem_t *a, int len, int i){
    assert(a!=NULL && len >= 0 && i >=0 && i < len);
    // i是當(dāng)前節(jié)點的偏移量供鸠,i+1是當(dāng)前節(jié)點的層序編號
    // lchild是孩子節(jié)點的偏移量锌钮,lchild + 1是孩子節(jié)點的層序編號
    // 對于完全二叉樹,有關(guān)系lchild + 1 = Left(i+1)
    int lchild = Left(i+1) - 1; 
    int rchild = Right(i+1) - 1;
    // 臨時設(shè)置最大值節(jié)點的偏移量為當(dāng)前節(jié)點值
    int largest = i;

    // 在有左孩子的前提下(lchild < len)扑浸,將當(dāng)前節(jié)點值與左孩子節(jié)點值比較
    if(lchild < len && elemCompare(a[lchild],a[largest]))
        largest = lchild;
    // 在有左孩子的前提下(lchild < len)烧给,將當(dāng)前節(jié)點值與左孩子節(jié)點值中的較大值與右孩子節(jié)點值比較
    if(rchild < len && elemCompare(a[rchild], a[largest]))
        largest = rchild;

    if (largest != i){
        swap(a,i,largest);
        MaxHeapify_RE(a,len,largest);
    }
}

static void MaxHeapify_NRE(elem_t *a, int len, int i){
    assert(a!=NULL && len >= 0 && i >=0 && i < len);
    int root = i;
    while(root < len){
        int lchild = Left(root+1) - 1; 
        int rchild = Right(root+1) - 1;
        int largest = root;
        
        if(lchild < len && elemCompare(a[lchild],a[largest]))
            largest = lchild;
        if(rchild < len && elemCompare(a[rchild], a[largest]))
            largest = rchild;

        if (largest == root)
            break;
        else {
            swap(a,root,largest);
            root = largest; // 沿著未調(diào)整前較大孩子節(jié)點的子樹往下調(diào)整
        }
    }
}
// 講一個無序數(shù)組構(gòu)建成一個最大堆,最壞時間復(fù)雜度為O(n)
static void BuildMaxHeap(elem_t *a, int len){
    assert(a!=NULL && len >= 0);
    for(int i = Parent(len)-1; i >= 0; i--){
        MaxHeapify_NRE(a,len,i);
    }
}
static void mergeSort(elem_t *a, int p, int r){
    assert(a!=NULL && p >= 0 && r >=0 && r >= p);
    if(p < r){
        int q = ((p+r) >> 1);
        mergeSort(a,p,q);
        mergeSort(a,q+1,r);
        merge(a,p,q,r);
    }
}
// 合并兩個有序的子序列為一個有序序列
static void merge(elem_t *a,int p,int q,int r){
    assert(a!=NULL && p >= 0 && q >= 0 && r >=0 && q >=p && r >= q);
    int nl = q - p + 1; // len1
    int nr = r - q;     // len2
    int L[nl+1],R[nr+1];
    for(int i = 0; i < nl; i++){
        L[i] = a[p+i];
    }
    for (int j = 0; j < nr; ++j){
        R[j] = a[q+j+1];
    }
    L[nl] = MAX_INT;
    R[nr] = MAX_INT;
    int i = 0, j = 0;
    // O(n), n = r - p + 1
    for(int k = p;k <= r;k++){
        if(elemCompare(L[i],R[j])){
            a[k] = R[j];
            j++;
        }
        else{
            a[k] = L[i];
            i++;
        }
    }
}
// static int cnt = 0;
static void quickSort(elem_t *a, int p, int r){
    assert(a!=NULL);
    // printf("\nNo.%05d p = %d, r = %d\n", ++cnt,p,r);
    if(p < r){
        int q = patition(a,p,r);
        // printf("\nNo.%05d p = %d, q = %d, r = %d\n", ++cnt,p,q,r);
        quickSort(a,p,q-1);
        quickSort(a,q+1,r);
    }
}
static int patition(elem_t *a, int p, int r){
    assert(a!=NULL && p >= 0 && r >=0 && r >= p);
    //x取子數(shù)組最后一個元素喝噪,把比x小的放在左邊础嫡, 把比x大放到右邊
    elem_t x  = a[r]; 
    int i = p - 1;
    for(int j = p; j <= r-1; j++){
        if (elemCompare(x,a[j])) // a[j] <= x
        {
            swap(a,++i,j);
        }
    }
    swap(a,i+1,r);
    return (i+1);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市酝惧,隨后出現(xiàn)的幾起案子榴鼎,更是在濱河造成了極大的恐慌,老刑警劉巖晚唇,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巫财,死亡現(xiàn)場離奇詭異,居然都是意外死亡哩陕,警方通過查閱死者的電腦和手機平项,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萌踱,“玉大人葵礼,你說我怎么就攤上這事〔⑼遥” “怎么了鸳粉?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長园担。 經(jīng)常有香客問我届谈,道長,這世上最難降的妖魔是什么弯汰? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任艰山,我火速辦了婚禮,結(jié)果婚禮上咏闪,老公的妹妹穿的比我還像新娘曙搬。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布纵装。 她就那樣靜靜地躺著征讲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪橡娄。 梳的紋絲不亂的頭發(fā)上诗箍,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音挽唉,去河邊找鬼滤祖。 笑死,一個胖子當(dāng)著我的面吹牛瓶籽,可吹牛的內(nèi)容都是我干的匠童。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼棘劣,長吁一口氣:“原來是場噩夢啊……” “哼俏让!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起茬暇,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤首昔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后糙俗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勒奇,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年巧骚,在試婚紗的時候發(fā)現(xiàn)自己被綠了赊颠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡劈彪,死狀恐怖竣蹦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沧奴,我是刑警寧澤痘括,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站滔吠,受9級特大地震影響纲菌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疮绷,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一翰舌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冬骚,春花似錦椅贱、人聲如沸懂算。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽犯犁。三九已至,卻和暖如春女器,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背住诸。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工驾胆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贱呐。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓丧诺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奄薇。 傳聞我的和親對象是個殘疾皇子驳阎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容