zoukankan      html  css  js  c++  java
  • 各种排序方法的收集

    各种排序算法实现的收集,肯定有你没有见过的。

    归并,快排,奇偶排,cocktail 排序, 梳排序,计数排序,基数排序,LSD基数排序, shell排序,桶排序,鸽巢排序等 

    1. 归并排序的实现

    #include <iostream>
    #include
    <stdio.h>
    #include
    <stdlib.h>
    #include
    <string.h>
    using namespace std;
    void merage(int a[],int low,int mid,int high)
    {
    int *temp = (int *)malloc((high - low + 1) * sizeof(int));
    int begin1 = low;
    int end1 = mid;
    int begin2 = mid + 1;
    int end2 = high;
    int k;
    for( k = 0;begin1 <= end1 && begin2 <= end2; k ++)
    if(a[begin1] <= a[begin2])
    temp[k]
    = a[begin1 ++];
    else
    temp[k]
    = a[begin2 ++];

    if(begin1 <= end1)
    memcpy(temp
    + k,a+begin1,(end1-begin1+1)*sizeof(int));
    if(begin2 <= end2)
    memcpy(temp
    + k,a + begin2,(end2-begin2+1)*sizeof(int));

    memcpy(a
    +low, temp, (high-low+1)*sizeof(int));//将排序好的序列拷贝回数组中
    }
    void merage_sort(int a[],int frist,int last)
    {
    int mid = 0;
    if(frist < last)
    {
    //mid = (frist+last) / 2; 可能是产生溢出
    //mid = frist /2 + last / 2;
    mid = (frist & last) + ((frist ^ last) >> 1);
    merage_sort(a,frist,mid);
    merage_sort(a,mid
    + 1,last);
    merage(a,frist,mid,last);
    }
    }
    int main()
    {
    int a[20] = {1,4,5,6,7,8,9,15,16,17,18,12,13,14,19,2,3,10,11,0};
    merage_sort(a,
    0,20);
    for(int i = 0;i < 20; i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

      2. 快排实现

    通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

      

    #include <iostream>
    using namespace std;
    #define N 100
    int partition(int r[],int low,int high)
    {
    int key;
    key
    = r[low];//这里选择数组的第一个元素作为基准点
    while(low < high)
    {
    while(low < high && r[high] >= key) high --;
    r[low]
    = r[high];
    while(low < high && r[low] <= key) low ++;
    r[high]
    = r[low];
    }
    r[low]
    = key;//左边比它小,右边比它大
    return low;
    }
    void quickSort(int r[],int low,int high)
    {
    int k;
    if(low < high)
    {
    k
    = partition(r,low,high);
    quickSort(r,low,k
    - 1);
    quickSort(r,k
    +1,high);
    }
    }
    int main()
    {
    int a[10] = {1,7,6,8,9,3,5,4,2,0};
    quickSort(a,
    0,9) ;
    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

      

     3 奇偶排序法

    #include <iostream>

    using namespace std;
    /*
    奇偶排序法的思路是在数组中重复两趟扫描。
    第一趟扫描选择所有的数据项对,
    a[j]和a[j+1],j是奇数(j=1, 3, 5……)。
    如果它们的关键字的值次序颠倒,
    就交换它们。
    第二趟扫描对所有的偶数数据项进行同样的操作(j=2, 4,6……)。
    重复进行这样两趟的排序直到数组全部有序。
    */
    /*
     奇偶排序实际上在多处理器环境中很有用,
    处理器可以分别同时处理每一个奇数对,
    然后又同时处理偶数对。
    因为奇数对是彼此独立的,
    每一刻都可以用不同的处理器比较和交换。
    这样可以非常快速地排序。
    */
    void swap(int a[],int a1,int a2)
    {
    int temp = a[a1];
    a[a1]
    = a[a2];
    a[a2]
    = temp;
    }
    void oddEvenSort(int a[],int n)
    {
    int flag = 1;
    while(flag != 0)
    {
    flag
    = 0;
    for(int i = 1;i < n-1;i += 2)
    {
    if(a[i] > a[i + 1])
    {
    swap(a,i,i
    + 1);
    flag
    ++;
    }
    }
    for(int i = 0;i < n-1;i += 2)
    {
    if(a[i] > a[i + 1])
    {
    swap(a,i,i
    + 1);
    flag
    ++;
    }
    }
    }
    }
    int main()
    {
    int a[10] = {1,2,0,9,6,8,7,3,4,5} ;
    oddEvenSort(a,
    10);

    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

     4 cocktail 排序,是冒泡排序的一种变形。与冒泡排序的不同处在于排序时是以双向在序列中进行排序,然后以一个是否交换作为排序结束的标志

    #include <iostream>
    using namespace std;
    void cocktail_sort(int arr[],int n)
    {
    int left = 0;
    int right = n - 1;
    bool swapped = true;
    while(swapped)
    {
    swapped
    = false;
    for(int i = left; i < right; i ++)
    {
    if(arr[i] > arr[i + 1])
    swap(arr[i],arr[i
    +1]);
    swapped
    = true;
    }
    right
    -= 1;
    for(int i = right; i > left; i --)
    {
    if(arr[i] < arr[i-1])
    {
    swap(arr[i],arr[i
    - 1]);
    swapped
    = true;
    }
    }

    left
    += 1;

    }
    }
    ////////////////////////////////////////////////////////
    int main()
    {
    int a[10] = {1,2,0,9,6,8,7,3,4,5} ;
    cocktail_sort(a,
    10);

    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

      5. comb_sort 又叫三路划分快排,gap 选取一般是1.3,但根据统计,对于随机数据1.247330950103979更加合适,这个数根据e得来的 梳排序,改良自冒泡排序和快速排序

         在泡沫排序中,只比较阵列中相邻的二项,即比较的二项的间距(Gap)是1,梳排序提出此间距其实可大于1,改自插入排序希尔排序同样提出相同观点。梳排序中,开始时的间距设定为阵列长度,并在循环中以固定比率递减,通常递减率设定为1.3。在一次循环中,梳排序如同泡沫排序一样把阵列从首到尾扫描一次,比较及交换两项,不同的是两项的间距不固定于1。如果间距递减至1,梳排序假定输入阵列大致排序好,并以泡沫排序作最后检查及修正。

    #include <iostream>
    using namespace std;
    void comb_sort(int a[],int n)
    {
    float shrink_factor = 1.247330950103979;
    int gap = n,swapped = 1,temp,i;
    while((gap > 1) || swapped )
    {
    if(gap > 1)
    gap
    = gap / shrink_factor;

    swapped
    = 0;
    i
    = 0;
    while ((gap + i ) < n)
    {
    if(a[i] > a[i + gap])
    {
    temp
    = a[i];
    a[i]
    = a[i + gap];
    a[i
    + gap] = temp;
    }
    i
    ++;
    }
    }
    }
    int main()
    {
    int a[10] = {2,3,5,6,9,8,7,0,4,1};
    comb_sort(a,
    10);
    for(int i = 0;i < 10; i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

      6. 计数排序 对每一个输入元素x,确定出小于x的元素个数。适用于输入是由小范围的整数构成的序列。算法是稳定的。

    #include <iostream>
    using namespace std;
    int arr[100], res[100], hash[100];
    int len, k = -1;
    void PrintHash()
    {
    cout
    << "Hash数组: " << endl;
    for(int i=0; i<=k; ++i)
    cout
    << hash[i] << " ";
    cout
    << endl;
    }
    void countingSort()
    {
    for(int i=0; i<=k; ++i)
    hash[i]
    = 0;
    // 此过程记录每一个元素的个数
    for(int i=1; i<=len; ++i)
    ++hash[arr[i]];
    PrintHash();
    // 此过程确定小于x的元素的个数
    for(int i=1; i<=k; ++i)
    hash[i]
    += hash[i-1];
    PrintHash();
    // 思考这里为何从i=len开始?而不从i=1开始?
    for(int i=len; i>0; --i)
    {
    res[hash[arr[i]]]
    = arr[i];
    --hash[arr[i]];
    }
    }
    int main()
    {
    cout
    << "输入元素个数: ";
    cin
    >> len;
    cout
    << "输入" << len << "个元素: " << endl;
    for(int i=1; i<=len; ++i)
    {
    cin
    >> arr[i];
    if(k < arr[i])
    k
    = arr[i];
    }
    countingSort();
    cout
    << "排序后结果为: " << endl;
    for(int i=1; i<=len; ++i)
    cout
    << res[i] << " ";    
    cout
    << endl;
    }

      7. 基数排序  按组成关键字的各个位来进行排序

    #include <iostream>
    #include
    <string.h>
    using namespace std;

    int arr[100],res[100],hash[100];

    int n;
    int maxbit()
    {
    int max = 0;
    int temp[100];

    for(int i = 0;i < n; i ++)
    temp[i]
    = arr[i];

    for(int i = 0;i < n;i ++)
    {
    int t = 1;
    while(temp[i]/10 > 10)
    {
    t
    ++;
    temp[i]
    /= 10;
    }
    if(max < t)
    max
    = t;
    }


    cout
    << "max:" << max << endl;
    return max;
    }


    void radixSort()
    {
    memset(res,
    0,sizeof(res));
    int nbit = maxbit();

    int tmp;
    int radix = 1;
    for(int i = 1;i <= nbit;i ++)
    {
    for(int j = 0;j < 10;j ++)
    hash[j]
    = 0;
    for(int j = 0;j< n;j ++)
    {
    tmp
    = (arr[j] / radix) % 10;
    ++hash[tmp];
    }

    for(int j = 1;j < 10;j ++)
    hash[j]
    += hash[j - 1];

    for(int j = n - 1;j >= 0;j --)
    {
    tmp
    = (arr[j]/radix) % 10;
    -- hash[tmp];
    res[hash[tmp]]
    = arr[j];
    }

    for(int j = 0;j < n;j ++)
    arr[j]
    = res[j];
    radix
    *= 10;
    }
    }
    int main()
    {
    cout
    << "输入元素个数:" << endl;
    cin
    >> n;
    cout
    << "输入" << n << "个元素:" << endl;

    for(int i = 0;i < n;i ++)
    cin
    >> arr[i];

    radixSort();

    cout
    << "排序后:" << endl;

    for(int i = 0;i < n; i ++)
    cout
    << res[i] << " ";
    cout
    << endl;

    return 0;
    }

      LSD基数排序

    基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

    #define R 256

    #define digit(a, d) ( a >> 8*d )

    static BYTE *aux;

    void radix_sort(BYTE *arr, int left, int right)
    {
    if(left < right)
    {
    int d = 0;
    for(d=3; d>=0; d--)
    {
    int i=0, j=0, count[R+1];
    for(j=0; j<R; j++)
    count[j]
    = 0;
    for(i=left; i<=right; i++)
    count[digit(arr[i],d)
    + 1]++;
    for(j=1; j<R; j++)
    count[j]
    += count[j-1];
    for(i=left; i<=right; i++)
    aux[count[digit(arr[i],d)]
    ++] = arr[i];
    for(i=left; i<=right; i++)
    arr[i]
    = aux[i-1];
    }
    }
    }

    void RadixSort(BYTE *array,int length)
    {
    aux
    = (BYTE*)malloc(length);
    radix_sort(array,
    0,length-1);
    free(aux);
    }

      对于int 的LSD基数排序

      

    #include <stdio.h> 
    #include
    <stdlib.h>

    void radixSort(int[]);

    int main(void) {
    int data[10] = {73, 22, 93, 43, 55, 14, 28, 65, 39, 81};

    printf(
    "\n排序前: ");
    int i;
    for(i = 0; i < 10; i++)
    printf(
    "%d ", data[i]);

    putchar(
    '\n');

    radixSort(data);

    printf(
    "\n排序後: ");
    for(i = 0; i < 10; i++)
    printf(
    "%d ", data[i]);

    return 0;
    }

    void radixSort(int data[]) {
    int temp[10][10] = {0};
    int order[10] = {0};

    int n = 1;
    while(n <= 10) {

    int i;
    for(i = 0; i < 10; i++) {
    int lsd = ((data[i] / n) % 10);
    temp[lsd][order[lsd]]
    = data[i];
    order[lsd]
    ++;
    }

    // 重新排列
    int k = 0;
    for(i = 0; i < 10; i++) {
    if(order[i] != 0) {
    int j;
    for(j = 0; j < order[i]; j++, k++) {
    data[k]
    = temp[i][j];
    }
    }
    order[i]
    = 0;
    }

    n
    *= 10;
    }
    }

      

    8 shell排序

    #include <iostream>
    using namespace std;

    int sortGroup(int a[],int n,int begin,int step)
    {
    for(int i = begin + step;i < n; i += step)
    {
    for(int j = begin; j < i;j += step)
    {
    if(a[i] < a[j])
    {
    int tmp = a[i];
    for(int k = i; k >j;k -= step)
    {
    a[k]
    = a[k-step];
    }
    a[j]
    = tmp;
    }
    }
    }
    return 1;
    }
    int shellSort(int a[],int n)
    {
    //以i进行分组,i每次循环之后减小为原来的一半
    for(int i = n / 2; i > 0;i --)
    //对每一个组进行排序
    for(int j = 0;j < i;j ++)
    sortGroup(a,n,j,i);
    }
    int main()
    {
    int a[10] = {4,10,9,8,7,6,5,4,3,2}; //创建10个数据,测试
    shellSort(a, 10); //调用希尔排序
    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;
    return 0;
    }

      9 桶排序

        桶排序的基本思想

       假设有一组长度为N的待排关键字序列K[1....n]。首先将这个序列划分成M个的子区间(桶) 。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]....B[M]中的全部内容即是一个有序序列。

    [桶—关键字]映射函数

          bindex=f(key)   其中,bindex 为桶数组B的下标(即第bindex个桶), k为待排序列的关键字。桶排序之所以能够高效,其关键在于这个映射函数,它必须做到:如果关键字k1<k2,那么f(k1)<=f(k2)。也就是说B(i)中的最小数据都要大于B(i+1)中最大数据。很显然,映射函数的确定与数据本身的特点有很大的关系,我们下面举个例子:

    假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。这些数据全部在1—100之间。因此我们定制10个桶,然后确定映射函数f(k)=k/10。则第一个关键字49将定位到第4个桶中(49/10=4)。依次将所有关键字全部堆入桶中,并在每个非空的桶中进行快速排序

        

    #include<iostream>
    #include
    <malloc.h>
    using namespace::std;

    typedef
    struct node{
    int key;
    struct node * next;
    }KeyNode;

    void inc_sort(int keys[],int size,int bucket_size){
    KeyNode
    **bucket_table=(KeyNode **)malloc(bucket_size*sizeof(KeyNode *));
    for(int i=0;i<bucket_size;i++){
    bucket_table[i]
    =(KeyNode *)malloc(sizeof(KeyNode));
    bucket_table[i]
    ->key=0; //记录当前桶中的数据量
    bucket_table[i]->next=NULL;
    }
    for(int j=0;j<size;j++){
    KeyNode
    *node=(KeyNode *)malloc(sizeof(KeyNode));
    node
    ->key=keys[j];
    node
    ->next=NULL;
    //映射函数计算桶号
    int index=keys[j]/10;
    //初始化P成为桶中数据链表的头指针
    KeyNode *p=bucket_table[index];
    //该桶中还没有数据
    if(p->key==0){
    bucket_table[index]
    ->next=node;
    (bucket_table[index]
    ->key)++;
    }
    else{
    //链表结构的插入排序
    while(p->next!=NULL&&p->next->key<=node->key)
    p
    =p->next;
    node
    ->next=p->next;
    p
    ->next=node;
    (bucket_table[index]
    ->key)++;
    }
    }
    //打印结果
    for(int b=0;b<bucket_size;b++)
    for(KeyNode *k=bucket_table[b]->next; k!=NULL; k=k->next)
    cout
    <<k->key<<" ";
    cout
    <<endl;
    }

    int main(){
    int raw[]={49,38,65,97,76,13,27,49};
    int size=sizeof(raw)/sizeof(int);
    inc_sort(raw,size,
    10);
    return 0;
    }

      

       10  鸽巢排序,先统计重复的数据,再排序,减少 比较次数。数度是stl::sort20多倍,stl中的sort采用的是模板化

         的快排的。

        缺点是需要一个size至少等于待排序数组取值范围的缓冲区,不适合int等大范围数据,但是如果内存狗用的话,也可以对int 型的数据进行排序

    void PigeonholeSort(BYTE *array, int length)
    {
    int b[256] = {0};
    int i,k,j = 0;
    for(i=0; i<length; i++)
    b[array[i]]
    ++;
    for(i=0; i<256; i++)
    for(k=0; k<b[i]; k++)
    array[j
    ++] = i;
    }

      对int型的进行排序,有一个问题是下面的程序只能对最大为256 的进行排序

    #include <iostream>
    using namespace std;
    void pigeonholeSort(int a[],int n)
    {
    int j = 0;
    int b[256] = {0};
    for(int i = 0;i < n;i ++)
    b[a[i]]
    ++;

    for(int i = 0;i < 256; i ++)
    for(int k = 0;k < b[i]; k ++)
    a[j
    ++] = i;
    }
    int main()
    {
    int a[10] = {3,4,9,8,5,6,7,2,1,0};
    pigeonholeSort(a,
    10);

    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;

    return 0;
    }

      改进一下:不限制数的大小,根据输入数据的最大值来确定边界

    #include <iostream>
    using namespace std;
    void pigeonholeSort(int a[],int n)
    {
    int j = 0;
    int b[256] = {0};
    for(int i = 0;i < n;i ++)
    b[a[i]]
    ++;

    for(int i = 0;i < 256; i ++)
    for(int k = 0;k < b[i]; k ++)
    a[j
    ++] = i;
    }
    void pigeonholesort2(int a[],int n,int maxValue)
    {
    int j = 0;
    //int b[maxValue] = {0};
    int b[maxValue];

    for(int i = 0; i < maxValue; i ++)
    b[i]
    = 0;
    for(int i = 0;i < n;i ++)
    b[a[i]]
    ++;
    for(int i = 0;i < maxValue; i ++)
    for(int k = 0; k < b[i]; k ++)
    a[j
    ++] = i;
    }
    int main()
    {
    int a[10] = {3,4,9,8,5,6,7,2,1,10};
    pigeonholeSort(a,
    10);

    for(int i = 0;i < 10;i ++)
    cout
    << a[i] << " ";
    cout
    << endl;

    cout
    << "------------------------------" << endl;
    int b[10] = {3,4,9,8,5,6,7,2,1,10};
    int max = 0;
    for(int i = 0;i < 10;i ++)
    if(max < b[i])
    max
    = b[i];

    cout
    << "max value :" << max << endl;
    pigeonholesort2(b,
    10,max);
    for(int i = 0;i < 10;i ++)
    cout
    << b[i] << " ";
    cout
    << endl;
    return 0;
    }

      

      改进版的鸽巢排序,先找出最大、最小值,减少比较次数。

       排序字节串的话速度约是鸽巢排序的一半,多一次遍历的计数排序

    void CountingSort(BYTE *array, int length)
    {
    int t;
    int i, z = 0;
    BYTE min,max;
    int *count;
    min
    = max = array[0];
    //先求最大最小值
    for(i=0; i<length; i++)
    {
    if(array[i] < min)
    min
    = array[i];
    else if(array[i] > max)
    max
    = array[i];
    }
    count
    = (int*)malloc((max-min+1)*sizeof(int));
    for(i=0; i<max-min+1; i++)
    count[i]
    = 0;
    for(i = 0; i < length; i++)
    count[array[i]
    -min]++;
    // 上面的鸽巢排序
    for(t = 0; t <= 255; t++)
    for(i = 0; i < count[t-min]; i++)
    array[z
    ++] = (BYTE)t;
    free(count);
    }

      另外的排序算法还有

       Burstsort,球排序等,明天继续

    http://en.wikipedia.org/wiki/Burstsort 

      http://zh.wikipedia.org/wiki/Bead_sort

    维基百科真强 啊 !

    参考:

    http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/RadixSort.htm

    http://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F

    http://apps.hi.baidu.com/share/detail/18982727

  • 相关阅读:
    HashMap 链表插入方式 → 头插为何改成尾插 ?
    MySQL 日志之 binlog 格式 → 关于 MySQL 默认隔离级别的探讨
    Eclipse
    Delphi
    Delphi
    Delphi
    Delphi
    Delphi
    Delphi
    Delphi
  • 原文地址:https://www.cnblogs.com/hitwtx/p/2149957.html
Copyright © 2011-2022 走看看