八大排序之冒泡排序和冒泡排序的优化

一、冒泡排序的思想
冒泡排序是交换排序的一种。
冒泡排序顾名思义,类似于大石头向下沉的问题,它的思想也就是大数据向后移,小数据向前移。
二、图解冒泡排序
给定一组数据
[12 3 21 32 1 34 12 35 34 18]
1、第一趟排序
定义两个变量i和j,j不断自加。每次将j和j+1比较。如果,arr[j+1]>arr[j],就将j+1和j交换。直到j走到len-1的位置,第一趟排序结束。得到第一堂排序后的数据
[3 12 21 1 32 12 34 34 18 35]
在这里插入图片描述

第一趟排序将最大的元素35排到了最后,所以冒泡排序每次只能将一个元素排序出来
2、第二趟排序
第二趟排序将i+1,j继续从0的位置开始进行自加,重复第一趟排序。继续交换,继续排序,让j走到len-1的位置,然后完成第二趟的排序。得到第二趟排序后的结果。
[3 12 1 21 12 32 34 18 34 35]
在这里插入图片描述

第二趟排序找到第二大的元素34。
剩下的排序过程和第一趟第二趟排序过程一样,i在每趟的排序后进行++。
所以此排序的核心代码就是每次控制j的边界的问题
i控制每趟排序的个数,j = len - i -1
三、代码实现冒泡排序

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

四、冒泡排序的优化
从上面的操作来看,我们发现这样只是两两元素进行了交换,并没有体现出冒泡排序的特点。
现在我们假设待排序的关键字序列是[9,1,5,8,3,7,4,6,2],
当i=1时,变量j由8反向循环到1,逐个比较,将较小值交换到前面,直到最后找到最小值放置在了第1的位置。
当i=1、j=8 时,我们发现6>2,因此交换了它们的位置.
j=7时,4>2,所以交换…
直到j=2时,因为1<2,所以不交换。j=1 时,9>1,交换,最终得到最小值1放置第一的位置。
这样在不断循环的过程中,除了将关键字1放到第一的位置,我们还将关键字2从第九位置提到了第三的位置,这个算法比前面的要有进步,在很多数据的排序过程中,这种差异会体现出来。图中较小的数字如同气泡般慢慢浮到上面,因此就将此算法命名为冒泡算法。如下图所示:
在这里插入图片描述
这样就体现出冒泡排序的特点,最小的数据会像水泡一样慢慢浮上水面。
接着当i = 2时,变量j由8反向循环到2,逐个比较,再将关键字2交换到第二位置的同时,3和4也慢慢浮上来。
但是这样的冒泡排序还是缺点的,比如我们给出这样的一组待排序数列
[2 1 3 4 5 6 7 8 9]
也就是说除了第一和第二个关键字需要交换外,其他的数据是不用交换的,但上面的算法还是将数据全部循环了一遍,这样大大降低了算法的效率。如图所示:
在这里插入图片描述
只要这关键两步,其他的循环都是多余的。
优化一:
设置一个flag标记一趟比较是否发生交换,如果没有发生交换,则数组已经有序

void BubbleSort1(int arr[], int len) 
{
	int i = 0;
	int j = 0;
	int tmp;
	int flag = 0; 
	for (i = 0; i < n; ++i) 
	{
		flag = 0;
		for (j = 0; j < len - i - 1;j++)
		 {
			if (arr[j] < arr[j + 1]) 
			{
				flag = 1;
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
		if (flag == 0) 
		{
			break;
		}
	}	
}

优化二:
我们发现,每次排序前或排序后数组的后面都有一部分已经有序,这时我们只要记下最后一次排下的数组的下标下次排序的时候就可以只排序到此下标位置即可。定义一个index来标记最后一次排序的位置

void BubbleSort2(int arr[], int len) {
    int flag=0;//定义标志位标记已经有序或无序
	int index=len-1;
	int index1=0;//无序区的上界
	for(int i=0;i<len-1;i++)
	{
		flag=1;//开始置为1
		for(int j=0;j < len - 1;j++)
		{
 			if(a[j]>a[j+1])
			{
				int tmp=a[j];
				a[j]=a[j+1];
				a[j+1]=tmp;
				flag=0;//交换后对flag置0,表示已经有序
				index1=j;
			}
		}
		if(flag == 0)
		{
			break;//如果flag为1则说明排序前已经有序
		}
		index=index1;//若排序过则将index置为最后一次交换的坐标,若没有则表示已经有序
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值