幾種排序算法

簡單實現了常見的幾種內部排序算法,包括冒泡(Bubble),插入(Insert),快速排序(Quick Sort),堆排序(Heap Sort),歸併(Merge),希爾排序(Shell Sort),並對這些算法的耗時在僞隨機數上進行了簡單的測試。
  說明:

  • 沒有實現計數、基數排序等線性複雜度的算法;
  • 各算法只是對算法思想的一次簡單模擬,沒有過多的優化;
  • 各排序主程序接口參數均爲整型數組及元素個數;
  • 程序計時使用了glibc的gettimeofday(),因此。。。;
  • 歸併排序中,每次調用都申請和釋放堆空間,因此比較耗時。可以採用原地歸併、使用全局/靜態的方法加以優化;
  • 快速排序中,對待排子序列的長度進行的了判斷,對短序列進行優先排序可以減小函數的遞歸深度(而不是次數);
  • 希爾排序中,爲了簡潔,步長因子統一取做2.2(11/5)。

 下面是主程序

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <time.h>
#include <sys/time.h> //~ gettimeofday()
 
typedef void (*SORTFUN)(int *a, int n);
 
#define ASIZE 24*1024 //~ array size
#define SCOUNT 6 //~ number of sort method
enum {BUBBLE, INSERT, QSORT, HEAP, MERGE, SHELL};
char *fname[SCOUNT] =
    {
        "Bubble", "Insert", "Qsort",
        "Heap", "Merge", "Shell"
    };
 
SORTFUN fpointer[SCOUNT]; //~ pointers to sort functions
 
int array[SCOUNT][ASIZE]; //~ array(s) under sort.
 
long timeused[SCOUNT]; //~ time taken by every sort function
 
/*******************Generate random data*********************/
void
gen_data(void)
{
    srand(time(NULL)); //~ rand seeding
    for(int i = 0; i < ASIZE; ++i) //~ generate random array[0]
    {
        array[0][i] = rand() % ASIZE;
    }
    for(int i = 1; i < SCOUNT; ++i) //~ copy array[0] to the rest
    {
        for(int j = 0; j < ASIZE; ++j)
        {
            array[i][j] = array[i-1][j];
        }
    }
    //NOTE: using TWO loops to maximize caching
}
 
/***********************Time the time**********************/
long
timer(void) //~ Current Time by millisecond
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
int
main(int AC, char **AV) //~ Both of AC and AV are fascinating ^_^
{
    gen_data();
 
    //NOTE: to disable a function, just comment it out below.
    fpointer[BUBBLE] = bubble_sort;
    fpointer[INSERT] = insert_sort;
    fpointer[QSORT] = quick_sort;
    fpointer[HEAP] = heap_sort;
    fpointer[MERGE] = merge_sort;
    fpointer[SHELL] = shell_sort;
 
    for(int i = 0; i < SCOUNT; ++i)
    {
        long starttime = timer();
        SORTFUN fp = fpointer[i];
        if(fp)
            fp(array[i], ASIZE);
        timeused[i] = timer() - starttime;
    }
 
    //~ Header
    printf("%%Method/t/t%%Time/t/t%%Elements/n");
    printf("-----------------------------------------/n");
    //~ result
    for(int i = 0; i < SCOUNT; ++i)
    {
        printf("%s/t/t%ld/t/t%d/n", fname[i], timeused[i], ASIZE);
    }
    printf("/n");
    return 0;
}

 

各種排序:

冒泡排序

/************************Bubble Sort**************************/
void
bubble_sort(int *a, int n)
{
    for(int i = n - 1; i > 0; --i)
    {
        int issorted = 0; //~ flag, for some optimition
        for(int j = 0; j < i; ++j)
        {
            if(a[j] > a[j+1])
            {
                issorted = 1;
                int tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
            }
        }
        if(!issorted)
            break;
    }
}

 

 對測試結果做一下簡要的總結:

  • 快排不是蓋的,在我有限的隨機測試中,它始終是最快的;
  • 這裏的歸併排序由於堆內存的頻繁申請與釋放,相比同量級的其它算法,是最慢的;
  • 希爾排序相當給力,儘管步長因子選擇很粗糙,但在我的測試中,還是超過了堆排序。這從側面證明了,在接近有序時插入排序是很快的。事實上,插入排序,由於其簡潔性,常常做爲高級排序算法的末級算法(局部算法)。

轉載出處:http://www.dutor.net/index.php/2010/10/sorts-of-sort-methods/


 插入排序:
/************************Insert Sort**************************/
void
insert_sort(int *a, int n)
{
    for(int i = 0; i < n - 1; ++i)
    {
        int j = i + 1;
        int tmp = a[j];
        while(j > 0 && tmp < a[j-1])
        {
            a[j] = a[j-1];
            --j;
        }
        a[j] = tmp;
    }
}

快速排序: 
/************************Quick Sort**************************/
int
partition(int *a, int n) //~ seperate a[], using a[0] as pivot
{
    int l = 0, r = n;
    int pivot = a[l];
    while(l < r)
    {
        while( l < r && a[--r] > pivot) ;
        a[l] = a[r];
        while(l < r && a[++l] < pivot) ;
        a[r] = a[l];
    }
    a[l] = pivot;
    return l; //~ return the final index of pivot
}
void
quick_sort(int *a, int n)
{
    if(n <= 1)
        return;
    int m = partition(a, n);
    if(m <= n / 2)
    {
        quick_sort(a, m);
        quick_sort(a + m + 1, n - m - 1);
    }
    else
    {
        quick_sort(a + m + 1, n - m - 1);
        quick_sort(a, m);
    }
}
 
/************************Quik Sort**************************/
void
sift(int *a, int i, int n) //~ sift to rebuild the heap rooted by a[i]
{
    int tmp = a[i];
    while(2*i + 1 < n)
    {
        int j = 2*i + 1;
        if(j + 1 < n && a[j+1] > a[j])
            ++j;
        if(a[j] > tmp)
        {
            a[i] = a[j];
            i = j;
        }
        else
            break;
    }
    a[i] = tmp;
}

 

堆排序:

/************************Heap Sort**************************/
void
heap_sort(int *a, int n)
{
    for(int i = (n-2) / 2; i >= 0; --i) //~ build heap
    {
        sift(a, i, n);
    }
    for(int i = 1; i < n; ++i) //~ rebuild the decreasing heap over and over
    {
        int tmp = a[0];
        a[0] = a[n-i];
        a[n-i] = tmp;
        sift(a, 0, n - i);
    }
}
 

歸併:
/***********************Merge Sort**********************/
void
merge_sort(int *a, int n)
{
    if(n == 1)
        return;
    int *ext = (int*)malloc(sizeof(int) * n / 2);
    merge_sort(a, n / 2);
    merge_sort(a + n / 2, (n + 1) / 2);
 
    memcpy(ext, a, n / 2 * sizeof(int));
    int i = 0, j = n / 2, k = 0;
    while(i < n / 2 && j < n)
    {
        if(a[j] < ext[i])
            a[k++] = a[j++];
        else
            a[k++] = ext[i++];
    }
    while(i < n / 2)
        a[k++] = ext[i++];
    while(j < n)
        a[k++] = a[j++];
    free(ext);
}

希爾排序: 
/***********************Shell Sort**********************/
void
shell_sort(int * a, int n)
{
    int step = n / 2;
    while(step > 0)
    {
        for(int i = step; i < n; ++i)
        {
            int tmp = *(a + i);
            int j = i - step;
            while(j >= 0 && tmp < *(a + j))
            {
                *(a + j + step) = *(a + j);
                j -= step;
            }
            *(a + j + step) = tmp;
        }
        if(step == 2)
            step = 1;
        else
            step = step * 11 / 5; //~ integer is better
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章