无聊写排序之 ---- 冒泡排序(Bubble Sort)

      排序是写代码中经常会遇到的一个问题,不管你是写项目还是写算法,经常会有sort的身影出现。当然排序的算法大大小小有很多种,也有现成的库函数可以直接调用,而且效率比你自己写的要高效很多倍。那为什么还要学排序呢,哈哈 各种排序的实现原理你还是要了解才能去更好的应用在不同的场景和高效高性能的编写code。。。


     排序算法大的分类上分为这么几类(我们这里讲的排序都是内排序):插入排序(直接插入排序算法 , 希尔排序), 选择排序(简单选择排序, 堆排序), 交换排序(冒泡排序,  快速排序), 归并排序(归并排序)。上述7种排序算法也是我们最常见的几种排序算法,今天我们讲解最简单的冒泡排序算法Bubble Sort。

冒泡排序(Bubble Sort):冒泡排序是一种交换排序,将两两相邻的元素进行大小对比,若反序则交换两个元素的位置, 否则进行下两个相邻元素。直到没有反序的元素出现,则停止排序。冒泡算法在实现上有许多不一定的地方,我们先看最常见的一种写法:

交换函数

void Swap(int arr[], int i, int j)
{
	arr[i] = arr[i] + arr[j];
	arr[j] = arr[i] - arr[j];
	arr[i] = arr[i] - arr[j];
}

void Bubble_sort_atypia(int arr[], int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = i+1; j < n; j++)
		{
			if (arr[i] > arr[j])
			{
				Swap(arr, i, j); // 交换两个值
			}
		}
	}
}

        这是最容易实现的一种方式, 将从头开始的每一个元素都和他后面的每一个元素进行对比,这样每次遍历一次都有一个最小的元素被放置在前面的位置上(如下图所示)。但是在严格意义上来讲它并不是标准的冒泡排序,我们讲冒泡排序是将两个相邻的元素进行对比和交换,而上述算法中除了每次遍历的第一组值相邻外其余都不相邻。而且还有一个缺陷:在将最小的数字冒泡到第一个位置的时候对次小的元素可能会换到最下面的位置。如:


在我们将1和2的顺序排好后3这个次小的数字被换到了最后面,这种冒泡算法对于别的元素的排序没有任何帮助,这种排序的效率会比较低,但是最容易书写的。


让我们来看标准的冒泡排序:

void Bubble_sort(int arr[], int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = n-2; j >= i; j--)	// j是从后往前进行的
		{
			if (arr[j] > arr[j+1])		// 比较两个相邻的数据项
			{
				Swap(arr, j, j+1);		// 交换两个相邻的数据 
			}
		}
	}
}


     当i = 0时, j = n-2, 而比较的永远都是k 和k+1两个位置上的元素,也就真正实现了相邻两个元素的比较和交换,这样每一次较小的元素都会想气泡一样冒出水面。

当我们把最小的元素1换到第一个位置的同时, 次小的元素2也被换到了更近的位置,这样在每次排序的过程中对于那些未排序的元素也有帮助,当排序数量少的时候可能还看不出优势来,当数据规模渐变渐大的时候这种优势将会越来越明显的体现出来。


冒泡排序的优化:

试想这样一个问题:当给出的序列基本有序或者完全有序时, 上述的代码会在排序完少数几个序列后仍将继续进行循环比较试图寻找反序的序列进行排序,这样虽然已经没有再做交换了, 但是还是有很多无谓的比较出现,因为此时序列已经有序了。我们改进这个部分,使用一个标志变量来记录上一次循环是否有交换出现,如果没有则说明序列已经有序便可以结束排序。代码如下:

void Bubble_sort_optimize(int arr[], int n)
{
	bool exchange_flag = true;
	for (int i = 0; i < n  && exchange_flag; i++) // 没有交换直接退出
	{
		exchange_flag = false;
		for (int j = n-2; j >= i; j--)	
		{
			if (arr[j] > arr[j+1])		// 比较两个相邻的数据项
			{
				Swap(arr, j, j+1);		// 交换两个相邻的数据 
				exchange_flag = true;
			}
		}
	}
}

冒泡排序的时间复杂度:O(n^2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值