菜鸟学习从入门到放弃(二)排序算法总结与应用(附代码)
2016-10-20 16:27
996 查看
排序算法的总结,水平有限,欢迎指正。文章介绍插入排序(直接插入排序—>希尔排序)、交换排序(冒泡排序—>快速排序)、选择排序(简单选择排序—>堆排序)、归并排序、桶排序、基数排序和计数排序共10种排序算法。最后有10种排序算法性能的比较的表格。
大部分都是别人的东西,主要参考:王红梅等.数据结构(C++版).清华大学出版社;算法导论(第三版)。我只是搬运工,出处不一定注得明。代码实现直接插入排序、冒泡排序、简单选择排序、希尔排序和快速排序。
常用排序算法主要是插入排序、交换排序和选择排序,所以先介绍。
第一步:将待排序序列分为有序区和无序区,初始状态有序区为序列第一个数,无序区为序列剩下数字。
第二步:将无序区第一个数字与有序区比较,并将其插入到适合的位置。
第三步:重复第二步直到无序区数字全部进入有序区。
首先整个待排序序列的分割:理论上间隔1<=d<=n都可,将相距为d的记录化为一组,将整个待排序序列分为d组(子序列),在子序列进行直接插入排序。(通常将d选n/2的下取整,然后迭代d/2)
重复分割直到d=1,即所有记录已经在一个序列中,并进行了一次直接插入排序。就可以到有序序列。
第一步:将待排序序列分为,有序序列和无序序列两个,初始有序序列记录是空,无序序列是整个待排序序列。
第二步:从序列第一个记录开始从头到尾比较相邻记录,如果是反序就交换,所以使得最值(最大值或者最小值)向后移动,进入有序序列。如上图第一趟排序就将最大值67移动到最后一个记录,作为第一个有序记录。
第三步:重复第二步直到无序序列记录为空或者所有无序序列中没有交换(这一步很重要,可以提前结束遍历,表示整个序列已经有序了)。
上图表示以29为轴值将序列分为大于29和小于29的两个部分。
第一步:将待排序序列分为有序和无序两部分,初始状态,无序为空,有序序列为整个待排序序列。
第二步:在无序区选取最值,并将它与无序区的第一个交换,同时将其纳入有序区,无序区记录减一。
第三步:重复第二步直到无序区只剩最后一个记录。
补充:
堆:指的是具有以下性质的完全二叉树:每个节点的值都大于等于其左右孩子节点的值(大根堆)或者每个节点的值都小于等于其左右孩子节点的值(小根堆)。
当然还有:
二路归并排序,将待排序每个记录看成有序序列,然后两两归并,直到合并为一个有序序列。
上面假设待排序序列值为0~9然后将0~9分为10个桶,将待排序序列分别分配到10个桶中,然后依次收集含有记录的桶中的记录即可得到排序序列。桶可以用静态链表实现,而桶中重复的序列可以采用队列存储,所以桶排序是稳定排序。
以上图为例:无序序列为:2、5、3、0、2、3、0、3。统计序列中记录值从小到大出现的累计次数。0出现两次所以将统计数组对于位置赋值为2,1出现0次2+0=2不变,2出现2次所以2+2=4,索引为2的位置的值被附为4,以此类推。最后输出统计数组中数值发生变化的数字,相邻变化差值为数字出现的次数。输出可得到有序序列。
希尔排序
大部分都是别人的东西,主要参考:王红梅等.数据结构(C++版).清华大学出版社;算法导论(第三版)。我只是搬运工,出处不一定注得明。代码实现直接插入排序、冒泡排序、简单选择排序、希尔排序和快速排序。
常用排序算法主要是插入排序、交换排序和选择排序,所以先介绍。
(一)插入排序(直接插入排序—>希尔排序)
1、直接插入排序
基本思想:一次将待排序中的每一个记录插入到一个已排好序的序列,直到全部记录都排好序。类似于玩纸牌你已经将35789排好摸到一张6,就从3开始比较,3比6小,5比6小,到7比6大,所以6插到5和7之间。具体步骤如图:第一步:将待排序序列分为有序区和无序区,初始状态有序区为序列第一个数,无序区为序列剩下数字。
第二步:将无序区第一个数字与有序区比较,并将其插入到适合的位置。
第三步:重复第二步直到无序区数字全部进入有序区。
2、希尔排序
希尔排序是对直接插入法的一种改进:先将整个待排序序列分割成若干个子序列,将子序列排序,然后合并,此时序列已经基本有序,再进行一次直接插入排序。如下图:首先整个待排序序列的分割:理论上间隔1<=d<=n都可,将相距为d的记录化为一组,将整个待排序序列分为d组(子序列),在子序列进行直接插入排序。(通常将d选n/2的下取整,然后迭代d/2)
重复分割直到d=1,即所有记录已经在一个序列中,并进行了一次直接插入排序。就可以到有序序列。
(二)交换排序(冒泡排序—>快速排序)
1、冒泡排序
冒泡排序通过两两比较相邻记录大小,反序交换位置,直到没有反序的记录为止。如图:第一步:将待排序序列分为,有序序列和无序序列两个,初始有序序列记录是空,无序序列是整个待排序序列。
第二步:从序列第一个记录开始从头到尾比较相邻记录,如果是反序就交换,所以使得最值(最大值或者最小值)向后移动,进入有序序列。如上图第一趟排序就将最大值67移动到最后一个记录,作为第一个有序记录。
第三步:重复第二步直到无序序列记录为空或者所有无序序列中没有交换(这一步很重要,可以提前结束遍历,表示整个序列已经有序了)。
2、快速排序
快速排序是对冒泡排序的改进,基本思想是:首先选一个轴值,以此为分界,分为大于该值和小于该值的两部分,然后重复该操作,直到整个序列有序。如图:上图表示以29为轴值将序列分为大于29和小于29的两个部分。
(三)选择排序(简单选择排序—>堆排序)
1、简单选择排序
基本思想是:第i躺排序,将无序列记录(整个序列第i个到第n个)中最值(最小或者最大值)选出来,放到整个序列第i个位置,序列的前i个记录即为有序的。如图:第一步:将待排序序列分为有序和无序两部分,初始状态,无序为空,有序序列为整个待排序序列。
第二步:在无序区选取最值,并将它与无序区的第一个交换,同时将其纳入有序区,无序区记录减一。
第三步:重复第二步直到无序区只剩最后一个记录。
2、堆排序
堆排序是对简单选择排序的改进,利用堆的性质进行排序。基本思想:首先将待排序序列的记录构造成堆,取堆顶记录,即所有记录的最值,并将其移入有序区,将剩下的记录再构造成堆,这样又能找到此最值,一次类推,直到只剩一个记录。补充:
堆:指的是具有以下性质的完全二叉树:每个节点的值都大于等于其左右孩子节点的值(大根堆)或者每个节点的值都小于等于其左右孩子节点的值(小根堆)。
当然还有:
(一)归并排序
归并排序:将若干有序序列逐步归并,最终归并为一个有序序列。我们常用的是二路归并排序,如图:二路归并排序,将待排序每个记录看成有序序列,然后两两归并,直到合并为一个有序序列。
(二)桶排序
桶排序是一种简单的分配排序,它是基于均匀分布假设的,基本思想:假设待排序记录的值都在0~m-1之间,设置m个桶,将值为i的记录分配到第i个桶中,然后将各个桶的记录依次收集起来即可。如图:上面假设待排序序列值为0~9然后将0~9分为10个桶,将待排序序列分别分配到10个桶中,然后依次收集含有记录的桶中的记录即可得到排序序列。桶可以用静态链表实现,而桶中重复的序列可以采用队列存储,所以桶排序是稳定排序。
(三)基数排序
基数排序排序的基本思想是:将关键码看成若干子关键码复合而成,然后借助分配和收集操作采用最次为优先的方法进行排序(还真没想好怎么解释。。。。。)。稳定排序算法。如图:(四)计数排序
计数排序基本思想:对每个输入元素x,确定小于x的元素的个数。如图:以上图为例:无序序列为:2、5、3、0、2、3、0、3。统计序列中记录值从小到大出现的累计次数。0出现两次所以将统计数组对于位置赋值为2,1出现0次2+0=2不变,2出现2次所以2+2=4,索引为2的位置的值被附为4,以此类推。最后输出统计数组中数值发生变化的数字,相邻变化差值为数字出现的次数。输出可得到有序序列。
排序算法性能比较
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 是否稳定 |
直接插入 | O(n2) | O(n) | O(n2) | O(1) | 是 |
希尔排序 | O(nlogn)~O(n2) | O(n1.3) | O(n2) | O(1) | 否 |
冒泡排序 | O(n2) | O(n) | O(n2) | O(1) | 是 |
快速排序 | O(nlogn) | O(nlogn) | O(n2) | O(nlogn)~O(n ) | 否 |
简单选择 | O(n2) | O(n2) | O(n2) | O(1) | 否 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 否 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 是 |
基数排序 | O(d(n+m)) | O(d(n+m)) | O(d(n+m)) | O(m) | 是 |
计数排序 | O(n) | O(n) | O(n) | O(n+k) | 是 |
桶排序 | O(n+m) | O(n+m) | O(n+m) | O(m) | 是 |
代码实现
直接插入排序
void insertion_sort(int r[], int n)//直接插入排序insertion { for (int i = 1; i < n; i++) { int temp = r[i]; int j; for ( j = i-1; r[j] > temp;j--) r[j + 1] = r[j]; r[j+1] = temp; } }冒泡排序
void bubble_sort(int r[], int n) //冒泡排序bubble { int exchange = n;//设置标志,提前结束循环 for (int i = 0; i < n&&exchange != 0; i++) { exchange = 0; for (int j = 0; j < n - i - 1; j++) if (r[j] > r[j + 1]) { int temp = r[j + 1]; r[j + 1] = r[j]; r[j] = temp; exchange++; } } }简单选择排序
void select_sort(int r[], int n) //简单选择排序select { for (int i = 0; i < n; i++) for (int j=0; j < n - i;j++) if (r[n-i-1]<r[j]) { int temp = r[j]; r[j] = r[n - i-1]; r[n - i-1] = temp; } }
希尔排序
void shell_sort(int r[], int n) //希尔排序shell { for (int d = n/2; d >= 1 ; d=d/2) for (int i = d; i < n; i++) { int temp = r[i]; int j; for (j = i - d; j >= 0 && r[j] > temp; j = j - d) r[j + d] = r[j]; r[j + d] = temp; } }快速排序
void quick_sort(int r[], int begin, int end) //快速排序quick { int partition(int r[], int begin, int end); if (begin<end) { int i = partition(r, begin, end); quick_sort(r, begin, i - 1); quick_sort(r, i + 1, end); } } int partition(int r[], int begin, int end) { int x = r[end]; int j = begin-1; for (int i = begin; i <= end-1; i++) { if (r[i] <= x) { j++; int temp = r[j]; r[j] = r[i]; r[i] = temp; } } int tem = r[j+1]; r[j+1] = r[end]; r[end] = tem; return j+1; }
综合实现
#include<iostream>
//#include"stdlib.h"
using namespace std;
void main()
{
void insertion_sort(int r[],int n); //直接插入排序insertion
void shell_sort(int r[], int n);//希尔排序shell
void bubble_sort(int r[], int n);//冒泡排序bubble
void quick_sort(int r[], int begin, int end); //快速排序quick
void select_sort(int r[], int n);//简单选择排序select
cout << "直接插入排序..." << endl;//直接插入排序insertion
int a[10];
for (int i = 0; i < sizeof(a)/sizeof(int); i++)
a[i] = rand() % 9;
cout << "原有序列:" ;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
insertion_sort(a, sizeof(a) / sizeof(int));
cout << endl;
cout << "有序序列:" ;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
cout << endl;
//希尔排序shell
cout << "希尔排序..." << endl;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = rand() % 9;
cout << "原有序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
shell_sort(a, sizeof(a) / sizeof(int));
cout << endl;
cout << "有序序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
cout << endl;
//冒泡排序bubble
cout << "冒泡排序..." << endl;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = rand() % 9;
cout << "原有序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
bubble_sort(a, sizeof(a) / sizeof(int));
cout << endl;
cout << "有序序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
cout << endl;
//快速排序quick
cout << "快速排序..."
89cf
<< endl;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = rand() % 9;
cout << "原有序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
quick_sort(a,0, sizeof(a) / sizeof(int)-1);
cout << endl;
cout << "有序序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
cout << endl;
//简单选择排序select
cout << "简单选择排序..." << endl;
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = rand() % 9;
cout << "原有序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
select_sort(a, sizeof(a) / sizeof(int));
cout << endl;
cout << "有序序列:";
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
cout << a[i] << ",";
cout << endl;
}
void insertion_sort(int r[], int n)//直接插入排序insertion { for (int i = 1; i < n; i++) { int temp = r[i]; int j; for ( j = i-1; r[j] > temp;j--) r[j + 1] = r[j]; r[j+1] = temp; } }
void shell_sort(int r[], int n) //希尔排序shell { for (int d = n/2; d >= 1 ; d=d/2) for (int i = d; i < n; i++) { int temp = r[i]; int j; for (j = i - d; j >= 0 && r[j] > temp; j = j - d) r[j + d] = r[j]; r[j + d] = temp; } }
void bubble_sort(int r[], int n) //冒泡排序bubble { int exchange = n;//设置标志,提前结束循环 for (int i = 0; i < n&&exchange != 0; i++) { exchange = 0; for (int j = 0; j < n - i - 1; j++) if (r[j] > r[j + 1]) { int temp = r[j + 1]; r[j + 1] = r[j]; r[j] = temp; exchange++; } } }
void quick_sort(int r[], int begin, int end) //快速排序quick { int partition(int r[], int begin, int end); if (begin<end) { int i = partition(r, begin, end); quick_sort(r, begin, i - 1); quick_sort(r, i + 1, end); } } int partition(int r[], int begin, int end) { int x = r[end]; int j = begin-1; for (int i = begin; i <= end-1; i++) { if (r[i] <= x) { j++; int temp = r[j]; r[j] = r[i]; r[i] = temp; } } int tem = r[j+1]; r[j+1] = r[end]; r[end] = tem; return j+1; }
void select_sort(int r[], int n) //简单选择排序select { for (int i = 0; i < n; i++) for (int j=0; j < n - i;j++) if (r[n-i-1]<r[j]) { int temp = r[j]; r[j] = r[n - i-1]; r[n - i-1] = temp; } }
相关文章推荐
- android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结
- git学习 - 理解、总结及菜鸟(本人)入门
- PHP学习总结(2)——PHP入门篇之PHP代码标识
- 菜鸟学习从入门到放弃(一)关于动态规划一些不太成熟的小理解
- 菜鸟入门 个人学习Linux知识总结
- DQN从入门到放弃学习总结(2)
- PHP学习总结(2)——PHP入门篇之PHP代码标识
- Linux经验总结:linux的入门学习流程(菜鸟发贴,仅供参考)(更新RHCE完结)
- Linux经验总结:linux的入门学习流程(菜鸟发贴,仅供参考)(更新RHCE完结)
- OSWorkflow入门学习4--包用途分析及代码片断
- 学习maven的使用,看到一篇很实用的入门教程(菜鸟级入门)
- PHP入门学习的几个不错的实例代码
- XHTML入门学习教程:XHTML网页图片应用
- XHTML入门学习教程:表格标签的应用
- 续:关于J2EE的学习与总结(非菜鸟勿看)
- struts 入门基础知识学习总结(转)
- Javascript入门学习第九篇 Javascript DOM 总结第1/2页
- Javascript入门学习第九篇 Javascript DOM 总结第1/2页
- 我学习rmi的入门总结
- 关于pl/sql调用java的学习总结(附代码)