排序--Bubble的优化和性能(算法时间、空间复杂度、稳定性)分析

本文介绍了冒泡排序的基本思想、优化方法以及性能分析。优化包括:设置标志位以提前结束排序、记录交换位置减少比较、正反交替扫描。冒泡排序在最好情况下时间复杂度为O(n),平均时间复杂度为O(n^2),空间复杂度为O(1),且由于其稳定性,相同元素的顺序不会改变。

 

一、算法基本思想

(1)基本思想

冒泡排序的基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。

算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。

二、算法实现

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int tmp = 0;
	for (i = 0; i < len - 1; i++)     //n-1趟
	{
		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;
			}
		}
	}
}

    冒泡排序还有三种优化方式:(以下都是以升序为例)

例如要排序下面这组数据: 0  1  2  3  4  5  6   7  9  8

     经过第一趟冒泡排序已经有序了,下面的几趟已经是多余的,这时我们可以加一个标志位flag,若那一趟没有交换数据,这这时已经有序,我们就可以退出排序,不必进行下来的几趟。

算法实现:
 

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int tmp = 0;
	for (i = 0; i < len - 1; i++)
	{
		flag = 1;                             
		for (j = 0; j < len - i - 1; j++)     //每排序一趟,则必然后面有一个已经有序,可以缩小排序的范围
		{
			if (arr[j]>arr[j + 1])             //只要要交换数据,则flag就会被修改
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                   //只要还未完全有序,则修改flag为0
			}
		}
		if (flag)                            
		{
			break;
		}
	}
}

冒泡再次优化的方法!!!

例如要排序下面这组数据:1  4  3  2  6  7  8  9 

     经过第一趟冒泡排序比较了,发现后面数据没有交换已经有序,接下来几趟比较后面的数据已经是多余的,这时我们可以记录每一次交换的位置,下一次从第一个数据比较到最后一次交换位置即可,不必再次比较后面的数据。

算法实现:

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int tmp = 0;
	int m = 0;                  //用来记录最后一次交换的位置
	int k = len-1;
	for (i = 0; i < len - 1; i++)
	{
		m = 0;
		flag = 1;
		for (j = 0; j < k; j++)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k
		{
			if (arr[j]>arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                   
				m = j;
			}
		}
		if (flag)                          
		{
			break;
		}
		k = m;                             //将k置成最后一次交换的位置
	}
}

冒泡排序还有第三种优化方式:

    对下面这组这组数进行排序:2  3  4  5  6  7  8  9  10  1

     只有后面两个数据无序,前面已经有序,按照以上优化冒泡需要进行多次。这时,我们采用正反交替扫描,正着找最大值,翻着找最小值,一趟就可以使数据有序。

void BubbleSort(int *arr, int len)
{
	assert(arr);
	int i = 0;
	int j = 0;
	int flag = 0;
	int m = 0;       //记录最后一次交换的位置
	int n = 0;
	int k = len - 1;
	for (i = 0; i < len - 1; i++)
	{
		m = 0;
		flag = 1;
		//正序扫描找最大值
		for (j = n; j < k; j++)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k
		{
			if (arr[j]>arr[j + 1])
			{
 
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;                    
				m = j;
			}
		}
		k = m;
		if (flag)             
		{
			break;
		}
		//反序扫描找最小值
		for (j = k; j>n; j--)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k
		{
			if (arr[j]<arr[j - 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = tmp;
				flag = 0;                  
			}
		}
		n++;
		if (flag)                   
		{
			break;
		}                           //将k置成最后一次交换的位置
	}
}

若比较的数据不是整形是其他类型怎么处理,这是我们需要支持泛型编程。

基础知识:

void * :通用指针(无符号指针)或叫做泛型指针,它的特点有:

(1)它用于临时存储地址

(2)它不能解引用

(3)它不能进行算术运算,因为呢,它就是临时的盒子,所以呀,不能依赖它进行计算,总不可能依赖一个通用的盒子计算有   类型的数据吧

算法实现:

//4.泛型冒泡
typedef int(*PCmp)(void *vp1, void *vp2);//泛型比较
void Swap(void* vp1, void*vp2,int size)
{
	void* temp = malloc(size);
	memcpy(temp, vp1, size);
	memcpy(vp1, vp2, size);
	memcpy(vp2, temp, size);
	free(temp);
}
void BubbleSort(void* arr, int len, int elemsize, PCmp cmp)
{
	void* var1;
	void* var2;
	int k = len - 1;
	int m = 0;
	bool flag = 1;
	for (int i = 0; i < len - 1; ++i)
	{
		for (int j = 0; j < k; ++j)
		{
			var1 = (char*)arr + j*elemsize;
			var2 = (char*)arr + (j + 1)*elemsize;
			if (cmp(var1, var2)>0)
			{
				Swap(var1, var2, elemsize);
				m = j;
				flag = 0;
			}
			
		}
		if (flag) break;
		k = m;
	}
}
int Cmp_int(void *vp1, void *vp2)
{
	return *(int *)vp1 - *(int *)vp2;
}

int Cmp_str(void *vp1, void *vp2)
{
	return strcmp(*(char **)vp1, *(char **)vp2);
}

void Test()
{
	int arr[] = { 3, 5, 7, 9, 0, 12, 45, 6, 78, 23, 44, 10 };
	BubbleSort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), Cmp_int);

	char *brr[] = { "abc", "aaa", "bcd", "xyz", "ccccc", "hhh" };
	BubbleSort(brr, sizeof(brr) / sizeof(brr[0]), sizeof(char *), Cmp_str);
	
	getchar();

}
int main()
{
	Test();
	
}

运行结果:

三、性能(算法时间、空间复杂度、稳定性)分析

 (1)时间复杂度

当原始序列“正序”排列时,冒泡排序总的比较次数为n-1,移动次数为0,也就是说冒泡排序在最好情况下的时间复杂度为O(n);

当原始序列杂乱无序时,冒泡排序的平均时间复杂度为O(n^2)。

(2)空间复杂度

冒泡排序排序过程中需要一个临时变量进行两两交换,所需要的额外空间为1,因此空间复杂度为O(1)。

(3)稳定性

冒泡排序在排序过程中,元素两两交换时,相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值