16 - 12 - 17 十大排序算法总结(一) 之 冒泡,简选,直插,希尔排序
来源:互联网 发布:药店用的软件 编辑:程序博客网 时间:2024/05/01 07:04
排序用到的结构与函数
这里先提供一个用于排序用的顺序表结构,这个结构将用于接下来介绍的所有排序算法。
#define MAXSIZE 10typedef struct{ int r[MAXSIZE]; //用于存储待排序数组,r[0]作为哨兵或者临时变量 int length; //用于记录顺序表的长度 }SqList;
此外,由于排序最常用到的操作是数组两元素的交换,这里写成一个函数,如下所示:
void swap(SqList *L, int i, int j) // 交换L中数组r的下标为i和j的值{ int temp = L->r[i]; L->r[i] = L->r[j]; L->r[j] = temp;}
一、冒泡排序
void BubbleSort0(SqList *L){ //冒泡排序初级版 1.0 int i, j; for (i = 0; i < L->length - 1; i++) { for (j = i + 1; j <= L->length - 1; j++){ if (L->r[i] > L->r[j]){ // 实现递增排序 swap(L, i, j); } } }} //严格:只能算是最最简单的交换排序,效率低下
void BubbleSort(SqList *L) //冒泡排序1.5{ int i,j; for(i = 1;i < L->length ;i++) { for(j = L->length - 1;j >= i;j--) //j从后往前循环 { if(L->r[j] > L->r[j + 1]) swap(L, j, j+1); } }}
冒泡能否再进行优化呢??当然,比如:
{2,1,3,4,5,6,7,8,9} , 只需要交换2,1就可以了,后面的比较全部都是多余的,那么我们就可以设置标志变量 flag
void BubbleSort(SqList *L) //冒泡排序1.5{ int i,j; Status flag = TRUE; //ex: int flag = 1; for(i = 1;i < L->length ;i++) { flag = FALSE; //初始化为FALSE for(j = L->length - 1;j >= i;j--) //j从后往前循环 { if(L->r[j] > L->r[j + 1]) swap(L, j, j+1); flag = TRUE; //发生数据交换时 } }}//当一次j循环中一次循环也没有发生,说明已经拍好了序列,跳出。
分析冒泡时间复杂度:最坏情况下需要比较:1+2+3+ + n-1 =n(n-1)/2 ,故O(n^2).
二、简单选择排序
通过 n-i 次关键字间的比较,从 n-i+1 个关键字最小的记录,
并和第 i 个记录交换值。
void SelectSort(SqList *L){ int i,j,min; for (i = 1; i < L->length ;i++) //FOR 1 { min = i; for (j = i+1; j < L->length ; j++) //FOR 2 { if(L->r[min] > L->r[j]) min = j; } if(i != min) swap(L,i,min); }}/*Loop 1 :*r[1] <r[j] ,只要有r[j]小于r[1],min = j,一次FOR 2 结束后,就找到了数组中拥有最小关键字的下标,把这个下标赋给min. 可以发现,交换的次数极少。 */
分析时间复杂度:无所谓最好或最差,都一样,n(n-1)/2次。O(n^2).性能比略优于冒泡
三、直接插入排序
在日常生活中,经常碰到这样一类排序问题:把新的数据插入到已经排好的数据列中。例如:一组从小到大排好顺序的数据列{1,2,3,4,5,6,7,9,10},欲把一个新的数据8插入到上述序列中。
直接插入排序(straight insertion sort)的做法是:
/每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序/
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
下面的 temp 相当于一个标志位,也算是哨兵。
如 arr[10] = {9,8,7,6,5,4,3,2,1,0}
// length=sizeof(arr)/sizeof(arr[0]);void InsertSort(int arr[]){ int i,j; for(i = 1 ; i < arr.length ; i++ ) { if( arr[i] < arr[i-1] ) //a[1]<a[0],a[1]需要前插。 { int temp = arr[i]; //temp = a[1]; for(j = i-1; j >= 0 && arr[j] > temp; j --) { arr[j+1] = arr[j]; //把比temp大或相等的元素全部后移一位,空出空位,让temp插入。 } arr[j+1] = temp;//把待排序的temp插入腾出位置的(j+1) } } }
@@:直接插入性能分析:仅多占用了一个元素空间,
时间效率上为O(n^2),但是比与冒泡,简单选择排序 稍微好一些。
最差(全逆序)需要比较 2+3+4+ +n = (n+2)*(n+1)/2 次。
四、希尔排序(Shell Sorting)
直接插入法再元素个数少,或者元素基本有序时候效率很高,但是数据量太大时候,就需要改进版的强插入排序:希尔排序。
排成基本有序,ex:{2,1,3,4,6,5,7,8,9}
需要把大的集合跳跃分割成一个一个小的子集。
第一次 increm(增量) = 10 / 2 = 5
↑ 图 第一次分了5组,(9,4)(1,8)(2,6)…在分别对组内直接插入排序,合并。
再分:5/2=2,成两组,对基本有序的组内直接插入排序,合并。
再分:2/2=1,对高度基本有序的序列直接插入排序,效率超高。
void ShellSort(int *a) // a是数组名。ex a[10]{ int i, j, k, t; k = L->length / 2 + 1; //k=6 while(k > 0) { for(i = k; i < n; i++)//FOR 1 //i=6 { t = a[i]; //t = a[6] j = i - k; //j=0; while(j >= 0 && t < a[j]) //若a[6]<a[0] ; { a[j + k] = a[j]; //a[6]=a[0] ; j = j - k; //j=-6 ; } a[j + k] = t; //a[0] =t=a[6] ; } // FOR 1 循环完后,第一趟排序己经排好,已经是大致有序了 k /= 2; //k=3; }}
我们用的测试数组如下:::::::::::::::::::::::::{8,10,3,5,7,4,6,1,9,2,4,23,4,346,3,346,34,6234,2334,23534,3646,5676,43,5,34,53,45,434,5,34534,534,234,235,345,45,568,464,568,35,2475,5685,234,456,23456,2345,4567,465,98};
性能良好。
性能分析:这里我们选取的增量是k ,每次除以2 ,但究竟除以几才能达到最好的性能,还是一个难题。
由于是一种跳跃式的移动,所以是一种不稳定排序。
未完待续,期待二~
鸣谢:
htp://www.cnblogs.com/MOBIN/p/4679208.html
- 16 - 12 - 17 十大排序算法总结(一) 之 冒泡,简选,直插,希尔排序
- 简单排序算法的汇总(快速排序、直插排序、希尔排序、选择排序、冒泡排序)
- 算法--直插排序
- 白话算法之直插排序
- 16 - 12 - 17 十大排序算法总结(二) 之 桶排序,堆排序
- C/C++十大经典排序算法之希尔排序
- 排序算法一之冒泡 选择 插入 希尔排序
- 直插,折半,二路,希尔排序
- 插入类排序:直插,折半插,希尔
- 排序算法(一):冒泡,选择,插入,希尔
- 冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序六大排序大总结
- 16 - 12 - 18 十大排序算法总结(三) 之 归并排序
- 16 - 12 - 19 十大排序算法总结(四) 之 快速排序
- 排序算法总结之希尔排序
- 排序算法总结之希尔排序
- 排序算法总结之希尔排序
- 排序算法总结(一)——冒泡、插入、希尔与选择排序
- (十)数据结构之希尔排序算法实现
- poj2239-Selecting Courses(匈牙利算法)
- 实习每日总结_20161214
- linux 中的echo
- Linux 服务器上安装Jenkins
- KISSY基础篇乄KISSY之DOM(1)
- 16 - 12 - 17 十大排序算法总结(一) 之 冒泡,简选,直插,希尔排序
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)
- Corefig for Windows Server 2012 Core and Hyper-V Server 2012
- Dubbo(二)聚合工程之实体类,通用Parent Demo
- 【每日一记】设计模式——组合模式
- 【51nod】1134 最长递增子序列
- Android开发中的多线程
- 正则表达式笔记(java编程思想)
- 静态路由的设置以及缺省路由的发布