归并排序与基数排序

你好,我是史丰源
欢迎你的来访,希望我的博客能给你带来一些帮助。

我的Gitee:代码仓库



在进入正文之前,一般排序的方法就是:

1.比较关键字的大小

2.不合适就移动数据


这里的归并排序与基数排序是一样的。

归并排序

概念(来自Wikipedia)

归并排序(也通常拼写为归并排序)是一种高效、通用且基于比较的 排序算法。大多数实现产生一个稳定的排序,这意味着相等元素的顺序在输入和输出中是相同的。归并排序是约翰·冯·诺依曼在 1945年发明的一种分而治之的算法。 [2]自下而上归并排序的详细描述和分析早在 1948 年就出现在Goldstine和 von Neumann 的报告中。 [3 ]

实现算法(来自Wikipedia)

从概念上讲,归并排序的工作原理如下:

  1. 将未排序列表划分为n个子列表,每个子列表包含一个元素(一个元素的列表被视为已排序)。
  2. 重复合并子列表以产生新的排序子列表,直到只剩下一个子列表。这将是排序列表。

归并时需要借助额外的数组tmp

看下面这个待排序的数组,我们将会把它分为两个部分(类似递归,直到分到最后一个数据元素)。

区间有序就进行归并,然后逐级返回并且归并,就可以完成排序。

在这里插入图片描述
在这里插入图片描述

void _MergeSort(int* a,int begin,int end,int* tmp)
{
    if(begin>=end)//不须分割了
        return ;
    
    int mid = (begin+end)/2;
    
    //左区间(begin,mid)右区间(mid+1,end)
   _MergeSort(a,begin,mid,tmp);
   _MergeSort(a,mid+1,end,tmp);//不断细分的一个过程
    
    //归并 归并完就是有序的了
    int begin1 = begin,end1 =mid;
    int begin2 = mid+1,end2 = end;
    int i = begin1;//下标标识
    while(begin1 <= end1 && begin2 <= end2)
    {
        if(a[begin1] < a[begin2])
        {
            tmp[i++] = a[begin1++]; //往tmp里拷数字
		}
        else 
        {
            tmp[i++] = a[begin2++];
		}
	}
    
    while(begin1<=end1)
    {
        tmp[i++] = a[begin1++];
    }
    while(begin2<=end2)//有一个必然结束
    {
        tmp[i++] = a[begin2++];
    }
    
    //把归并数据拷贝回原数组
    memcpy(a+begin,tmp+begin,(end-begin+1)*sizeof(int));
    
}
void MergeSort(int *a,int n)
{
    int *tmp =(int*)malloc(sizeof(int)*n);
    if(tmp == NULL)
    {
        printf("malloc fail\n");
        exit(-1);
    }
    _MergeSort(a,0,n-1,tmp);
    free(tmp);
}

基数排序

概念(来自Wikipedia)

基数排序是一种非比较 排序算法它通过根据radix创建元素并将其分配到存储桶中来避免比较。对于具有多个有效数字的元素,对每个数字重复此分桶过程,同时保留前一步的顺序,直到所有数字都被考虑在内。因此,基数排序也被称为**桶排序数字排序**。

基数排序可以应用于可以按字典顺序排序的数据,无论是整数、单词、穿孔卡片、扑克牌还是邮件

举例(来自Wikipedia)

有两种模式MSD最高位优先 LSD最低位优先

我们这里讲实现LSD最低位优先规则.

LSD最低位优先:
在这里插入图片描述

从最低位排序,排序完再向上取高位再排序。重复这个过程,直到排序完成。

在这里插入图片描述

回收数据

在这里插入图片描述

核心思想:

1.分发数据

2.回收数据

#include<queue>
#define K 3
#define RADIX 10
queue<int> Q[RADIX];

//构造10个队列 10个基数 先进先出

int GetKey(int value,int k)//根据第几次取关键字 对应取关键字
{
    int key = 0;
  while(k>=0)
  {
      key = value%10;
      value/=10;
      k--;
  }
    return key;
}

void Distribute(int arr[],int left,int right,int k)
{
    for(int i =left;i<right;++i)
    {
        int key = GetKey(arr[i],k);
        Q[key].push(arr[i]);
        
	}
}

void Collect(int arr[])
{
    int k = 0;
    for(int i =0;i<RADIX;++i)
    {
        while(!Q[i].empty())
        {
            arr[k++] = Q[i].front();
            Q[i].pop();
		}
	}
}

void RadixSort(int arr[],int left,int right)
{
    for(int i = 0;i<K;++i)
    {
        //分发数据
        Distribute(arr,left,right,i);
        //回收数据
        Collect(arr);
	}
}

int main()
{
    int arr[] = {278,109,63,930,589,184,505,269,8,83};
    int n = sizeof(arr)/sizeof(arr[0]);
    for(int i = 0;i<n;++i)
    {
		printf("%d ",arr[i]);
    }
    printf("\n");
    RadixSort(arr,0,n);
    for(int i = 0;i<n;++i)
    {
		printf("%d ",arr[i]);
    }
    printf("\n");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值