数据结构——二路归并排序和基数排序

本文详细介绍了两种排序算法——二路归并排序和基数排序。二路归并排序采用分治思想,通过递归划分和归并操作实现排序,时间复杂度为O(nlogn)。基数排序则根据关键字的每一位进行分配和收集,适用于非负整数排序,其时间复杂度为O(d(n+r)),稳定且与初始顺序无关。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二路归并排序

算法原理

假设该数组为q,左边界为 l,右边界为 r,并设置临时数组tmp。

采用分治思想:
第一步:确定分界点: mid = l + r >>1。
第二步:递归划分左右两段。
第三步:归并(合二为一):将左右两段在 tmp 中排好序,并将tmp中排好序的数据拷回 q 的相应位置。

代码实现
#include<iostream>
using namespace std;

const int N = 100010;
int q[N], tmp[N];

void merge_sort(int q[], int l, int r){
    if(l >= r) return;
    
    int mid = l+r>>1;
    merge_sort(q, l, mid);
    merge_sort(q, mid+1, r);
    
    int i = l, j = mid+1, k = 0;
    while(i <= mid && j <= r) 
        if(q[i] < q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    while(i <= mid) tmp[k++] = q[i++];
    while(j <= r) tmp[k++] = q[j++];
    
    for(i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
}

int main(){
    int n;
    scanf("%d", &n);
    for(int i=0; i<n; i++) scanf("%d", &q[i]);
    merge_sort(q, 0, n-1);
    for(int i=0; i<n; i++) printf("%d ", q[i]);
    return 0;
}
性能分析
  • 空间效率:使用临时数组tmp,共n个单元,所以空间复杂度为O(n)O(n)O(n)
  • 时间效率:每趟归并的时间复杂度为O(n)O(n)O(n),共需要进行⌈log⁡2n⌉\lceil\log_2n\rceillog2n趟归并,所以时间复杂度为O(nlog⁡2n)O(n\log_2n)O(nlog2n)
  • 稳定性:稳定

基数排序

算法原理
  • 基于关键字各位大小进行排序。
  • 最高位优先法(MSD),按关键字位权重递减依次逐层划分成若干个更小的子序列,最后将所有子序列依次连接成一个有序序列。
  • 最低位优先法(LSD),按关键字权重递增依次进行排序,最后形成一个有序序列
  • 排序过程(以最低位优先法为例)
    • 假设长度为nnn的线性表中每个结点aja_jaj的关键字为一个ddd元组(kjd−1,kjd−2,…,kj1,kj0k_j^{d-1},k_j^{d-2},…,k^1_j,k^0_jkjd1,kjd2,,kj1,kj0),满足0<=kji<=r−1(0<=j<n,0<=i<=d−1)0<=k_j^i<=r-1(0<=j<n,0<=i<=d-1)0<=kji<=r1(0<=j<n,0<=i<=d1),其中kjd−1k_j^{d-1}kjd1为最主位关键字,kj0k_j^0kj0为最次位关键字。
    • 使用rrr个队列Q0,Q1,…,Qr−1Q_0,Q_1,…,Q_{r-1}Q0,Q1,,Qr1
    • i=0,1,…,d−1i=0,1,…,d-1i=0,1,,d1,依次做一次“分配”和“收集”。
      • 分配:开始时,把各个队列设为空队列,然后依次考察每个结点aja_jaj,若aja_jaj关键字kji=kk^i_j=kkji=k,则把aja_jaj放进QkQ_kQk队列中
      • 收集:将各个队列中的结点依次首尾相接,得到新的结点序列
代码实现
void RadixSort(int A[], int n){
	int temp[10][n];			// 10个辅助队列
	int len[10];				// 记录每个队列中的数据个数
	int max=A[1];				// 记录最大值
	for(int i=2; i<=n; i++)
		if(max < A[i])
			max = A[i];
	int s=max, count=0;				// count记录最大值的位数
	while(s){
		s = s/10;
		count++;
	}
	for(int j=1, x=1; j<=count; j++, x*=10){
		for(int i=0; i<10; i++)	len[i]=0;		// 初始化
		// 分配
		for(int k=1; k<=n; k++){
			int elem = (A[k]/x)%10;		// 取相应位置的数
			temp[elem][len[elem]++] = A[k];
		}
		// 收集
		int cnt=1;
		for(int y=0; y<10; y++)
			for(int z=0; z<len[y]; z++)
				A[cnt++] = temp[y][z];
		printf("第%d趟:", j);
		for(int k=1; k<=n; k++) printf("%d ", A[k]);
        printf("\n");
	}
}
举例

在这里插入图片描述

性能分析
  • 空间效率:需要辅助存储空间为r个队列,所以时间复杂度为O(r)O(r)O(r)
  • 时间效率:需要进行d趟排序(分配和收集),一趟分配需要O(n)O(n)O(n),一趟收集需要O(r)O(r)O(r),所以其时间复杂度为O(d(n+r))O(d(n+r))O(d(n+r)),且与序列的初始状态无关
  • 稳定性:稳定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值