简单排序算法之三种冒泡排序

冒泡排序简述:

冒泡排序(Bubble Sort)本质是一种交换排序,不停比较前后两个元素大小,反序则交换,直到没有反序为止。

排序前的准备:

#define MAXSIZE 10
//顺序表结构
template <class T>
struct SqList
{
	T s[MAXSIZE + 1] = { NULL,98,24,55,81,32,77,48,60,14,8 };          //数组s,s[0]可作为临时变量使用
	int length = MAXSIZE;              //s长度
	void PrintArray();
};
typedef SqList<int> SList;

//交换l中的数组中下标为i和j的值
void Swap(SList *L, int i, int j)
{
	int temp = L->s[i];
	L->s[i] = L->s[j];
	L->s[j] = temp;
}
默认的顺序表为98,24,55,81,32,77,48,60,14,8,并准备了一个交换函数,用于交换。


简单的冒泡排序:

//冒泡排序(简)
void BubbleSort1(SList *L)
{
	int i, j;
	for (i = 1; i < L->length; i++)
	{         //从第一个元素开始
		for (j = i + 1; j <= L->length; j++)     //比较后面所有元素
		{     //把最小的元素放到前面
			if (L->s[i] > L->s[j])
			{
				//交换元素
				Swap(L, i, j);        //交换只把最小元素放到前面,不考虑其他元素位置,效率低          
			}
		}
	}
}
这个排序最为简单,便于理解,每次循环遍历后,都会把当前数组最小的一个元素放到遍历首位,但不会考虑其他元素的位置,可能会导致第二小的元素反而跑到数组末位,所以这种冒泡排序是低效的。


正宗的冒泡排序:

//冒泡排序
void BubbleSort2(SList *L)
{
	int i, j;
	for (i = 1; i < L->length; i++)   
	{
		for (j = L->length - 1; j >= i; j--)
		{      //j从后往前遍历
			if (L->s[j] > L->s[j+1])   //前一个元素比后一个元素大,和前面算法不同
			{
				//交换元素
				Swap(L, j, j + 1);            //每次把最小元素放到前面的同时,下一个最小元素也会往前移动若干位置,效率高
			}
		}
	}
}
这种冒泡排序严格遵循“冒泡"的概念,最小的元素像气泡一样冒到最上面,此时不仅最小的元素会到数组首位,第二小的元素也会前进若干位,所以这种冒泡效率更高。


优化后的冒泡排序:

我们发现当顺序表大部分为有序时,如312456789时,只用交换几次后元素就有序了,但仍然会最后整体遍历一次表,对比前面,这样就浪费了不少时间,所以我们在排序同时加入一个标志位,如果有序便不再遍历最后一次。

//冒泡排序优化
void BubbleSort3(SList *L)
{
	int i, j;
	int unordered = true;     //标志位默认是无序的
	for (i = 1; i < L->length && unordered; i++)      //只有当是无序时才进行遍历
	{
		unordered = false;            //假设此时有序,如果后面没有进行交换则不再进入第一层循环,减少最后一次遍历
		for (j = L->length - 1; j >= i; j--)
		{
			if (L->s[j] > L->s[j+1])
			{
				Swap(L, j, j + 1);       //交换元素
				unordered = true;       //改变标识符为无序
			}
		}
	}
}


冒泡排序的时间复杂度: 

冒泡排序比较次数最小的情况是有序数列,此时要比较n-1次,时间复杂度为O(n);

而最差的情况是完全反序,如987654321,此时要比较次数=1+2+3+(n-1),即((n)(n-1))/2,时间复杂度为O(n^2)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值