排序算法(插入类排序)


根据耿国华老师的sopc课程总结(都以从小到大排序为例)

插入类排序

直接插入排序

将第i个记录直接插入到前面排好序的i-1个记录中。将第i个记录K_i顺次与前面i-1个记录比较,将所有大于K_i的记录向后移,当遇到一个小于或者等于K_i的记录时,该记录后必有一个空位,此时把K_i插入空位即可
完整的直接插入排序从i=2开始,将第一个记录记为已排好序的序列

//直接插入排序 
void InsSort(int *num, int len){
	if(num == NULL || len == 0){
		return;
	}
	
	for(int i = 2; i < len; i ++){	
		num[0] = num[i];	//监视哨
		int j = i - 1; 
		while(num[j] > num[0]){
			num[j+1] = num[j];	//后移数字 
			j --;
		}
		num[j+1] = num[0];	//插入到空位中 
	}
}

从时间耗费角度来看,主要时间耗费在关键字比较和移动元素上
对于一趟排序:
最好:顺序,while循环执行1次,且不移动记录
最坏:逆序,while循环执行和移动记录都为i-1次
对整个排序:
最好:已排好序(顺序),总的比较次数为n-1,移动记录次数为2(n-1),每次只对待插记录移动两次
最坏:逆序排列,总比较次数为(n+2)(n-1)/2,即i从i=2到i=n的累加和,移动记录次数也达到最大(n+4)(n-1)/2,即i+1从i=2到i=n的累加和
则算法时间复杂度为O(n^2),空间复杂度为O(1)

折半插入排序

利用折半查找思想在有序排列的i-1个记录中确定应插入位置

void BinSort(int *num, int len){
	int low, high, mid, x;
	for(int i = 2; i < len; i ++){
		x = num[i];
		low = 1;
		high = i - 1;
		while(low <= high){
			mid = (low + high) / 2;
			if(x < num[mid]){
				high = mid - 1;
			}
			else{
				low = mid + 1;
			}
		}
		for(int j = i-1; j >= low; j --){
			num[j+1] = num[j];	//记录后移 
		}
		num[low] = x;
	}
}

每插入一个元素,需要比较的次数最大为折半查找树的深度,如插入第i个元素时,需要进行log2n,因此插入n-1个元素的平均比较次数为nlog2n
虽然折半插入排序与直接插入排序比较,改善了比较次数的数量级为O(nlog2n),但未改变移动元素的时间耗费,故其时间复杂度为O(n^2)

希尔排序

先将待排序记录序列分割成若干个“较稀疏”的子序列,分别进行插入排序

  1. 首先选定记录间的距离为d_i(i=1),在整个待排序记录序列中将所有间隔d_i的记录分成一组,进行组内直接插入排序
  2. 然后取i=I+1,记录间距离为d_i(d_i<d_i-1),在整个待排序记录序列中将所有间隔d_i的记录分成一组,进行组内直接插入排序
  3. 重复步骤2,直到d_i=1,此时只有一个子序列,对该序列进行直接插入排序,完成整个排序过程
void ShellInsert(int *num, int len, int delta){
	int i, j;
	for(i = 1+delta; i < len; i ++){
		if(num[i] < num[i-delta]){
			num[0] = num[i];
			for(j = i-delta; j > 0 && num[0] < num[j]; j -= delta){
				num[j+delta] = num[j];
			}
			num[j+delta] = num[0];
		}
	}
}
void ShellSort(int *num, int len, int *delta, int n){
	for(int i = 0; i < n; i ++){
		ShellInsert(num, len, delta[i]);
	}
} 

时间复杂度为O(n^1.5)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值