【DSA MOOC】起泡排序的原理及常数优化

根据学堂在线TsinghuaX: 30240184X 数据结构(2015秋)这门课的内容,对bubblesort做了一些总结。

1. bubblesort(起泡排序),原理来自这样一个观察规律:若序列有序,则任意一对相邻元素顺序。其逆否命题为:若存在相邻元素逆序,则序列无序。

2. 利用这一原理,bubblesort按照逐步消除逆序对的思路来实现整体有序。

3. 实现:对序列进行若干趟扫描,每遇到相邻逆序对,交换之,直至不再存在逆序对。

4. 算法的正确性分析:

(1)不变性(问题已求解的部分扩大):每一轮扫描交换,都会使当前未就位的元素中最大的那个就位(每次冒出一个最大的泡)

(2)单调性(问题未求解的规模递减):每一轮扫描交换,都会使有序序列长度增1,无序序列长度减1,问题规模也因而减1

5. 实现为如下代码:

 1 void swap(int& a,int& b){
 2     int t=a;
 3     a=b;
 4     b=t;
 5 }
 6
 7 void bubblesort(int a[],int n){
 8     bool sorted = false; //先假设尚未整体有序
 9     while(!sorted){ //进入循环体
10         sorted=true; //假设现在前n项已有序
11         for(int i=0; i<n-1; i++){ //进行一趟扫描交换(从0一直到n-1,判断每组相邻元素)
12             if(a[i] > a[i+1]){
13                 swap(a[i],a[i+1]);
14                 sorted = false; //这一趟有交换则还需要再一趟扫描
15             }
16         }
17         n--;//一趟扫描交换必然会冒出一个泡~所以后面已就位的元素可以不在下次的扫描范围内了
18     }
19 }
20  

6. 复杂度分析:

(1)基本语句为第12行的if(a[i]>a[i+1])

(2)初始时,必然会进入第9行的while循环,然后进入第11行的for循环,基本语句被执行n-1次。

(3)最好情况是输入完全有序,while循环只进入一次,for循环执行n-1轮,因此基本语句相应地执行n-1次,T(n) = n-1=Ω(n)

(4)最坏情况是输入完全逆序,while循环被执行n次;在第 i 轮while循环中,for循环执行 i 轮,基本语句也相应地执行 i 次。因此基本语句累加执行n(n-1)/2次,T(n)=n(n-1)/2=O(n2)

Vector一章,对bubblesort有两次常数优化。

函数原型是这样的:

  void bubble(Rank lo, Rank hi);

  void bubbleSort(Rank lo, Rank hi);

Rank即向量元素的秩,在此被定义为int型。lo和hi为待排序区间的左、右界桩。

外部通过调用 v.bubbleSort(lo, hi) 来给向量v的区间[lo,hi)排序,而bubbleSort调用bubble(lo,hi)实现对每个无序子区间的收缩。

 

最朴素的bubblesort大概是这样,最好最坏平均情况都为O(n^2)

 1 //最朴素版
 2 void bubble(Rank lo, Rank hi) {
 3     while (++lo < hi){//从左至右扫描,修正相邻逆序对
 4         if (_elem[lo - 1]>_elem[lo]){
 5             swap(_elem[lo - 1], _elem[lo]);
 6         }
 7     }
 8 }
 9 void bubbleSort(Rank lo, Rank hi){
10     while (lo < hi) bubble(lo, hi--);//右界桩每次向左挪一位
11 }

 

第一次改进后是这样,这种改进很常见,能使最好情况变为为O(n)。

 1 bool bubble(Rank lo, Rank hi) {
 2     bool sorted=true;//增设sorted变量,记录此次扫描是否发生交换(未发生交换则sorted=true)
 3     while (++lo < hi){
 4         if (_elem[lo - 1]>_elem[lo]){
 5             sorted = false;
 6             swap(_elem[lo - 1], _elem[lo]);
 7         }
 8     }
 9     return sorted;//返回是否已有序
10 }
11 void bubbleSort(Rank lo, Rank hi){
12     while (!bubble(lo, hi--));//一趟扫描没有发生交换(检测结果为sorted)则排序完成
13 }

 

第二次改进后是这样,可以跳跃式地收缩区间,降低了平均情况常数因子

 1 Rank bubble(Rank lo, Rank hi) {
 2     Rank last=lo;//设置last变量,记录最后一次交换的位置
 3     while (++lo < hi){;}
 4
 5             swap(_elem[lo - 1], _elem[lo]);
 6         if (_elem[lo - 1]>_elem[lo]){
 7             last = lo
 8         }
 9         return last;//last及以后的元素都已就位,不必再进行扫描
10 }
11 void bubbleSort(Rank lo, Rank hi){
12     while (lo<(hi=bubble(lo, hi--)));//将右界桩挪到最后一次last位置
13 }

第二次改进可用下图来描述

 

时间: 2024-10-06 03:24:11

【DSA MOOC】起泡排序的原理及常数优化的相关文章

VFP中产生随机数并实现起泡排序

本文来介绍一下在vfp中实现起泡排序的问题,考虑到做成实例比较好理解,因此本文还是会以实例的方式来表达.本例在刚开始设计时,是采用这种方式来处理的:定义一个作用域为全局的.宽度为10的一维数组,利用表单上的文本框连续输入并接收10个数字,然后再对这10个数字进行从小到大的排序.不过运行了一下,觉得这种方式好麻烦,便改成了使用随机函数产生10个数字并对它们排序,所以本文也涉及到了一点vfp中的随机函数. 本例运行时如下图: 下面我们进入正题,首先看一下如何在vfp中产生随机数.有的学友以为vfp中

经典的7种排序算法 原理C++实现

经典的7种排序算法 原理C++实现 排序是编程过程中经常遇到的操作,它在很大程度上影响了程序的执行效率. 7种常见的排序算法大致可以分为两类:第一类是低级排序算法,有选择排序.冒泡排序.插入排序:第二类是高级排序算法,有堆排序.排序树.归并排序.快速排序. 一.低级排序算法 1. 选择排序 排序过程:给定一个数值集合,循环遍历集合,每次遍历从集合中选择出最小或最大的放入集合的开头或结尾的位置,下次循环从剩余的元素集合中遍历找出最小的并如上操作,最后直至所有原集合元素都遍历完毕,排序结束. 实现代

起泡排序【模板】

这个起泡排序的 for 循环比较奇怪,注意...邓老师写的还是为了开发我们的思维... 另外就是 swap 函数在 using namespace std; 中有现成的函数... #include <iostream> using namespace std; void bubblesort(int A[],int n) { for(bool sorted=false;sorted=!sorted;n--) for(int i=1;i<n;i++) //自左向右,检查 A[0,n) 的相

Jquery 选中表格一列并对表格排序实现原理_jquery

在前端对表格排序的Jquery插件有很多,功能也很强大,比如说Jquery Data Tables对表格的处理就相当强大,可对表格进行排序,搜索,分页等操作,不过没有仔细研究过其实现原理. 为了更好的理解在前端对表格进行排序的原理,也为了进一步的学习Jquery,所以决定用Jquery来实现一个对表格进行排序的小功能. 该实现的主要思想是:获取鼠标点击的表头单元格的列号,遍历数据行,获取每个<tr>中的html,同时获取每个<tr>标签下对应获取到的列号的<td>标签中

Android研究院之ListView原理学习与优化总结

转载自雨松MOMO程序研究院本文链接地址:Android研究院之ListView原理学习与优化总结(二十一) 列表的显示需要三个元素: ListVeiw: 用来展示列表的View. 适配器 : 用来把数据映射到ListView上 数据: 具体的将被映射的字符串,图片,或者基本组件. 根据列表的适配器类型,列表分为三种,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter,这三种适配器的使用大家可学习下官网上面的使用或者自行百度谷歌,一堆DEMO!!!其中以

JAVA简单选择排序算法原理及实现_java

简单选择排序:(选出最小值,放在第一位,然后第一位向后推移,如此循环)第一位与后面每一个逐个比较,每次都使最小的置顶,第一位向后推进(即刚选定的第一位是最小值,不再参与比较,比较次数减1) 复杂度: 所需进行记录移动的操作次数较少 0--3(n-1) ,无论记录的初始排列如何,所需的关键字间的比较次数相同,均为n(n-1)/2,总的时间复杂度为O(n2):空间复杂度 O(1) 算法改进:每次对比,都是为了将最小的值放到第一位,所以可以一比到底,找出最小值,直接放到第一位,省去无意义的调换移动操作

PostgreSQL 百亿级数据范围查询, 分组排序窗口取值 极致优化 case

本文将对一个任意范围按ID分组查出每个ID对应的最新记录的CASE做一个极致的优化体验.优化后性能维持在可控范围内,任意数据量,毫秒级返回,性能平稳可控.比优化前性能提升1万倍. CASE 有一张数据表,结构: CREATE TABLE target_position ( target_id varchar(80), time bigint, content text ); 数据量是 100 亿条左右 target_id 大约 20 万个 数据库使用的是 PostgreSQL 9.4 需求: 查

MultiDex工作原理分析和优化方案

动态加载技术(插件化)系列已经坑了有一段时间了,不过UP主我并没有放弃治疗哈,相信在不就的未来就可以看到"系统Api Hook模式"和插件化框架Frontia的更新了.今天要讲的是动态加载技术的亲戚 -- MultiDex.他们的核心原理之一都是dex文件的加载. MultiDex是Google为了解决"65535方法数超标"以及"INSTALL_FAILED_DEXOPT"问题而开发的一个Support库,具体如何使用MultiDex现在市面已

SQL优化器原理-Shuffle优化

这是MaxCompute有关SQL优化器原理的系列文章之一.我们会陆续推出SQL优化器有关优化规则和框架的其他文章.添加钉钉群"关系代数优化技术"(群号11719083)可以获取最新文章发布动态. 本文主要介绍MaxCompute Optimizer对Shuffle方面的相关优化. 1 简介 分布式系统中,Shuffle是重操作之一,直接影响到了SQL运行时的效率.Join.Aggregate等操作符都需要借助Shuffle操作符,确保相同数据分发到同一机器或Instance中,才可以