Algorithm----冒泡排序以及优化方法

上第一门语言课,相信大家接触的第一个排序算法应该就是冒泡排序,相信大学四年过去,许多人对冒泡排序还是停留在最原始的版本,其实,冒泡排序是存在许多优化方法的,下面讲解常见的优化方法。

首先,上菜最原始的冒泡排序方法

看不懂的同学,就先补补相关知识

void bubble1(int *array, int len) {
	

	int counter = 0;

	for (int i = 0; i < len - 1; i++) {
	
		for (int j = 0; j < len - i - 1; j++) {
		
			//升序排序
			if (array[j + 1] < array[j]) {
				
    				array[j] = array[j] + array[j + 1];
					array[j + 1] = array[j] - array[j + 1];
					array[j] = array[j] - array[j + 1];
			
			}
			counter++;

		}
	
	}

	for (int i = 0; i < len; i++) {
	
		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

一、第一种优化方法,设置交换完成flag

冒泡排序最基本的问题是他是个暴力算法,就算是【1, 2, 3, 4】, 他也给需要你遍历6次;原始的冒泡排序相当于一个开环系统,没有反馈,那我们为了提高排序效率,我们可以判断当前序列是否有序。那什么时候序列已经有序了呢,根据冒泡排序的特性,当没有一个气泡冒泡,那么就是有序了,意思就是在第二个循环时,没有元素进行交换。

void bubble2(int *array, int len) {


	int counter = 0;
	bool flag = true;

	for (int i = 0; i < len - 1; i++) {

		//默认已排序完成
		flag = true;
		for (int j = 0; j < len - i - 1; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				
				//未排序完成
				flag = false;
			}

			counter++;


		}
		if (flag == true) {
		
			break;
		}
		
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

二、加入边界判断

我们可以注意到我们每次进行排序都是进行到 len - i - 1, 这也是冒泡排序的一个洉病, 过分自信,认为自己排过的才是有序的,忽略了原序列本来就由局部有序,那么我们可以记录有序的边界,从而提高排序效率。

void bubble3(int *array, int len) {


	int counter = 0;
	bool flag = true;
	int sortBorder = len - 1;
	int lastExchangeIndex = 0;

	for (int i = 0; i < len - 1; i++) {

		flag = true;		
		for (int j = 0; j < sortBorder; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				//记录这次是否已经交换
				flag = false;

				lastExchangeIndex = j;
			}

			counter++;

		}
		if (flag == true) {

			break;
		}

		sortBorder = lastExchangeIndex;
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

三、鸡尾酒排序(双向冒泡)

鸡尾酒排序最要是解决大部分元素已经有序的情况,例如,需要将 [2, 3, 4, 5, 6, 7, 8, 1] 升序排序, 按照上述比较策略

if (array[j + 1] < array[j])

我们需要将 2, 3, 4, 5, 6, 7, 8依次冒泡起来,那我们可以想到,把 1 沉下去不是更加容易吗,但是程序的比较策略是固定的,我们无法用一种比较策略去解决两种情况,这个时候我们就需要引进鸡尾酒排序,在排序过程中,我们不仅需要把大的元素冒泡,同时也需要把数值小的元素下沉,实现双向交换。

void bubble4(int *array, int len) {


	int counter = 0;
	bool flag = true;

	for (int i = 0; i < len / 2; i++) {

		

		//正向
		flag = true;
		for (int j = i; j < len - i - 1; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				//记录这次是否已经交换
				flag = false;

			}

			counter++;

		}
		if (flag == true) {

			break;
		}
		
		//反向
		flag = true;
		for (int j = len - i - 1; j > i; j--) {
		
			if (array[j - 1] > array[j]) {

				array[j] = array[j] ^ array[j + 1];
				array[j + 1] = array[j] ^ array[j + 1];
				array[j] = array[j] ^ array[j + 1];
				//记录这次是否已经交换
				flag = false;

			}
			
			counter++;
		}
		if (flag == true) {

			break;
		}
		
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

tips:交换元素我们也可以使用异或的方式,异或计算是比加法快速的。
四、四种算法比较

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>


void bubble1(int *array, int len) {
	

	int counter = 0;

	for (int i = 0; i < len - 1; i++) {
	
		for (int j = 0; j < len - i - 1; j++) {
		
			//升序排序
			if (array[j + 1] < array[j]) {
				
				array[j] = array[j] + array[j + 1];
					array[j + 1] = array[j] - array[j + 1];
					array[j] = array[j] - array[j + 1];
			
			}
			counter++;

		}
	
	}

	for (int i = 0; i < len; i++) {
	
		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

void bubble2(int *array, int len) {


	int counter = 0;
	bool flag = true;

	for (int i = 0; i < len - 1; i++) {

		//默认已排序完成
		flag = true;
		for (int j = 0; j < len - i - 1; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				
				//未排序完成
				flag = false;
			}

			counter++;


		}
		if (flag == true) {
		
			break;
		}
		
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

void bubble3(int *array, int len) {


	int counter = 0;
	bool flag = true;
	int sortBorder = len - 1;
	int lastExchangeIndex = 0;

	for (int i = 0; i < len - 1; i++) {

		flag = true;		
		for (int j = 0; j < sortBorder; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				//记录这次是否已经交换
				flag = false;

				lastExchangeIndex = j;
			}

			counter++;

		}
		if (flag == true) {

			break;
		}

		sortBorder = lastExchangeIndex;
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}

void bubble4(int *array, int len) {


	int counter = 0;
	bool flag = true;

	for (int i = 0; i < len / 2; i++) {

		

		//正向
		flag = true;
		for (int j = i; j < len - i - 1; j++) {

			if (array[j + 1] < array[j]) {

				array[j] = array[j] + array[j + 1];
				array[j + 1] = array[j] - array[j + 1];
				array[j] = array[j] - array[j + 1];
				//记录这次是否已经交换
				flag = false;

			}

			counter++;

		}
		if (flag == true) {

			break;
		}
		
		//反向
		flag = true;
		for (int j = len - i - 1; j > i; j--) {
		
			if (array[j - 1] > array[j]) {

				array[j] = array[j] ^ array[j + 1];
				array[j + 1] = array[j] ^ array[j + 1];
				array[j] = array[j] ^ array[j + 1];
				//记录这次是否已经交换
				flag = false;

			}
			
			counter++;
		}
		if (flag == true) {

			break;
		}
		
	}

	for (int i = 0; i < len; i++) {

		printf("%d\t", array[i]);

	}
	printf("\ncounter:%d\n", counter);


}


int main() {


	//最基本的冒泡排序
	int array1[] = { 5, 1, 6, 3, 9, 2, 8, 7 };
	int len1 = 8;
	bubble1(array1, len1);

	//加入flag的改进冒泡排序
	int array2[] = { 5, 1, 6, 3, 9, 2, 8, 7 };
	int len2 = 8;
	bubble2(array2, len2);

	//加入边界判断以及flag的冒泡排序
	int array3[] = { 5, 1, 6, 3, 9, 2, 8, 7 };
	int len3 = 8;
	bubble3(array3, len3);

	//最基本的冒泡排序
	int array1_1[] = { 2, 3, 4, 5, 6, 7, 8, 1 };
	int len1_1 = 8;
	bubble1(array1_1, len1_1);

	//鸡尾酒排序
	int array4[] = { 2, 3, 4, 5, 6, 7, 8, 1 };
	int len4 = 8;
	bubble4(array4, len4);


	system("pause");
	return 0;

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值