四种基本算法概述:

  • 基本排序:选择,插入,冒泡,希尔。上述算法适用于小规模文件和特殊文件的排序,并不适合大规模随机排序的文件。前三种算法的执行时间与N2成正比,希尔算法的执行时间与N3/2(或更快)成正比;

  • 前三种算法在平均,最坏情况下都是N2,而且都不需要额外的内存;所以尽管他们的运行时间只相差常数倍,但运行方式不同;

  • 对于已经就序的序列而言,插入排序和冒泡排序的运行时间都是O(N),但是选择排序的时间仍旧是O(N^2);

  • 因为Insertion和Bubble都是相邻项间的比较交换,所以不会出现不稳定因素,为稳定排序;Selection有跳跃交换过程,所以可能出现不稳定情况;

  • 排序算法运行时间的关键因素为:比较次数,数据移动次数;

  • 对于随机序列而言,插入排序不能预见元素在数组中的最终位置;选择排序则不会再接触,改变已排序元素的位置;

  • 对于算法整体情况:Insertion的每一次排序过程中,待插入元素平均需要经过已排序元素的一半,才能找到其插入位置;Selection和Bubble的每一次排序过程中,只需要遍历所有未排序元素并寻找最小项,不同的是随着Bubble排序的进行,未排序部分会接近正序,Selection则仅是一次将最小元素交换到最终位置;

  • 对于已排序或者已经接近正序排列的数组而言,Insertion和Bubble都可以为线性时间完成,但是Selection仍旧为二次时间完成;

  • 对于小型数组而言,Insertion和Selection是Bubble速度的两倍;对于数据移动开销较大的情况,Selection是最优选择;

议题:选择排序(selection sort)

分析:

  • 搜索整个数组,查找最小值元素,并将它与位于数组首位的元素交换;然后在除第一个元素的范围内查找最小值元素,并将它与位于数组次首位的元素交换;重复进行,直到数组最后一个元素终止;

  • 弱势:每一次寻找最小元素的过程中不能利用序列中本身存在的排序信息以及上一次寻找过程的信息,每次查找过程几乎是独立完成,所以对于已排序序列和未排序序列的排序时间相同,为N2;元素之间的比较次数也为N2

  • 优势:数据移动量,次数达到最小,适合于庞大项,小键值的序列。内循环查找剩余序列中的最大项,外循环每次交换将一个元素放到他的最终位置上(所以总共的交换次数为N-1,在同等级算法中移动次数最少);

  • 性质:不稳定排序, 2.5.8.2.1.6,2会与1进行交换,这时与第二个2的相对顺序改变,大约使用N-1次交换,N(N-1)/2次比较;

  • 时间:算法运行时间与序列状态无关,总是N2。其对输入(也就是数组原有的顺序)不敏感,为适应性排序;

样例:

 void selectSort(int *array, int l, int r) {
int minimum;
int temp; /**
* 外循环从左向右遍历处理array的每一个元素,
* 由于到达array[r]的时候,其左边的元素已经就序
* 所以不用处理array[r];
* */
for(int i=l;i<r;i++) {
/**
* 使用minimum记录array中最小元素的索引
* */
minimum=i;
for(int j=i+;j<=r;j++) {
if(array[minimum]>array[j])
/**
* 发现更小元素时仅更新索引
* */
minimum=j;
}
/**
* 由于选择排序并不是相邻元素之间的交换,所以
* 可能破坏数据的稳定性,选择排序是非稳定性算法
* 如:2,5,8,2,1,6序列中,第一个2就会因为与1交换,
* 从而排在第二个2的后面
* */
temp=array[minimum];
array[minimum]=array[i];
array[i]=temp;
}
} int main() {
int array[]={,,,,,};
selectSort(array,,);
for(int i=;i<;i++)
printf("%d,",array[i]);
}

议题:插入排序(insertion sort)

分析:

  • 实现之一:假定位于当前索引项左边的序列已经排好序,将当前项插入到左边序列中的合适位置,定位方法是从右向左依次比较,当遇到小于等于自己的项时停止,循环进行,直到数组结束;

  • 实现之二:主要是对实现之一的改进。针对点有二:避免无谓的赋值;减少测试条件。实现之一的内循环有两个检测条件,数组下标是否小于0和数组元素是否小于 等于当前元素,由于第一个条件在很少情况下才成立,所以可想办法简化。方法是:首先将数组中的最小值放于数组开始处,然后在剩余的范围中进行插入排序,从 而内循环仅有一个检测条件;

  • 弱势:运行效率取决于待排序序列的已排序程度(非适应性算法),顺序序列运行时间为N,逆序序列运行时间为N2。并且一次数据移动并不能保证此数据项在正确的排序位置,还需要为后面更小的元素移动;

  • 优势:减少数据复制,减少测试条件,使用标记元素将内循环中的多个条件测试合并为一个,目标元素在一次插入过程中仅有一次移动(虽然不是最终位置,虽然需要平移其他元素);

  • 性质:稳定排序,内部循环的跳出条件之一是判断数组元素是否小于当前索引元素,是的话就将当前索引元素插入其右边,所以相同键值的元素顺序不变。N2 /4次比较,N2 /4次半交换(也就是中间元素的顺移),最坏情况时比较和交换次数都加倍;

  • 时间:序列状态影响运行效率,顺序序列为N,逆序序列为N2,平均为N2

样例:

 void insertSort_1(int *array, int l, int r) {
int temp;
int index; /**
* 外循环从左向右的第二个元素开始处理array的
* 每一个元素; 并假定当前索引i左边的元素序列
* 都已经就序;
* */
for(int i=l+;i<=r;i++) {
/**
* 插入排序的策略是将array[i]的值插入到
* i左边已经就序的序列中;
* */
temp=array[i];
index=i-;
/**
* 第一个循环条件保证在到达array最左边时停止
* 第二个循环条件保证仅当temp更小时才继续处理
* 第二个循环条件保证插入排序是稳定性
* */
while(index>=l && array[index]>temp) {
/**
* 交换方式时将左边的元素顺次复制到紧靠
* 其右边的元素
* */
array[index+]=array[index];
index--;
}
/**
* 最终将array[i]放到指定位置
* */
array[index+]=temp;
}
} void insertSort_2(int *array, int l, int r) {
int temp;
int index;
int minimum=l; /**
* 寻找array中最小值,并将其与array[l]的值进行交换
* */
for(int i=l+;i<=r;i++) {
if(array[minimum]>array[i])
minimum=i;
}
temp=array[minimum];
array[minimum]=array[l];
array[l]=temp;
/**
* 外循环从左向右的第二个元素开始处理array的
* 每一个元素; 并假定当前索引i左边的元素序列
* 都已经就序;
* */
for(int i=l+;i<=r;i++) {
/**
* 插入排序的策略是将array[i]的值插入到
* i左边已经就序的序列中;
* */
temp=array[i];
index=i-;
/**
* 由于array[l]的元素为array中最小的元素
* 所以,内循环只需要一个循环条件,从而减少
* 内部循环的代码,加快执行速度
* */
while(array[index]>temp) {
/**
* 交换方式时将左边的元素顺次复制到紧靠
* 其右边的元素
* */
array[index+]=array[index];
index--;
}
/**
* 最终将array[i]放到指定位置
* */
array[index+]=temp;
}
} int main() {
int array[]={,,,,,};
insertSort_2(array,,);
for(int i=;i<;i++)
printf("%d,",array[i]);
return ;
}

议题:冒泡排序(Bubble Sort)

分析:

  • 实现之一:从左向右遍历数组,此为外循环,每一次遍历中将当前元素与它右边紧接的元素比较,较大的放于右边,重复这样的操作直到数组末尾,此为内循环,结束之后然后进入下一次外循环;非适应性算法,无论给定数据序列状态如何,运行时间相同;

  • 实现之二:当数组是顺序时,内层循环的每一次并不会进行交换;所以检测当且仅当内层循环一遍之后,没有发生任何交换,则可以跳出外层循环,此时排序完成。适应性算法,根据初始数据序列的状态决定排序时间;

  • 弱势:需要多次移动数据(平均每两次比较会又一次移动);一般来说,冒泡排序比其他两种N2排序算法要慢;

  • 优势:易于实现,前面的操作会为后面的操作提供排序信息提升性能(较大元素往右边集中),一次遍历将一个元素放到最终位置。可以改进为摇摆排序(Shaker Sort,将单向扫描数组改成从头到尾,从尾到头的交替式移动);

  • 性质:稳定排序,比较过程中仅当左边元素大于右边元素才交换,同等情况下比选择,插入排序慢。最坏情况下平均要N(N-1)/2次比较,N(N-1)/2次交换;

  • 时间:序列状态影响运行效率,顺序序列为N,逆序序列为N2,平均为N2

样例:

 void bubbleSort_1(int *array, int l, int r) {
int temp; /**
* 外循环从左向右遍历,每一次针对array上的一个位置i
* 的值;由于每次都是讲最小的元素交换到i的位置,所以
* 当处理array[r]的时候,最小的r-l个元素已经就位,
* 所以不用处理r位置的元素
* */
for(int i=l;i<r;i++) {
for(int j=r;j>i;j--) {
if(array[j-]>array[j]) {
/**
* 内循环从右向左处理每两个元素,并将
* 较小的元素放置到左边的位置
* */
array[j-]=array[j-]^array[j];
array[j]=array[j-]^array[j];
array[j-]=array[j-]^array[j];
}
}
}
} void bubbleSort_2(int *array, int l, int r) {
int temp;
bool isStable; /**
* 外循环从左向右遍历,每一次针对array上的一个位置i
* 的值;由于每次都是讲最小的元素交换到i的位置,所以
* 当处理array[r]的时候,最小的r-l个元素已经就位,
* 所以不用处理r位置的元素
* */
for(int i=l;i<r;i++) {
/**
* 加入isStable标志,如果内循环没有发生任何交换
* 操作,则说明序列已经就序,则直接跳出外循环;
* */
isStable=true;
for(int j=r;j>i;j--) {
if(array[j-]>array[j]) {
/**
* 内循环从右向左处理每两个元素,并将
* 较小的元素放置到左边的位置
* */
array[j-]=array[j-]^array[j];
array[j]=array[j-]^array[j];
array[j-]=array[j-]^array[j];
isStable=false;
}
}
if(isStable)
break;
}
} int main() {
int array[]={,,,,,};
bubbleSort_2(array,,);
for(int i=;i<;i++)
printf("%d,",array[i]);
return ;
}

议题:希尔排序(增量式插入排序)(Shell Sort)

分析:

  • 对插入排序的改进,插入排序中元素仅能通过与相邻元素的交换一步一步形成有序序列。现在首先大粒度地将元素交换到属于他的区域,再小粒度进一步缩小区域, 最终到达正确位置,这样可以减少中间不必要的交换,所以使得序列在一开始就整体上向着有序的方向前进,而进行远距离间隔的交换能达到目的;

  • 希尔排序使用一 个递减的间隔序列,分批进行插入排序,也就是间隔N时,分别对序列中间隔N的元素进行插入排序,然后对间隔next(N)的元素进行插入排序,最终间隔序 列达到1(也就是常规的插入排序);

  • 弱势:增量序列(Incremental Sequence)很难选择;

  • 优势:不像插入排序那样一次交换仅仅涉及邻接项,希尔排序是首先就在整体上使得序列趋于有序,然后逐渐细致到每项(这个时候序列已经呈现得很有序);

  • 性质:不稳定排序,相同索引键项在不同的间隔序列中可能在各自序列中被交换;使用的增量序列为:1,4,13,40,121,…………构建函数为 h=3*h+1,获取函数是h=h/3。在函数最开始的时候,根据数组元素的个数调整h的最大值,限制函数h<=(r-1)/9。使用增量三角(确 定当前值X后,他的左上方的值为x/3,右上方的值为x/2。前三项为1,2,3,然后按照规则生成的三角数阵,此为Pratt序列)获得的序列可以使得 比较次数少于N(㏒2 N)2

  • 时间:使用Knuth序列为N3/2,使用增量三角序列(Pratt序列)为N(㏒2 N)2

样例:

 void shellSort(int *array, int l, int r) {
int temp;
int index;
int interval;
/**
* 构造增量序列:1,4,13,40,121,364,……
* 此序列由Knuth在1969年推荐的;
* 为了保证对于一个增量interval而言,序列array中
* 都至少有三个元素l,l+h和l+2h,则需要加入(r-l)/9的限制
* 此序列最多可将shellsort算法的速度提升25%
*
* 当然也可以使用序列:1,8,23,77,281,1073,……
* */
for(interval=;interval<=(r-l)/;interval=*interval+);
/**
* 确定增量序列的最大可用值之后,按照从大到小的顺序对array序列
* 进行interval-增量排序,interval/=3可以取得下一个增量元素
* */
for(;interval>;interval/=) {
/**
* 内部循环完全是插入排序,只是之前处理相差1的元素需要替换为
* 相差interval的元素
* */
for(int i=l+interval;i<=r;i++) {
temp=array[i];
index=i-interval; while(index>=l && array[index]>temp) {
array[index+interval]=array[index];
index-=interval;
} array[index+interval]=temp;
}
}
} int main() {
int array[]={,,,,,};
shellSort(array,,);
for(int i=;i<;i++)
printf("%d,",array[i]);
return ;
}

笔试算法题(53):四种基本排序方法的性能特征(Selection,Insertion,Bubble,Shell)的更多相关文章

  1. 笔试算法题(58):二分查找树性能分析(Binary Search Tree Performance Analysis)

    议题:二分查找树性能分析(Binary Search Tree Performance Analysis) 分析: 二叉搜索树(Binary Search Tree,BST)是一颗典型的二叉树,同时任 ...

  2. php四种基础排序算法的运行时间比较

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  3. PHP四种基本排序算法

    PHP的四种基本排序算法为:冒泡排序.插入排序.选择排序和快速排序. 下面是我整理出来的算法代码: 1. 冒泡排序: 思路:对数组进行多轮冒泡,每一轮对数组中的元素两两比较,调整位置,冒出一个最大的数 ...

  4. php四种基础排序算法的运行时间比较!

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  5. 四种简单的图像显著性区域特征提取方法-----AC/HC/LC/FT。

    四种简单的图像显著性区域特征提取方法-----> AC/HC/LC/FT. 分类: 图像处理 2014-08-03 12:40 4088人阅读 评论(4) 收藏 举报 salient regio ...

  6. iOS中常用的四种数据持久化方法简介

    iOS中常用的四种数据持久化方法简介 iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data 1.属性列表涉及到的主要类:NSUserDefaults,一般 ...

  7. WordPress忘记密码找回登录密码的四种行之有效的方法

    WordPress忘记密码找回登录密码的四种行之有效的方法 PS:20170214更新,感谢SuperDoge同学提供的方法,登入phpMyAdmin后,先从左边选自己的数据库,然后点上面的 SQL ...

  8. Scrapy里Selectors 四种基础的方法

    在Scrapy里面,Selectors 有四种基础的方法xpath():返回一系列的selectors,每一个select表示一个xpath参数表达式选择的节点css():返回一系列的selector ...

  9. 笔试算法题(54):快速排序实现之单向扫描、双向扫描(single-direction scanning, bidirectional scanning of Quick Sort)

    议题:快速排序实现之一(单向遍历) 分析: 算法原理:主要由两部分组成,一部分是递归部分QuickSort,它将调用partition进行划分,并取得划分元素P,然后分别对P之前的部分和P 之后的部分 ...

随机推荐

  1. 10_传智播客iOS视频教程_NSString

    从今天开始不会再去用C语言当中的字符串.因为OC当中设计了一种更为好用的存储字符串的变量. C的字符串和OC的字符串是有区别的. NSString类型的指针变量,只能存储OC字符串的地址.第一步是声明 ...

  2. Ueditor中代码的高亮和背景在前端页面的实现

    首先废话就不多说,这个富文本编辑器的下载和js等基本文件的导入略. 我的最终目标是这样的,我们在页面中的富文本框中输入代码,希望它能够被后台接受.存入数据库,当通过服务器将这些代码再一次显示在前台的页 ...

  3. Linux 系统管理命令 - iotop - 动态显示磁盘 I/O 统计信息

    命令详解 重要星级: ★★★★☆ 功能说明: iotop 命令是一款实时监控磁盘 I/O 的工具, 但必须以 root 用户的身份运行.使用 iotop 命令可以很方便的查看每个进程使用磁盘 I/O ...

  4. 【WIP】Swift4 异常处理, JSON处理

    创建: 2018/03/24 更新: 2018/06/05 补充catch可以只带where不带模式 [任务表]TODO 异常处理语法  异常的发生 抛出例外 thorw 式 ● 抛出的值的类型必须采 ...

  5. E20180219-hm-xa

    comparison n. 比较,对照; [语] 比喻; 比较级; conjunction  n. 连接; 连词; 联合,结合物; (恒星.行星等的) 合; [例句] assignment  n. 分 ...

  6. 不让浏览器缓存input的值

    方法一: 在不想使用缓存的input中添加 autocomplete="off"eg: <input type="text" autocomplete=& ...

  7. bzoj 2750: [HAOI2012]Road【spfa+dfs】

    枚举起点做spfa,然后一条边在最短路上的条件是dis[e[i].to]==dis[u]+e[i].va,所以每次spfa完之后,dfs出a[i]表示经过i点的最短路的起点数,b[i]表示经过i点的最 ...

  8. USACO Training刷题记录 By cellur925

    Section 1.1 Your Ride Is Here 貌似没啥可说 Greedy Gift Givers 上来就想stl map映射,有两个坑:如果送给别人的人数为0,那么需要特判一下,防止整数 ...

  9. 有了Git这些操作,我再也不怕开发了!

    Git 是什么? Git 是一个分布式的代码管理容器,本地和远端都保有一份相同的代码. Git 仓库主要是由是三部分组成:本地代码,缓存区,提交历史. Git 有哪些常规操作? Git的常规操作你了解 ...

  10. [POI2009]SLO

    Description 对于一个1-N的排列(ai),每次你可以交换两个数ax与ay(x<>y),代价为W(ax)+W(ay) 若干次交换的代价为每次交换的代价之和.请问将(ai)变为(b ...