交换和归并排序

1.1冒泡排序

void BubbleSort(int* a, int n) {
	for (int i = 0; i < n; i++) {
		int mark = 0;
		for (int j = 0; j < n-1-i; j++) {
			if (a[j] > a[j + 1]) {
				Swap(&a[j], &a[j + 1]);
				mark = 1;
			}
		}
		if (mark == 0) {
			break;
		}
	}
}

冒泡排序是一种简单的排序算法,其基本思想是通过比较相邻的元素并交换位置,使较大的元素逐渐“浮”到数组的末尾,而较小的元素则逐渐“沉”到数组的开始。具体步骤如下:

  1. 从数组的第一个元素开始,依次比较相邻的两个元素。如果前一个元素大于后一个元素,就将它们交换位置。
  2. 继续向后依次比较相邻的元素,重复上述操作,直到到达数组的倒数第二个元素。
  3. 重复执行上述操作,每次比较会将当前未排序部分的最大元素移动到末尾。
  4. 重复2和3的步骤,直到整个数组有序。

冒泡排序的时间复杂度为O(n^2),其中n为数组的长度。尽管冒泡排序的时间复杂度较高,但它是一种稳定的排序算法,适用于小规模数据的排序操作。

我们来测试一下:

1.2快速排序

void QuickSort1(int* a, int left, int right) {
 //前后指针,cur,prev先走 cur碰到比keyi大的数据就++,小的数就停下,prev++,然后交换,最后keyi与prev交换
	if (left>=right) {
		return;
	}
	//小区间优化,数据较小时采用插入排序可减少90%的递归消耗
	if (right - left+1 <= 10) {//这里的加一是因为right为数组的下标,例如有10个数 right为9 left为0 
		InsertSort(a + left, right - left + 1);//这里的a+left为插入的初始位置,每次的初始位置肯可能不同
	}
	else {


		int keyi = left;
		int prev = left; int cur = left + 1;
		while (cur <= right) {
			if (a[cur] <= a[keyi] && ++prev != cur)
				Swap(&a[prev], &a[cur]);
			++cur;
		}
		Swap(&a[keyi], &a[prev]);
		keyi = prev;
		QuickSort1(a, left, keyi - 1);
		QuickSort1(a, keyi + 1, right);
	}
}

在快速排序中我们的key的选择,堆整个排序的效率起着很大的作用,我们只要让其几乎每次都不是最小或者最大即可。

在这里就出现了随机数取key和三数取中的方法。

随机数选key:

// 100 200 注意这里的left不一定为0
//选[left right]区间的随机数与第一个数据交换做key.
srand(time(0));
int randi = rand() % (right - left+1 );//这里的加一是为了刚好达到该区间,例如rand()%100的区间为0~99 .
randi += left;//randi+left后才会达到该区间
Swap(&a[left],&a[randi]);

三数取中:

//拿到三数数值中间的数,这样就可以避免选key的时候,选到最小或最大值
int GetMidi(int* a, int left, int right) {
	int midi = (right - left) / 2;
	if (a[left] > a[right]) {
		if (a[right] < a[midi]) {
			return midi;
		}
		else if (a[left] < a[midi]) {
			return left;
		}
		else
			return right;
	}
	//a[left] < a[right]
	else
	{
		if (a[right] < a[midi]) {
			return right;
		}
		else if (a[left] > a[midi]) {
			return left;
		}
		else
			return midi;
	}
}

快速排序基于分治的思想,通过将序列分割成较小的子序列来解决问题。在每一趟排序中,通过在序列中移动元素,将基准元素放置到最终排序位置的同时,也将序列划分为两个子序列。递归地应用快速排序可以使得整个序列有序。

快速排序的时间复杂度为O(nlogn)(最坏情况下为O(n^2)),其中n为序列的长度。快速排序是一种不稳定的排序算法。

2.1归并排序

//归并排序:将数组不断分成一个数据后开始递归回去合并
//时间复杂度:O(N*logN)
void _MergeSort(int* a, int begin, int end, int *tmp) {
	if (begin == end) {
		return;
	}
	int mid = begin+(end - begin) / 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 = begin; 
	//依次比较,取小的尾插tmp数组
	while (begin1 <= end1 && begin2 <= end2) {
		if (a[begin1] <= a[begin2]) {
			tmp[i++] = a[begin1++];
		}
		else {
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1) {
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2) {
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

void MergeSort(int* a, int n) {
	int *tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL) {
		perror("malloc fail");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
 }

归并排序(Merge Sort)是一种基于分治法的排序算法,它的基本思想是将待排序序列分成若干个子序列,分别进行排序,然后再将已排序的子序列合并成一个有序的序列,从而达到整个序列有序的目的。

具体步骤如下:

  1. 将待排序序列不断二分,直到每个子序列只有一个元素为止。
  2. 对每个子序列进行排序,可以通过递归地调用归并排序来实现。
  3. 将排好序的子序列进行合并,形成一个有序的序列。

在归并排序中,合并操作是关键步骤。合并操作需要额外的空间来存储已排序的子序列,因此归并排序需要辅助的空间来存储合并结果。

归并排序的时间复杂度为O(nlogn),其中n为序列的长度。归并排序是一种稳定的排序算法,因为在合并操作中,相等的元素在合并的过程中不会改变它们的相对位置。

归并排序是一种经典的排序算法,它不仅时间复杂度较低,而且稳定性好,适合各种规模的数据排序。

谢谢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c23856

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值