冒泡排序(Bubble Sort)是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,以将当前序列的最小值交换到当前序列最前端为一轮结束,需要(length-1)轮,感觉数据是一个一个往上冒出来,这个现象类似“冒泡泡”,所以称为冒泡排序。

1、顺序存储结构实现冒泡排序

首先我们需要一个待排序的数组 arr[10] = {0, 9, 1, 5, 8, 3, 7, 4, 6, 2},其中arr[0]=0用做哨兵或临时变量所以不参与排序,所以数组下标从1开始,有效长度len=9,实际长度为10。

然后我们还需要交换数据的操作:

void swap_arr(int *arr, int i, int j)
{int temp = arr[i];arr[i]   = arr[j];arr[j]   = temp;
}

1.1、最简单的冒泡排序

void Simple_Bubble_Sort(int *arr, int len)
{for (int i=1; i<len; i++)        for (int j=1; j<len; j++)    if (arr[j] > arr[j+1])     /*如果反序就交换*/swap_arr(arr, j, j+1);
}

最简单的冒泡排序从严格意义来说,并不是冒泡排序,因为不符合“冒泡”的思想,它应该是最简单的交换排序。

它的思路:持续(length-1)轮,每一轮整个序列两两相邻记录的关键字都进行比较交换,这样整个序列一定会变为有序。

当然这样的思路让它的时间效率非常糟糕,它不区分最好和最坏情况,所以它的最好时间复杂度和最坏时间复杂度都为O(n²)。

这样简单的思路和实现,也是让初学者最容易理解和记住的排序算法。

1.2、标准的冒泡排序

void Bubble_Sort(int *arr, int len)
{for (int i=1; i<len; i++)          /*冒泡到i位置,下轮循环度减一*/for (int j=len-1; j>=i; j--)   /*从底向上,两两比较交换*/if (arr[j] > arr[j+1])     /*如果反序就交换*/swap_arr(arr, j, j+1);
}

每一轮下标 j 都会从8开始,将这一轮的最小值往上送到序列最顶端。

下图中,较小的数据如同气泡般慢慢浮到上面,因此就将该算法命名为冒泡算法。

标准的冒泡排序也需要进行(length-1)轮循环,但是总的比较和交换次数比最简单的冒泡排序要减少一半。

标准的冒泡排序的平均时间复杂度O(n²/2)。

1.2、优化冒泡排序

请问,标准的冒泡排序是否还有优化的空间?

假如序列变为arr[10] = {0, 2, 1, 3, 4, 5, 6, 7, 8, 9},我们一眼就能看出只要将1和2交换,整个序列就有序了,但标准的冒泡排序不知道,它仍会兢兢业业地一轮一轮去比较,而且比较次数还是非常多的,所以标准的冒泡排序在这个方面仍然可以优化。

优化方法也非常简单,当一轮比较之后都没有任何数据进行交换,那么说明序列已经有序了,不需要开始下一轮了。

在标准的冒泡排序的基础上,设置一个标志位,每开始一轮之前,先假设标志位为有序,如果途中交换过数据,则将标志位设置为无序,然后在每一轮结束后,判断标志位是否有序即可。

void Optimal_Bubble_Sort(int *arr, int len)
{                   for (int i=1; i<len; i++) {                                   /*flag用来标记序列是否已经完全排序好了*/bool flag = true;               /*开始了新一轮的交换之前,先假设这一轮flag=true*/for (int j=len-1; j>=i; j--)    {  if (arr[j] > arr[j+1]) {    /*如果反序就交换*/swap_arr(arr, j, j+1);flag = false;           /*有交换说明还没排好*/}}if (flag == true)               /*若flag=true说明这一轮都没有交换过数据*/break;                      /*就可以退出循环不用继续了*/}
} 

这个优化避免了序列已经有序的情况下,仍无意义的、费时的循环判断,让冒泡排序在最好以及相对好的情况下的性能有了很高的提升,但在较坏和最坏情况下没有提升,优化后的冒泡排序的时间复杂度仍为O(n²/2)。

2、链式存储结构实现冒泡排序

首先链式存储结构采用单链表的形式:

typedef int DataType;
typedef struct LinkNode {DataType data;     /*数据域*/LinkNode *next;    /*后继指针*/
}*LinkList;

然后是交换结点数据的操作,该操作不交换结点:

/*交换结点里面的数据*/
void swap_link(LinkList node, LinkList next)
{int temp   = node->data;node->data = next->data;next->data = temp;
}

如果实现冒泡排序的链式算法需要使用len,那么和数组的冒泡排序并无太大差别,差别在于单链表只能单向从头到尾的访问,而之前数组的冒泡排序是从尾到头的排序,所以需要修改一下思路:每次将最大值冒泡到链表的尾部,j 每次都从下标1开始,随着 i 的增大而 j 的判定范围往前面收缩。

void Optimal_Bubble_Sort_LinkList(LinkList Head, int len)
{for (int i = 1; i<len; i++) {bool flag = true;LinkList q = Head->next;for (int j = 1; j<len-i+1; j++, q = q->next) /*j<len-i+1:让j的范围随着i的增大往前收缩*/{if (q->data > q->next->data) {swap_link(q, q->next);        flag = false; }}if (flag == true)               /*若flag=true说明这一轮都没有交换过数据*/break;}
}

如果不想使用len来实现冒泡排序的链式算法,我们可以使用一个End指针来表示已经排好序的位置,将每一轮的遍历到End前一个结点为止,此时End前一个结点也排好序了,End就前移一位。

void Optimal_Bubble_Sort_LinkList(LinkList Head)
{LinkList p, q;LinkList End = NULL;                            /*一开始End为NULL,在数组外*/for (p=Head->next; p->next!=NULL; p=p->next) {bool flag = true;for (q=Head->next; q->next!=End; q=q->next) /*q遍历到End前一个结束*/{if (q->data > q->next->data) {swap_link(q, q->next);flag = false; }}End = q;                                    /*End往前移一位*/if (flag == true)               /*若flag=true说明这一轮都没有交换过数据*/break;}
}

3、鸡尾酒排序:冒泡排序的升级

鸡尾酒排序其实是冒泡排序的一种升级,并不在十大经典排序算法中。

鸡尾酒排序可以理解为双向冒泡排序,排序过程就像钟摆一样,第一轮先从左到右比较交换,把最大值冒泡到最右端,然后再从右到左把最小值冒泡到最左端,一轮可以把排序两个数据,也因此轮数变为原来的一半。

void Cocktail_Sort(int *arr, int len)
{for (int i=1; i<len/2; i++){/*先从左往右冒泡最大值*/bool flag = true;for (int j=i; j<len-i+1; j++)   /*从第一个冒泡到最后一个*/{                              if (arr[j] > arr[j+1]) {swap_arr(arr, j, j+1);flag = false;  }}if (flag == true) break;        /*若flag=true说明这一轮都没有交换过数据*//*再从右往左冒泡最小值*/flag = true;for (int j=len-i; j>=i; j--)    /*经过从左往右冒泡最大值,右边有一个排好序了*/{                                /*从倒数第二个开始,从右往左冒泡最小值到i位置*/if (arr[j] > arr[j+1]) {swap_arr(arr, j, j+1);flag = false;  }}if (flag == true) break;        /*若flag=true说明这一轮都没有交换过数据*/}
}

鸡尾酒排序相当于冒泡排序来说,优势是减少了排序的轮数,虽然鸡尾酒排序的最坏时间复杂度还是O(n²/2),但在大多数情况下(除最坏以外)都比冒泡排序效率高很多,而缺点就是代码量增加了。

鸡尾酒排序因为双向排序的缘故,不适合使用单链表来实现,但可以使用双向链表实现,这里就不再实现了。

数据结构与算法(十六)冒泡排序和鸡尾酒排序相关推荐

  1. 数据结构与算法(十二):八大经典排序算法再回顾

    文章出自汪磊的博客,未经允许不得转载 一.排序的理解 提到排序大部分同学肯定第一时间想到int数组的排序,简单啊,所谓排序不就是将int数组按照从大到小或者从小到大排序吗,如果我有个数组存放的不是in ...

  2. 我的软考之路(六)——数据结构与算法(4)之八大排序

    排序是编程的基础,在程序中会经常使用,好的排序方法可以帮助你提高程序运行的效率,所以学好排序,打好基础,对于程序的优化会手到擒来.无论你的技术多么强,如果没有基础也强不到哪去. 不多说了,我们直接进入 ...

  3. 数据结构与算法(六)

    数据结构与算法 第一章 绪论 第二章 线性表 第三章 树与二叉树 第四章 图 第五章 查找 第六章 排序 文章目录 数据结构与算法 第六章 内部排序 一.基本概念 二.冒泡排序 三.快速排序 四.直接 ...

  4. 数据结构与算法(六)- 单向链表的反转

    数据结构与算法(六)- 单向链表的反转 一.头节点插入法 /*** 反转单向链表(头插法)** 1.先定义一个节点reverseHead = new HeroNode()* 2.从头到尾遍历原来的链表 ...

  5. 数据结构和算法(十)递归-迷宫游戏

    1. 数据结构和算法(十)递归-迷宫游戏 1.1 迷宫游戏   今天做一个简单的迷宫游戏,用二维数实现地图,让程序自动寻路的小游戏. 1.2 简单的迷宫 简单的迷宫 用二维数实现地图,找路策略:[右- ...

  6. 06_JavaScript数据结构与算法(六)单向链表

    JavaScript 数据结构与算法(六)单向链表 认识链表 链表和数组 链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同. 数组 存储多个元素,数组(或列表)可能是最常用的 ...

  7. 排序算法之冒泡排序及鸡尾酒排序

    目录 一.排序算法的分类 二.冒泡排序 1.原始的冒泡排序 2.改进一步的冒泡排序 3.更进一步的冒泡排序 三.鸡尾酒排序 四.完整测试代码 一.排序算法的分类 在介绍排序算法之前,我们先根据时间复杂 ...

  8. 冒泡排序和鸡尾酒排序(改进的冒泡排序)

    冒泡排序 冒泡排序是最基本的排序算法,也是排序算法中的经典的算法,也是比较简单.容易理解的算法,而且还可以对其排序过程进行优化. 冒泡排序排序过程总是大数往前放,小数往后放,相当于气泡往上升,所以称作 ...

  9. 冒泡排序,鸡尾酒排序,选择排序

    冒泡排序 改进 鸡尾酒排序 选择排序 冒泡排序 最好情况:Ο(n) 最坏情况:Ο(n2) 平均情况:Ο(n2) 辅助空间:Ο(C) 稳定性:稳定 冒泡排序是一种简单的算法,它重复地走访过要排序的元素, ...

最新文章

  1. HZOJ string
  2. hashmap的各种问题及答案
  3. mysql实现读写分离
  4. jQuery基础--样式篇(3)
  5. 论文浅尝 | 改善多语言KGQA的 Zero-shot 跨语言转换
  6. 容量耦合系数模型_期刊在线 | 基于ALE流固耦合方法的刷式密封泄漏特性理论与实验研究...
  7. 实战:自定义简易版SpringBoot
  8. java this关键字的使用_Java this 关键字的使用方法详解
  9. 使用dbstart 和dbshut 脚本来自动化启动和关闭数据库
  10. java api 版本控制_API 版本控制的几种方式
  11. rgss3a解包器_Rgss3a解包器下载
  12. 基于ZigBee cc2530单片机多传感器的智能阳台仿真设计与实现
  13. public static void main解释
  14. 大一c语言课设之图书管理系统
  15. PostgreSQL 聚合函数讲解 - 3 总体|样本 方差, 标准方差
  16. 用IDEA创建基于Spring Cloud的Feign的微服务:服务接口、服务提供者、服务使用者分离
  17. 为陶崇园争取正义懒人包1.0
  18. 熊分享-负重前行有我陪伴!
  19. java基础(多态的理解与应用)
  20. IDC时评:从巴黎圣母院大火看数据中心运维

热门文章

  1. 虚幻5:或许将会颠覆可视化行业
  2. phpexcel数据导出加打包,
  3. 冰冰学习笔记:vim工具的基本操作
  4. 开发者账号 企业公司 邓伯氏(DUNS Number)流程
  5. 看看谁更快:Ubuntu 10.04对决Windows 7
  6. 快鲸资产管理系统 :高效解决资产管理中的痛点和难点
  7. 你在淘宝买件东西背后的复杂技术 技术普及帖
  8. DNS欺骗实验过程和分析
  9. Ajax学习(3rd)
  10. Linux 环境 Apache Web 服务器配置详解