计数排序和桶排序

介绍两种非基于比较的排序算法。前面提到的排序算法,快排,堆排,合并等都是通过比较元素之间的大小来进行排序的,基于比较的排序是不能突破 NLog2N 的下界的。而这两种算法的时间复杂度是可以达到 O(N) 的,当然它收到一定条件的限制。
计数排序:
计数排序假设输入数据的范围已经知道,并且是在一个确定的范围内,如 (0,K] 内。基本思路是:对于每一个输入数据X,确定小于X的元素个数,利用这个特性,就可以确定X在输出数组中的位置。例如: X=18 ,数组中小于X的元素个数为7,则X就应该在输出数组中的第8个位置上,如果出现相同的元素时稍微做一下变形就可以。
下面我给出一个简单的实现:

/*
Problem:Counting Sort
State:Sloved
Author:Liang Shaocong
Date:2015/4/5
*/
#include <iostream>
#include <ctime>
#include <cstring>
#include <vector>
const int LENGTH=20;
const int MAX_NUM=100;
int Order[LENGTH+1];
void  Counting_Sort(int A[],int B[],int C[]){
    for(int i=0;i<=MAX_NUM;i++)
        C[i]=0;
    //统计每个位置的元素个数   
    for(int i=1;i<=LENGTH;i++)
        C[A[i]]=C[A[i]]+1;
    //确定位置 
    for(int i=1;i<=MAX_NUM;i++)
        C[i]=C[i]+C[i-1];
    //确定输出位置 
    for(int j=LENGTH;j>=1;j--){
        B[C[A[j]]]=A[j];
        Order[C[A[j]]]=j;
        C[A[j]]=C[A[j]]-1;
    }   
    for(int j=1;j<=LENGTH;j++)
        A[j]=B[j];
}
int main(void){
    int A[LENGTH+1],B[LENGTH+1],C[MAX_NUM+1];
    std::cout<<"Before Counting Sort:"<<std::endl;
    //Initialize
    for(int i=1;i<=LENGTH;i++){
        A[i]=rand()%100+1;
        std::cout<<A[i]<<" ";
    }
    std::cout<<std::endl;
    Counting_Sort(A,B,C);
    std::cout<<"After Counting Sort:"<<std::endl;
    for(int i=1;i<=LENGTH;i++)
        std::cout<<A[i]<<" ";
    std::cout<<std::endl;
    //在原来序列中的位置 
    std::cout<<"Location in primary array: "<<std::endl;
    for(int i=1;i<=LENGTH;i++)
        std::cout<<Order[i]<<" ";   
}

桶排序:
桶排序也假设输入数据的范围确定,假设为 [0,100) 。这样便可以建立10个桶,其中每个桶分别存储 [0,10) , [10,20) , [20,30) ……. [90,99) 之间的元素。把每一个输入数据放到相应的桶里,同时对每一个桶内部进行排序。最后再把桶合并。
下面是简单的实现:

/*
Problem:Bucket_Sort 
Author:Liang Shaocong
Date:2015/4/9
State:Sloved
*/
#include <iostream>
#include <vector>
#include <ctime>
using std::cin;using std::cout;using std::endl;using std::vector;
const int BUCKET_NUM=10; //bucket number
const int N=20;  //element number

struct Node{
    int value;
    Node *next;
    explicit Node(int i=-1):value(i),next(nullptr){}
};
Node* Insert_Bucket(int value,Node* Bucket){
    Node ivec;
    Node *newNode=new Node(value);
    Node *previous=&ivec,*current=Bucket;
    ivec.next=Bucket;

    while(current!=nullptr && current->value<=value){
        previous=current;
        current=current->next;
    }
    newNode->next=current;
    previous->next=newNode;

    return ivec.next;
}
Node* Merge_Bucket(Node *Bucket1,Node *Bucket2){
    Node ivec;
    Node *head=&ivec;

    while(nullptr!=Bucket1 && nullptr!=Bucket2){
        if(Bucket1->value<=Bucket2->value){
            head->next=Bucket1;
            Bucket1=Bucket1->next;
        }else{
            head->next=Bucket2;
            Bucket2=Bucket2->next;
        }
        head=head->next;
    }
    if(nullptr!=Bucket1)
        head->next=Bucket1;
    if(nullptr!=Bucket2)
        head->next=Bucket2;

    return ivec.next;
}
void Bucket_Sort(int arr[],int n){
    vector<Node*> Bucket(BUCKET_NUM,(Node*)(0));
    //Insert to Bucket
    for(int i=0;i<n;i++){
        int index=arr[i]/BUCKET_NUM;
        Node *head=Bucket.at(index);
        Bucket.at(index)=Insert_Bucket(arr[i],head);
    }
    //header of the bucket
    Node *head=Bucket.at(0);
    //Merge these buckets
    for(int i=1;i<BUCKET_NUM;i++)
        head=Merge_Bucket(head,Bucket.at(i));

    for(int i=0;i<n;i++){
        arr[i]=head->value;
        head=head->next;
    }   
}
int main(void){
    int arr[N];
    for(int i=0;i<N;i++)
        arr[i]=rand()%100;
    cout<<"Before Bucket Sort:"<<endl;
    for(int i=0;i<N;i++)
        cout<<arr[i]<<" ";
    cout<<endl;
    //Sort   
    Bucket_Sort(arr,N);
    cout<<"After Sort: "<<endl;

    for(int i=0;i<N;i++)
        cout<<arr[i]<<" ";
    return 0;
}

以上:
参考资料:
http://zh.wikipedia.org/wiki/%E6%A1%B6%E6%8E%92%E5%BA%8F
https://www.byvoid.com/blog/sort-radix

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值