【C++实现】基本排序算法 插入排序——归并排序——快速排序——堆排序

/*
排序总结:(基于100w随机数,有序数、重复数测试)
1、插入排序适合近乎有序的序列
2、归并排序优化:(优化前       120S)
1)数据小于15时采用插入排序 10S
2)避免频繁动态申请内存 memcpy(dest,src,sizeof(int)*len) 用static 变量      0.2S
缺点:需要O(N)的空间复杂度

3、快速排序优化:(优化前 如果序列完全有序,则程序直接栈溢出,如果序列为随机数  0.7S)
1)随机选择枢轴 可有效避免近乎有序序列排序慢的情况 尽量不用swap使用节约一次赋值的时间    0.4S
2) 数据小于15时采用插入排序  0.2S
优点:空间复杂度O(log(n))
缺点:近乎有序时效率不高

4、堆排序 :先heapify 在从小到大排
优点:空间复杂度O(1) 原地排序
*/


#include<ctime>
inline void swap2(int &a, int &b){
	int c = a;
	a = b;
	b = c;
}

//插入排序 
void insertSort(int arr[], int lo, int hi){
	for (int i = lo; i < hi; i++){
		int e = arr[i];
		int j;
		for (j = i; j >lo && e < arr[j - 1]; j--)//判断条件放在for内部会导致错误
			arr[j] = arr[j - 1];
		arr[j] = e;
	}
}
void insertSort(int arr[], int n){
	insertSort(arr, 0, n);
}

//归并排序
void Merge(int arr[], int lo, int mi, int hi){
	int lb = mi - lo;
	int lc = hi - mi;
	int* A = arr + lo;
	static int* B = new int[10000000 / 2];//此处优化后只需0.2S
	int* C = arr + mi;
	memcpy(B, A, lb*sizeof(int));
	for (int i = 0, j = 0, k = 0; j < lb || k < lc;){
		if (j < lb && (k >= lc || B[j] < C[k])) A[i++] = B[j++];
		if (k < lc && (j >= lb || B[j] >= C[k])) A[i++] = C[k++];
	}
	//delete[] B;
}
void __mergeSort(int arr[], int lo, int hi){
	//if (hi - lo < 2) return;//100w数据需要121.2S  使用插入排序优化后只需10.1S 
	if (hi - lo <= 15) {
		insertSort(arr, lo, hi);
		return;
	}
	int mi = lo + (hi - lo) / 2;
	__mergeSort(arr, lo, mi);
	__mergeSort(arr, mi, hi);
	Merge(arr, lo, mi, hi);
}
void mergeSort(int arr[], int n){
	__mergeSort(arr, 0, n);
}
int partition(int arr[], int lo, int hi){
	swap2(arr[lo], arr[rand() % (hi - lo) + lo]);
	int e = arr[lo];
	int i = lo + 1, j = hi - 1;
	while (true)
	{
		while (i <= j && arr[i] < e) i++; // 从左向右找第一个小于x的数
		while (i <= j && arr[j] > e) j--;// 从右向左找第一个大于等于x的数		
		if (i > j) break;
		swap2(arr[i++], arr[j--]);
	}
	swap2(arr[lo], arr[j]);
	return j;
}
int partition2(int arr[], int lo, int hi){
	swap2(arr[lo], arr[rand() % (hi - lo) + lo]);
	int e = arr[lo];
	hi--;
	while (lo<hi)
	{
		while (lo < hi && arr[hi] > e) hi--;// 从右向左找第一个大于等于x的数
		if (lo < hi) arr[lo++] = arr[hi];
		while (lo < hi && arr[lo] < e) lo++; // 从左向右找第一个小于x的数
		if (lo<hi) arr[hi--] = arr[lo];
	}
	arr[lo] = e;
	return lo;
}
void quickSort(int arr[], int lo, int hi){
	//if (hi - lo < 2) return;
	if (hi - lo <= 15) {
		insertSort(arr, lo, hi);
		return;
	}
	int j = partition2(arr, lo, hi);
	quickSort(arr, lo, j);
	quickSort(arr, j + 1, hi);
}
void quickSort(int arr[], int n){
	srand(time(NULL));
	quickSort(arr, 0, n);
}

//堆排序
void shiftDown(int arr[], int k, int n){
	int e = arr[k];
	int j = k;
	while (k * 2 + 1 < n){
		j = k * 2 + 1;
		if (j + 1 < n&&arr[j + 1] > arr[j]) j++;
		if (arr[j] > e) {
			arr[k] = arr[j];
			k = j;
		}
		else break;//注意break
	}
}
void heapSort(int arr[], int n){
	for (int i = (n - 2) / 2; i >= 0; i--){
		shiftDown(arr, i, n);
	}
	for (int i = n - 1; i >= 0; i--){
		swap2(arr[0], arr[i]);
		shiftDown(arr, 0, i);
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值