排序算法十:桶排序 排序算法十:桶排序


声明:引用请注明出处http://blog.csdn.net/lg1259156776/


引言

在我的博文《“主宰世界”的10种算法短评》中给出的首个算法就是高效的排序算法。本文将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。

系列博文的上一篇讲述了基数排序,本文讲述它的“表亲”:桶排序(bucket sort)


排序相关的的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
    • 数据表( data list): 它是待排序数据对象的有限集合。
    • 排序码(key):通常数据对象有多个属性域,即多个数据成员组成,其中有一个属性域可用来区分对象,作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类
    • 内排序:指在排序期间数据对象全部存放在内存的排序;
    • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

排序算法的分析

排序算法的稳定性

如果在对象序列中有两个对象 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销

算法执行时所需的附加存储。


桶排序(bucket sort)

基本思想

桶排序的基本思想是将一个数据表分割成许多buckets,然后每个bucket各自排序,或用不同的排序算法,或者递归的使用bucket sort算法。也是典型的divide-and-conquer分而治之的策略。它是一个分布式的排序,介于MSD基数排序和LSD基数排序之间。关于基数排序可以参看上一篇博文《排序算法九:基数排序》。

基本流程

建立一堆buckets;
遍历原始数组,并将数据放入到各自的buckets当中;
对非空的buckets进行排序;
按照顺序遍历这些buckets并放回到原始数组中即可构成排序后的数组。

图示

排序算法十:桶排序
排序算法十:桶排序

算法的c plus plus描述

#include <iostream>
#include <iomanip>
using namespace std;

#define NARRAY 8  /* array size */
#define NBUCKET 5 /* bucket size */
#define INTERVAL 10 /* bucket range */

struct Node 
{ 
    int data;  
    struct Node *next; 
};

void BucketSort(int arr[]);
struct Node *InsertionSort(struct Node *list);
void print(int arr[]);
void printBuckets(struct Node *list);
int getBucketIndex(int value);

void BucketSort(int arr[])
{   
    int i,j;
    struct Node **buckets;  

    /* allocate memory for array of pointers to the buckets */
    buckets = (struct Node **)malloc(sizeof(struct Node*) * NBUCKET); 

    /* initialize pointers to the buckets */
    for(i = 0; i < NBUCKET;++i) {  
        buckets[i] = NULL;
    }

    /* put items into the buckets */
    for(i = 0; i < NARRAY; ++i) {   
        struct Node *current;
        int pos = getBucketIndex(arr[i]);
        current = (struct Node *) malloc(sizeof(struct Node));
        current->data = arr[i]; 
        current->next = buckets[pos];  
        buckets[pos] = current;
    }

    /* check what's in each bucket */
    for(i = 0; i < NBUCKET; i++) {
        cout << "Bucket[" << i << "] : ";
            printBuckets(buckets[i]);
        cout << endl;
    }

    /* sorting bucket using Insertion Sort */
    for(i = 0; i < NBUCKET; ++i) {  
        buckets[i] = InsertionSort(buckets[i]); 
    }

    /* check what's in each bucket */
    cout << "-------------" << endl;
    cout << "Bucktets after sorted" << endl;
    for(i = 0; i < NBUCKET; i++) {
        cout << "Bucket[" << i << "] : ";
            printBuckets(buckets[i]);
        cout << endl;
    }

    /* put items back to original array */
    for(j =0, i = 0; i < NBUCKET; ++i) {    
        struct Node *node;
        node = buckets[i];
        while(node) {
            arr[j++] = node->data;
            node = node->next;
        }
    }

    /* free memory */
    for(i = 0; i < NBUCKET;++i) {   
        struct Node *node;
        node = buckets[i];
        while(node) {
            struct Node *tmp;
            tmp = node; 
            node = node->next; 
            free(tmp);
        }
    }
    free(buckets); 
    return;
}

/* Insertion Sort */
struct Node *InsertionSort(struct Node *list)
{   
    struct Node *k,*nodeList;
    /* need at least two items to sort */
    if(list == 0 || list->next == 0) { 
        return list; 
    }

    nodeList = list; 
    k = list->next; 
    nodeList->next = 0; /* 1st node is new list */
    while(k != 0) { 
        struct Node *ptr;
        /* check if insert before first */
        if(nodeList->data > k->data)  { 
            struct Node *tmp;
            tmp = k;  
            k = k->next; 
            tmp->next = nodeList;
            nodeList = tmp; 
            continue;
        }

        for(ptr = nodeList; ptr->next != 0; ptr = ptr->next) {
            if(ptr->next->data > k->data) break;
        }

        if(ptr->next!=0){  
            struct Node *tmp;
            tmp = k;  
            k = k->next; 
            tmp->next = ptr->next;
            ptr->next = tmp; 
            continue;
        }
        else{
            ptr->next = k;  
            k = k->next;  
            ptr->next->next = 0; 
            continue;
        }
    }
    return nodeList;
}

int getBucketIndex(int value)
{
    return value/INTERVAL;
}

void print(int ar[])
{   
    int i;
    for(i = 0; i < NARRAY; ++i) { 
        cout << setw(3) << ar[i]; 
    }
    cout << endl;
}

void printBuckets(struct Node *list)
{
    struct Node *cur = list;
    while(cur) {
        cout << setw(3) << cur->data;
        cur = cur->next;
    }
}

int main(void)
{   
    int array[NARRAY] = {29,25,3,49,9,37,21,43};

    cout << "Initial array" << endl;
    print(array);
    cout << "-------------" << endl;

    BucketSort(array); 
    cout << "-------------" << endl;
    cout << "Sorted array"  << endl;
    print(array); 
    return 0;
}

输出为:

Initial array
 29 25  3 49  9 37 21 43
-------------
Bucket[0] :   9  3
Bucket[1] :
Bucket[2] :  21 25 29
Bucket[3] :  37
Bucket[4] :  43 49
-------------
Bucktets after sorted
Bucket[0] :   3  9
Bucket[1] :
Bucket[2] :  21 25 29
Bucket[3] :  37
Bucket[4] :  43 49
-------------
Sorted array
  3  9 21 25 29 37 43 49

虽然程序中的bucket采用链表结构以充分利用空间资源,而且bucket的构造也很巧妙,做的数据结构类似于栈链表的形式,插入都是插到顶部,所以后遍历的数据总是会在上面,因此从放入bucket之后的输出可以看出,跟图示进行对比,发现确实跟原来的原始相对顺序相反。


2015-9-29 艺少