冒泡排序

从整体上看,冒泡排序是一种稳定排序,即排序完成后,原本序列中的键值相等的元素相对位置不会发生改变。算法的时间复杂度是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;
}

冒泡算法(C++模板实现)的更多相关文章

  1. 1014 C语言文法定义与C程序的推导过程 程序:冒泡算法C程序(语法树)

    阅读并理解提供给大家的C语言文法文件. 参考该文件写出一个自己好理解版的现实版的完整版的C语言文法. 给出一段C程序,画出用上述文法产生这段C程序的完整语法树. 程序:冒泡算法C程序 点此文字查看原图 ...

  2. 冒泡算法C#

    冒泡算法C# namespace数组排序 { classProgram { staticvoidMain(string[]args) { inttemp=; ,,,,,,,,}; #region该段与 ...

  3. Python函数练习:冒泡算法+快速排序(二分法)

    冒泡算法: #-*- coding: UTF-8 -*-#冒泡排序 def func(lt):if type(lt).__name__ !='list' and type(lt).__name__ ! ...

  4. javascript之冒泡算法

    今天看了js中数组的方法,其中sort()方法用于排序,就让我想到学C语言的时候有一个冒泡算法,就想用js写一个. <script> var arr=[1,30,20,40,21,31,1 ...

  5. php的冒泡算法

    <?php /* 冒泡算法  * @para $arr 传人进去排序的数组  * @return $newArr 排序之后的数组  */   function maopao($arr){     ...

  6. python学习之路-6 冒泡算法、递归、反射、os/sys模块详解

    算法 冒泡算法 # 冒泡算法就是将需要排序的元素看作是一个个"气泡",最小的"气泡"最先浮出水面,排在最前面.从小到大依次排列. # 代码如下: li = [9 ...

  7. Python冒泡算法和修改配置文件

    先学习之前未完成的冒泡算法 li = [13,22,6,99,11] 从小到大 从第一个数字比较把大的往后移位 for m in range(4): num1 = li[m] num2 = li[m+ ...

  8. Python之collections序列迭代器下标式循环冒泡算法等

    练习题 元素分类 有如下值集合[11,22,33,44,55,66,77,88,99]将所有大于66的数作为一个列表放在字典的key为k1的value小于等于66的为k2的value {'k1':[7 ...

  9. Python系列之文件操作、冒泡算法、装饰器、及递归

    文件处理 python对文件进行读写操作的方法与具体步骤,包括打开文件.读取内容.写入文件.文件中的内容定位.及关闭文件释放资源等 open().file(),这个两函数提供了初始化输入\输出(I\O ...

随机推荐

  1. 我的第一个python代码实践:Trie树

    Trie树 不解析,  本园很多博文有提到. 直接上代码: #coding:utf-8 ''' create on 2013-07-30 @author :HuangYanQiang ''' LETT ...

  2. python mongodb 读写CSV文件

    # -*- coding: utf-8 -*-import osimport csvimport pymongofrom pymongo import MongoClient #建立连接client ...

  3. 使用js为html元素动态添加class

    <ul id="root"> <li>1</li> <li>2</li> <li>3</li> ...

  4. C#语法中一个问号(?)和两个问号(??)的运算符是什么意思?

    (1).C#语法中一个个问号(?)的运算符是指:可以为 null 的类型. MSDN上面的解释: 在处理数据库和其他包含不可赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型以及日期类型的功 ...

  5. Oracle DB优化

    http://www.jb51.net/article/77876.htm http://www.jb51.net/article/56881.htm http://danni505.blog.51c ...

  6. c++ const char *c_str(); 坑的学习

    语法: const char *c_str(); c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有string类型,故必须通过st ...

  7. 目录重定向的源代码工程( linux平台利用VFS实现目录重定向驱动)虚拟磁盘MINIPORT驱动代码(雨中风华)

    http://download.csdn.net/user/fanxiushu/uploads/2 http://download.csdn.net/user/fanxiushu/uploads/1

  8. 6个常见的 PHP 安全性攻击

    了解常见的PHP应用程序安全威胁,可以确保你的PHP应用程序不受攻击.因此,本文将列出 6个常见的 PHP 安全性攻击,欢迎大家来阅读和学习. 1.SQL注入 SQL注入是一种恶意攻击,用户利用在表单 ...

  9. 常见 jar包详解

        常见 jar包详解 jar包 用途 axis.jar SOAP引擎包 commons-discovery-0.2.jar 用来发现.查找和实现可插入式接口,提供一些一般类实例化.单件的生命周期 ...

  10. 解决WebService 测试窗体只能用于来自本地计算机的请求

    问题: 今天上 午,WebService部署成站点之后,如果在本地测试webservice可以运行,在远程却显示“测试窗体只能用于来自本地计算机的请求”或 者"The test form i ...