排序算法--冒泡与选择

排序算法有很多,在我们学习数组那一章节的时候,就给大家列过许多的排序代码。本节我们讲两个比较简单的排序算法:冒泡排序与选择排序


冒泡排序

排序思想

相邻两个元素进行比较,将较大者(或者较小者)作为泡给冒出去,也就是交换,当数组所有相邻元素都进行比较过后,最后一个值一定是最大的(或者是最小的)。然后对这样的一个操作进行循环操作,来使所有的最大值(最小值)依次排到数组后面。

排序图解

第一步:从左向右,依次两两比较,将最大的元素放到待排元素区的最后位置。(即下标n-1位置)

第二步: 采用相同的方法,再次遍历 ,将第二大的数,放在数组倒数第二个位置(即n-2的位置),以此类推,直至数组有序。

 代码实现

void BubbleSort(int* arr, int size)
{
	for (int i = 0; i < size - 1; i++) {
		for (int j = 0; j < size - 1 - i; j++) {
			if (arr[j] > arr[j + 1]) {
				swap(arr[j], arr[j + 1]);
			}
		}
	}
}

 时间复杂度分析

外层循环代表排序的趟数,内层循环代表比较的次数。随着趟数的变化,内层的比较也会依次减少。即总共执行次数为:n-1 + n-2 + n-3 +...+3+2+1=n(n-1)/2,时间复杂度为O(n²)。稳定性:稳定排序。

优化方向

如果有一趟没有进行交换,剩下的趟数必然无法发生交换,后续的比较均是拉低效率的执行。所以设置一个标志变量,来判断是否排序已经完成。

//冒泡排序:时间复杂度 O(n^2),稳定
void BubbleSort(int* arr, int size)
{
	for (int i = 0; i < size - 1; i++) {
		bool flag = true;//flag代表排序是否完成
		for (int j = 0; j < size - 1 - i; j++) {
			if (arr[j] > arr[j + 1]) {
				swap(arr[j], arr[j + 1]);
				flag = false;//交换说明还不知道排序完成了没有
			}
		}
		if (flag)return;//如果完成,就不用接着排了,直接跳出去吧
	}
}

选择排序

排序思想

选择排序是将未排序的部分中元素的最大值(最小值)找出来。与未排序区的最后一个元素进行交换。找最值的方式是通过记录数组的下标(索引/位置)实现的。循环进行上述操作,直至排序完成。

排序图解

我们想要将这个列表中的数据按照播放次数按升序排列。

 第一步:找出列表中播放次数最多的元素,将它与列表最后一个位置的元素进行交换

 第二步:再次这样做,找到播放次数第二多的歌曲

继续这样做,最后将得到一个有序列表:

代码实现


void SelectSort(int* arr, int size)
{
	for (int i = 0; i < size; i++) {
		int index = i;
		for (int j = i + 1; j < size - 1; j++) {
			if (arr[j] < arr[index])
				index = j;
		}
		swap(arr[i], arr[index]);
	}
}

时间复杂度分析

外层循环是排序的趟数,从零索引位到size-1索引位都需要进行比较。内层循环是比较的次数,将无序区的最大值的索引坐标index找到然后交换。随着趟数的增加,有序区的元素逐渐增多,无需区的元素逐渐减少,所以,该事件复杂度分析方法同冒泡类似,最终结果一样,为O(n²)。

优化方向

思考,进行一次比较快还是执行一次交换操作快?显然判断的效率大于交换的效率。

那么假如排序提前完成,后续的交换都是最后一个元素本身在进行交换,不断地执行交换操作。

//选择排序:时间复杂度 O(n^2),不稳定
void SelectSort(int* arr, int size)
{
	for (int i = 0; i < size; i++) {
		int index = i;
		for (int j = i + 1; j < size - 1; j++) {
			if (arr[j] < arr[index])
				index = j;
		}
		if (index != size - 1)//加if只是为了提升一点点效率,可不要判断,直接交换
			swap(arr[i], arr[index]);
	}
}

其实差别就在于if判断条件这一句代码。但优化的力度非常的小,不写也行,区别不大,而且如果每次都进行判断,执行n次,就会无辜多出n次判断操作,但假如一开始为有序数组,判断的时候就会用n次的判断操作替代执行n次的交换操作,交换操作一般为临时变量法实现,最少具有3句指令。所以,这个优化纯属看心情。


感谢大家!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值