排序进阶基础

点击跳到直接插入排序
点击跳到希尔排序
点击跳到基数排序

3.1、排序的分类

在这里插入图片描述


3.1.1、排序的分类

根据排序过程所用策略的不同,可将内部排序方法分为5类:交换排序、选择排序、插入排序、归并排序和基数排序。其中交换排序、选择排序和插入排序是一个逐步扩大记录的有序序列长度的过程。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


3.2、直接插入排序

算法思想:每次将无序区的第一个记录按关键字插入到有序区的合适位置,并将有序区的长度加1. 假设记录个数为8,输入关键字序列为(56,68,25,45,90,38,10,72),每一趟插入排序的结果如图所示

在这里插入图片描述
第i躺插入排序若需将记录L.rcd[i+1]插入到有序区L.rcd[1…i]中,则应先执行以下步骤在这里插入图片描述

void InsertSort(RcdSqList &L){//对顺序表L作直接插入排序
	int i,j;
	for(i=1;i<L.length;i++)
		if(L.rcd[i+1].key<L.rcd[i].key){//需将L.rcd[i+1]插入到有序序列中
				L.rcd[0]=L.rcd[i+1];//先将记录L.rcd[i+1]保存在空闲的0号单元
				j=i+1;
				do{//记录后移
					j--;
					L.[j+1]=L.rcd[j];
				}while(L.rcd[0].key<L.rcd[j-1].key);//判断是否需要继续后移
		}
		L.rcd[j]=L.rcd[0];//插入
}

在这里插入图片描述


3.3、希尔排序

希尔排序的思路:

在这里插入图片描述
希尔排序的演示:
在这里插入图片描述

希尔排序与直接插入排序的差别:
在这里插入图片描述

一趟希尔排序:

void ShellInsert(RcdSqList & L,int dk){
	//对顺序表L作一趟希尔排序,增量为dk
	int i,j;
	for(i=1;i<=L.length-dk;i++)
		if(L.rcd[i].key>L.rcd[i+dk].key){
		//需将L.rcd[i+dk]插入到有序序列
			L.rcd[0]=L.rcd[i+dk];//暂存再L.rcd[0]
			j=i+dk;
			do{//记录后移
				j-=dk;
				L.rcd[j+dk]=L.rcd[j];
			}while(j-dk>0&&L.rcd[0].key<L.rcd[j-dk].key);//是否继续移动
		L.rcd[j]=L.rcd[0];//插入
		}
}

希尔排序:

void ShellSort(RcdSqList & L,int d[],int t){
	//按增量序列d[0..t-1]对顺序表L作希尔排序
	int k;
	for(k=0;k<t;k++)
		ShellSort(L,d[k]);
}

希尔排序的时间复杂度是所取增量序列的函数,尚难准确分析。且希尔排序是不稳定的排序,如(56,34,47,23,66,18,47),若排序结果为(18,23,34,47,47,56,66)则称该排序方法是稳定的;若排序结果为(18,23,34,47,47,56,66)则称该排序方法是不稳定的。


3.4、基数排序

在这里插入图片描述
在这里插入图片描述
基数排序的数据类型定义如下:

typedef struct{
	KeysType * keys;//关键字
	...//其他数据项
}KeysRcdType;//基数排序中的记录类型
typedef struct{
	KeysRcdType *rcd;//0号位置放哨兵
	int length;//顺序表长度
	int size;//顺序表容量
	int digitNum;//关键字位数
	int radix;//关键字基数
}KeysSqList;//顺序表类型

在这里插入图片描述
在这里插入图片描述
基于count数组,依次计算关键字从0到9的记录的起始位置,存入数组pos。值为0的关键字的起始位置为1,值为j(1<=j<=9)的关键字的起始位置是值为j-1的关键字的起始位置加上值为j-1的关键字的个数,如图所示在这里插入图片描述
第一趟收集时由337的个位数7取得器起始位置pos[7]的值6,将337放入rcd1[6]中,并将pos[7]加1,令pos[7]指向下一个个位数为7的记录应放入的位置。接着,由332的个位数2取得其起始位置pos[2]的值为2,将332放入rcd1[2]中,并将pos[2]加1.在这里插入图片描述
继续上述过程,第一趟收集的结果如下图所示:
收集的代码如下:

for(k=1;k<=n;k++){//第i躺收集
	j=rcd[k].keys[i];
	rcd1[pos[j]++]=rcd[k];//复制记录,对应的起始位置加1
}

在这里插入图片描述

第三趟对百位数进行分配和收集,将记录从数组rcd收集到数组rcd1,分配和收集的结果分别如下图所示。第三趟收集的结果就是最后排序的结果。由于趟数为奇数,须将数组rcd1复制回rcd。
在这里插入图片描述

计数基数排序:

Status RadixSort(KeysSqList &L){//对顺序表L进行计数基数排序
	KeysRcdType *rcd1;//开设同等大小的辅助空间用于复制数据
	int i=0,j;
	int *count,*pos;
	count=(int *)malloc(L.radix*sizeof(int));
	pos=(int *)malloc(L.radix*sizeof(int));
	rcd1=(KeysRcdType *)malloc((L.length+1)*sizeof(KeysRcdType));//
	if(NULL==count||NULL==pos||NULL==rcd1)
		return OVERFLOW;
	while(i<L.digitNum){
		for(j=0;j<L.radix;++j)
			count[j]=0;
		if(0==i%2)//对L.rcd进行一趟基数排序,结果存入rcd1
			RadixPass(L.rcd,rcd1,L.length.i++,count,pos,L.radix);
		else//对rcd1进行一趟基数排序,结果存入L.rcd
			RadixPass(rcd1,L.rcd,L.length.i++,count,pos,L.radix);
	}
	if(1==L.digitNum%2)//排序后的结果在rcd1中,复制至L.rcd中
		for(j=1;j<=L.length;j++)
			L.rcd[j]=rcd1[j];
	free(count);
	free(pos);
	free(rcd1);
	return OK;
}

一趟计数基数排序:

void RadixPass(KeysRcdType rcd[],KeysRcdType rcd1[],int n,int i,int count[],int pos[],int radix){
//对数组rcd中记录关键字的第i位计数,计算得到起始位置数组pos[]
//并按照pos数组将数组rcd中记录复制到数组rcd1中
	int k,j;
	for(k=1;k<=n;k++)//对各种取值计数
		count[rcd[k].keys[i]]++
	pos[0]=1;
	for(j=1;j<radix;j++)//求起始位置
		pos[j]=count[j-1]+pos[j-1];
	for(k=1;k<=n;k++){//收集
		j=rcd[k].key[i];
		rcd1[pos[j]++]=rcd[k];
	}
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值