冒泡排序算法的各种优化(C/C++)

冒泡排序大家都很熟悉,但优化到极致的冒泡算法,大家知道吗?今天我们介绍的算法,就是根据冒泡算法优化而来的,鸡尾酒排序(cocktail sort)。

根据冒泡排序的思想,我们不难得出,每次都会有最小或者最大(取决于升序还是降序)的数字放到数组最后的位置,倘若本轮循环并未发生交换,则说明数组已经有序。

同时,处于发生交换的位置之后的数据,已经是有序的状态。

根据这两点,我们做两个优化:

(1)设定一个bool变量,用来记录本轮循环是否发生交换,如果没有,可以直接break掉大循环。

(2)设定一个int变量,用来记录最后一次发生交换的位置,下次循环只需要循环到这个位置,就可以结束。

先写一个swap函数用以交换两个变量:

void swap(int *a, int *b)
{
	if (*a == *b)
		return;

	*a ^= *b;
	*b ^= *a;
	*a ^= *b;
}

注意:这里if一定要写上,否则如果a和b指向的地址相同,则不能正常完成交换(也可以这么想,相等的情况下,又何必有下面交换的过程呢?)

根据上面优化的思路,我们得到了第一个冒泡排序优化的版本:

void bubble_sort(int* a, int n)
{
	int nExchangeIndex = n - 1;
	for (int i = 0; i < n; ++i)
	{
		bool boMark = false;
		int nSortBroad = nExchangeIndex;
		for (int j = 0; j < nSortBroad; ++j)
		{
			if (a[j] > a[j + 1])
			{
				swap(&a[j], &a[j + 1]);
				boMark = true;
				nExchangeIndex = j;
			}
		}

		if (!boMark)
			break;
	}
}

做到这里,其实冒泡排序已经是很完善了,但是还有一种特殊情况,比如待排序序列为:{1,2,3,4,5,6,7,8,9,0}。

这种情况下,显然大部分序列已经有序,唯独一个0,打破了沉寂,非要战战兢兢地跑完所有循环,才能排序成功,那这种情况,我们又该如何应对呢?

这就引出了我们的重头戏,鸡尾酒排序。

鸡尾酒排序实际就是在冒泡排序上优化而来,一次大循环内,写两个小循环,第一个从头到尾冒一遍,第二个从尾到头冒一遍,如此一轮大循环后,刚刚的例子就已经有序,在第二轮大循环过后,循环将会因为没有交换而break。

废话不多讲,直接上代码:

void cocktail_sort(int* a, int n)
{
	int nMidLen = n >> 1;    //由于大循环内会顺逆两次小循环,所以大循环只需要循环到数组个数的一半

	int nExchangeIndex1 = n - 1;
	int nExchangeIndex2 = 0;
	for (int i = 0; i < nMidLen; ++i)
	{
		bool boMark = false;
		int j;

		int nSortBroad = nExchangeIndex1;
		for (j = nExchangeIndex2; j < nSortBroad; ++j)
		{
			if (a[j] > a[j + 1])
			{
				swap(a + j, a + j + 1);
				boMark = true;
				nExchangeIndex1 = j;
			}
		}

		if (!boMark)
			break;

		nSortBroad = nExchangeIndex2;
		for (j = nExchangeIndex1; j > nSortBroad; --j)
		{
			if (a[j - 1] > a[j])
			{
				swap(a + j - 1, a + j);
				boMark = true;
				nExchangeIndex2 = j;
			}
		}

		if (!boMark)
			break;
	}
}

注意,我们这鸡尾酒排序依旧可以使用刚刚的两个优化技巧,记录是否交换,记录最后交换的位置。

这个,我愿称之为冒泡排序的究极体,虽然他的时间复杂度并没有变化,但实际运用起来,基本都会比原始的冒泡排序快上一些。

曾经作为面试官考过这个题目,发现有大部分的都并不知道冒泡排序能进行优化,故拿出来分享一下,大家一起学习!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值