• 冒泡算法(C++模板实现)


    冒泡排序

    从整体上看,冒泡排序是一种稳定排序,即排序完成后,原本序列中的键值相等的元素相对位置不会发生改变。算法的时间复杂度是O(n2),空间复杂度为O(1),即这是一个“就地算法”。


    简单的冒泡排序算法以及实现

    冒泡算法的基本思想是先实现局部的有序性,再进一步实现整体的有序性。

    从前向后依次检查每一对相邻元素,一旦发现逆序即交换二者的位置。对于长度为n的序列,共需做 n - 1次比较和不超过 n - 1次交换,这一过程称作一趟扫描交换。

    举个例子,先来看看对于一个杂乱的序列{1, 3, 8, 2, 0, 5, 6, 4, 9, 7},如何排序成为一个升序呢?依据冒泡算法的基本思想,从前向后逐一对每一对相邻元素进行检查,若逆序则交换。

    1. 第1和2位,{1,3}顺序正确,看下一对
    2. 第2和3位,{3,8}顺序正确,看下一对
    3. 第3和4位,{8,2}顺序错误,进行交换,第3位变为2,第四位为8,即此时整体序列为{1, 3, 2, 8, 0, 5, 6, 4, 9, 7}
    4. {8,0}又是错序,进行交换,{1, 3, 2, 0, 8, 5, 6, 4, 9, 7}
    5. {1, 3, 2, 0, 5, 8, 6, 4, 9, 7}
    6. {1, 3, 2, 0, 5, 6, 8, 4, 9, 7}
    7. {1, 3, 2, 0, 5, 6, 4, 8, 9, 7}
    8. 注意,此时{8,9}这一局部的序列是符合升序的,所以看下一对
    9. {9,7}是乱序的,进行交换。{1, 3, 2, 0, 5, 6, 4, 8,7, 9}

    以上,就完成了一趟扫描交换。每一次比较,局部内的较大值会交换到后面,小的值会交换到前面,就像气泡在水中浮向水面,所以称为冒泡算法。注意一点,每进行过一趟扫描为排序中的最大值已经“沉入”最后,所以下一趟比较时,需要比对的数对会较少一,即n减一。

    代码实现如下(C++):

    // 对一个数组a使用冒泡算法进行升序排序
    template <typename T>
    void bubbleSort_simple(T a[], int n) {
    	// n为数组的规模大小
    	int count = n;
    	// count用于辅助输出显示第几趟扫描比较
    	while (n--) {
    		for (int i = 0; i < n; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    			}
    		}
    		cout << "这是第" << count - n <<"趟比较: ";
    		printArray(a);  // 输出显示数组的函数
    	}
    }
    

    运行结果如下图:


    冒泡算法改进

    观察前面的结果,可以发现其实第4趟比较后就已经达成目标了,然而原来程序中依然要等while (n--)执行完,令n等于0才能结束,会浪费不少时间和系统资源。针对这一状况,可以设立一个标志位值。思想是这样的:当每次做一趟扫描,设最后发生过交换数值的位置为K,K的后面的位置的值已经是按序的了。下一趟排序就只用扫描到K位置之前的。若新的这一趟中的K值与上一轮相同,表明排序已经完成。

    改进的冒泡算法代码实现如下:

    template <typename T>
    void bubbleSort_improved(T a[], int n) {
    	// n为数组的规模大小
    	int count = 0;  // count用于记录第几趟扫描比较
    	int pos = n;  //  pos用于记录每一趟最后有发生交换的位置
    	int oldPos = 0;  //  记录上一趟的最后有发生交换的位置,
    	                 //  与pos对比,若一样,说明已经排好序
    	while (n > 0 && n != oldPos) {
    		oldPos = n;
    		for (int i = 0; i < n; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    				pos = i;
    			}
    		}
    		n = pos;
    		count++;
    		cout << "这是第" << count <<"趟比较后: ";
    		printArray(a);
    	}
    }
    

    运行结果如下:


    双向冒泡算法(鸡尾酒算法)

    传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,如果利用在每趟排序中进行正向和反向两遍冒泡的方法一次可以得到两个最终值(最大者和最小者) , 从而使排序趟数大幅减少。

    双向冒泡算法代码实现:

    template <typename T>
    void bubbleSort_bidirectional(T a[], int n) {
    	// n为数组的规模大小
    	cout << "双向冒泡排序实现。" << endl;
    	int count = 0;
    	int low = 0;
    	int high = n - 1;
    	while (low < high) {
    		for (int i = low; i < high; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    			}
    		}
    		high--;
    		for (int j = high; j > low; j--) {
    			if (a[j] < a[j - 1]) {
    				T temp = a[j];
    				a[j] = a[j - 1];
    				a[j - 1] = temp;
    			}
    		}
    		low++;
    		count++;
    		cout << "第" << count <<"趟比较后: ";
    		printArray(a);
    	}
    }
    

    运行结果:


    完整代码如下

    #include <iostream>
    using namespace std;
    
    template <typename T>
    void printArray(T a[]) {
    	int count = 10;
    	for (int i = 0; i < count; i++) {
    		cout << a[i] << " ";
    	}
    	cout << endl;
    }
    
    template <typename T>
    void bubbleSort_simple(T a[], int n) {
    	// n为数组的规模大小
    	cout << "简单冒泡排序实现。" << endl;
    	int count = 0;
    	while (n--) {
    		for (int i = 0; i < n; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    			}
    		}
    		count++;
    		cout << "第" << count <<"趟比较后: ";
    		printArray(a);
    	}
    }
    
    template <typename T>
    void bubbleSort_improved(T a[], int n) {
    	// n为数组的规模大小
    	cout << "冒泡排序改进版实现。" << endl;
    	int count = 0;  // count用于记录第几趟扫描比较
    	int pos = n;  //  pos用于记录每一趟最后有发生交换的位置
    	int oldPos = 0;  //  记录上一趟的最后有发生交换的位置,
    	                 //  与pos对比,若一样,说明已经排好序
    	while (n > 0 && n != oldPos) {
    		oldPos = n;
    		for (int i = 0; i < n; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    				pos = i;
    			}
    		}
    		n = pos;
    		count++;
    		cout << "第" << count <<"趟比较后: ";
    		printArray(a);
    	}
    }
    
    template <typename T>
    void bubbleSort_bidirectional(T a[], int n) {
    	// n为数组的规模大小
    	cout << "双向冒泡排序实现。" << endl;
    	int count = 0;
    	int low = 0;
    	int high = n - 1;
    	while (low < high) {
    		for (int i = low; i < high; i++) {
    			if (a[i] > a[i + 1]) {
    				T temp = a[i];
    				a[i] = a[i + 1];
    				a[i + 1] = temp;
    			}
    		}
    		high--;
    		for (int j = high; j > low; j--) {
    			if (a[j] < a[j - 1]) {
    				T temp = a[j];
    				a[j] = a[j - 1];
    				a[j - 1] = temp;
    			}
    		}
    		low++;
    		count++;
    		cout << "第" << count <<"趟比较后: ";
    		printArray(a);
    	}
    }
    
    int main() {
    	int a[10] = {1, 3, 8, 2, 0, 5, 6, 4, 9, 7};
    	double b[10] = {4, 7.42, 8.309, 2.1, 6.34, 9.078, 3.098, 1.23, 5.27, 0.243};
    	int c[10] = {1, 3, 8, 2, 0, 5, 6, 4, 9, 7};
    	bubbleSort_simple(a, 10);
    	cout << endl;
    	bubbleSort_improved(b, 10);
    	cout << endl;
    	bubbleSort_bidirectional(c, 10);
    	cout << endl;
    	printArray(a);
    	printArray(b);
    	printArray(c);
    	return 0;
    }
    
  • 相关阅读:
    Eclipse创建Maven Web项目 + 测试覆盖率 + 常见问题(2015.07.14——湛耀)
    JAVA面试题——JAVA编程题1(2015.07.22)
    Spring 国际化
    BeanPostProcessor 的使用,实现在对象初始化之前或者之后对对象进行操作
    spring 的配置 bean>>property>>name属性
    文件保存
    Spring-demo1(初学者的尝试,2015.03.19)
    新花生壳内网版2.3 + Tomcat7 搭建自己的网站(2015.01.21)
    (原)Struts 相关资源下载
    Xilinx 7 series FPGA multiboot技术的使用(转)
  • 原文地址:https://www.cnblogs.com/heiqiaoshusheng/p/5281194.html
Copyright © 2020-2023  润新知