c++(非递归排序)
在上面一篇博客当中,我们发现普通查找和排序查找的性能差别很大。作为一个100万的数据,如果使用普通的查找方法,那么每一个数据查找平均下来就要几十万次,那么二分法的查找呢,20多次就可以搞定。这中间的差别是非常明显的。既然排序有这么好的效果,那么这篇博客中,我们就对排序算做一个总结。
按照我个人的理解,排序可以分为两种:一种是非递归排序,它主要按照非递归的方法对数据进行排序,也就是说主要数据的移位和循环来完成;另外一种就是递归方法,我们在排列当前数据的时候首先把子数据排列有序,然后才会排列当前的数据。这种不断递归调用的方法就是递归排序。
非递归排序的方法很多,这里主要介绍冒泡排序、插入排序、希尔排序;递归的方法也不少,这里介绍的方法是快速排序、归并排序和堆排序。排序的内容很多,本篇博客主要介绍非递归排序,递归排序的内容主要在下一节内容解决。
(1)冒泡排序
冒泡排序的内容并不复杂。假设有n个数据需要排序,那么我们需要确定n个从大到小的数据,每一次都挑选第n大的数据是多少,并且放大相应的位置。直到所有的数据都排列整齐了,那么我们的排序就结束了。
- void bubble_sort(int array[], int length)
- {
- int inner = 0, outer = 0;
- int median = 0;
- if(NULL == array || 0 == length)
- return;
- for(outer = length-1; outer >= 1; outer --){
- for(inner = 0; inner < outer; inner ++){
- if(array[inner] > array[inner + 1]){
- median = array[inner];
- array[inner] = array[inner + 1];
- array[inner + 1] = median;
- }
- }
- }
- }
void bubble_sort(int array[], int length)
{
int inner = 0, outer = 0;
int median = 0; if(NULL == array || 0 == length)
return; for(outer = length-1; outer >= 1; outer --){
for(inner = 0; inner < outer; inner ++){
if(array[inner] > array[inner + 1]){
median = array[inner];
array[inner] = array[inner + 1];
array[inner + 1] = median;
}
}
}
}
那么这个程序有没有什么改进的地方呢?当然存在,如果发现在一次遍历循环之中,如果没有发生移位的现象,那么是不是可以判断这个排序可以结束了呢?朋友们可以好好思考一下这个问题?
- void bubble_sort(int array[], int length)
- {
- int inner = 0, outer = 0;
- int median = 0;
- int flag = 1;
- if(NULL == array || 0 == length)
- return;
- for(outer = length-1; outer >= 1 && flag; outer --){
- flag = 0;
- for(inner = 0; inner < outer; inner ++){
- if(array[inner] > array[inner + 1]){
- median = array[inner];
- array[inner] = array[inner + 1];
- array[inner + 1] = median;
- if(flag == 0)
- flag = 1;
- }
- }
- }
- }
void bubble_sort(int array[], int length)
{
int inner = 0, outer = 0;
int median = 0;
int flag = 1; if(NULL == array || 0 == length)
return; for(outer = length-1; outer >= 1 && flag; outer --){
flag = 0; for(inner = 0; inner < outer; inner ++){
if(array[inner] > array[inner + 1]){
median = array[inner];
array[inner] = array[inner + 1];
array[inner + 1] = median; if(flag == 0)
flag = 1;
}
}
}
}
(2) 插入排序
插入排序的意思就是说,我们把数据分成两个部分,一部分是已经排好序的数据,一部分是当前还没有完成排序的数据。那么这么说来的话,排序的过程是不是就是把没有排序的数据逐个插入到已经排好序的队列中的过程呢。大家可以自己先试一下,然后再看看我的代码对不对?
- void insert_sort(int array[], int length)
- {
- int inner = 0;
- int outer = 0;
- int median = 0;
- if(NULL == array || 0 == length)
- return;
- for(outer = 1; outer <length; outer ++){
- for(inner = outer; inner >= 1; inner --){
- if(array[inner] < array[inner -1]){
- median = array[inner];
- array[inner] = array[inner -1];
- array[inner -1] = median;
- }else{
- break;
- }
- }
- }
- }
void insert_sort(int array[], int length)
{
int inner = 0;
int outer = 0;
int median = 0;
if(NULL == array || 0 == length)
return; for(outer = 1; outer <length; outer ++){
for(inner = outer; inner >= 1; inner --){
if(array[inner] < array[inner -1]){
median = array[inner];
array[inner] = array[inner -1];
array[inner -1] = median;
}else{
break;
}
}
}
}
那么插入排序有没有像冒泡排序那样的改进方法呢?其实没有。因为每一次插入排序的位置都是局部比较的结果,而冒泡排序每一次的内容都是全局最优的。这从数据比较的次数就可以看出来。
(3)希尔排序
希尔排序,我个人认为可以看成是冒泡排序的变种。它的基本思想是:首先按照一个序列递减的方法逐渐进行排序。比如说有10个数据,我们按照序列5、3、1的顺序进行排序。首先是5,那么我们对1和6、2和7、3和8、4和9、5和10进行排列;第二轮是3,那么对数据1、4、7、10排列,再对2、5、8进行排列,以及3、6、9排列;第三轮就和冒泡排序一样了,以此对每个数据进行排列。它的优势就是让整个队列基本有序,减少数据移动的次数,从而降低算法的计算复杂度。
- void shell_sort(int array[], int length, int step)
- {
- int inner = 0;
- int outer = 0;
- int median = 0;
- if(NULL == array || 0 == length)
- return;
- for(; step >= 1; step -=2){
- for(int index = 0; index < step; index ++){
- if((length -1) < (index + step))
- continue;
- else{
- outer = index + step;
- while( (outer + step) <= (length - 1))
- outer += step;
- }
- for(; outer >= (index + step); outer -= step){
- for(inner = index; inner <= outer - step; inner += step){
- if(array[inner] >= array[inner + step]){
- median = array[inner];
- array[inner] = array[inner + step];
- array[inner + step] = median;
- }
- }
- }
- }
- }
- }
void shell_sort(int array[], int length, int step)
{
int inner = 0;
int outer = 0;
int median = 0; if(NULL == array || 0 == length)
return; for(; step >= 1; step -=2){
for(int index = 0; index < step; index ++){
if((length -1) < (index + step))
continue;
else{
outer = index + step;
while( (outer + step) <= (length - 1))
outer += step;
} for(; outer >= (index + step); outer -= step){
for(inner = index; inner <= outer - step; inner += step){
if(array[inner] >= array[inner + step]){
median = array[inner];
array[inner] = array[inner + step];
array[inner + step] = median;
}
}
}
}
}
}
总结:
(1)上面的排序都是非递归程序,理解上不难,但是细节问题需要注意,特别是长度的问题
(2)代码编写的时候务必注意测试用例的设计
(3)如果可能的情况下,多使用已经验证的代码和函数
c++(非递归排序)的更多相关文章
- C#实现(递归和非递归)高速排序和简单排序等一系列排序算法
本人由于近期工作用到了一些排序算法.就把几个简单的排序算法.想冒泡排序,选择排序,插入排序.奇偶排序和高速排序等整理了出来,代码用C#代码实现,而且通过了測试.希望能给大家提供參考. ...
- 笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)
议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小) 分析: 算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法:使用显示下推栈存储快速排 ...
- 排序算法练习--JAVA(插入、直接选择、冒泡、快速排序、非递归快速排序)
排序算法是数据结构中的经典算法知识点,也是笔试面试中经常考察的问题,平常学的不扎实笔试时候容易出洋相,回来恶补,尤其是碰到递归很可能被问到怎么用非递归实现... package sort; impor ...
- 排序算法C语言实现——快速排序的递归和非递归实现
/*快排 - 递归实现nlogn*//*原理: 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排 ...
- 合并两个排序的链表递归和非递归C++实现
题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,要求合成后的链表满足单调不减规则. 1.分析 已知输入的两个链表递增有序,要使输出的链表依然递增有序,可以依次从输入的两个链表中挑选最小的 ...
- java:合并两个排序的链表(递归+非递归)
//采用不带头结点的链表 非递归实现 public static ListNode merge(ListNode list1,ListNode list2){ if(list1==null) retu ...
- 先贴上代码:Random快排,快排的非递归实现
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为主元,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序.值得注意的是, ...
- javascript实现非递归--归并排序
另一道面试题是实现归并排序,当然,本人很不喜欢递归法,因为递归一般都是没有迭代法好.所以首选都是用迭代法,但是迭代法确实是难做啊,至底而上的思想不好把握. 这是我的实现代码 /* * * 非递归版归并 ...
- 深度优先搜索(DFS)递归形式改为非递归形式
DFS将递归改为非递归这个方法的需求来自于一道三维积木组合的题目,还在苦苦调试中,暂且不提. 普通的认识对于递归向非递归的转化无非是使用栈,但是结合到深度搜索如何将栈很好利用,如何很好保存现场,都不是 ...
随机推荐
- web调用客户端程序
背景 最近做一个集成需求,我们是B/S架构的,对方是C/S架构的,对方直接扔过来一个EXE连OCX都没有,让我们调用,也就是说,我们需要通过js程序去调用他们的客户端程序并传入多个参数,当时内心是崩溃 ...
- Python 项目实践二(下载数据)第四篇
接着上节继续学习,在本节中,你将下载JSON格式的人口数据,并使用json模块来处理它们.Pygal提供了一个适合初学者使用的地图创建工具,你将使用它来对人口数据进行可视化,以探索全球人口的分布情况. ...
- Golang丰富的I/O----用N种Hello World展示
h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...
- 使用 JSON.parse 反序列化 ISO 格式的日期字符串, 将返回Date格式对象
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- UNIX域协议(无名套接字)
关于什么是UNIX域套接字可以参考:http://www.cnblogs.com/xcywt/p/8185597.html这里主要介绍非命名的UNIX域套接字的用法.1.socketpair函数先看m ...
- [编织消息框架][JAVA核心技术]异常基础
Java异常体系结构 Thorwable类所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常. 其中异常类Exception又分为运行时异常(RuntimeExcept ...
- Windows 7样式地址栏(Address Bar)控件实现
介绍 从Vista开始,地址栏就有了很大的改变,不知道大家有什么感觉,笔者觉得很方便,同时又兼容之前的功能,是个很不错的创新.不过,微软并不打算把这一很酷的功能提供给广大的开发人员. 本文提供了一个简 ...
- Life in Changsha 第一次scrum冲刺
第一次冲刺任务 基于大局的全面性功能框架定位,要求能实现用户基于自己的需求进行的一系列操作. 用户故事 用户打开“生活在长大”的界面 程序首页展示校园服务,论坛等相关信息 用户选择某个功能 程序界面跳 ...
- Fiddler中设置断点修改返回结果Response
测试有时会遇到需要测试返回不同的数据前端展示出来会如何?如果去数据库中的数据会比较麻烦.这样我们可以通过fiddler设置断点来修改返回的数据实现测试不同的数据展示. 1.设置断点 (1)点击菜单栏按 ...
- Python新式类与经典类的区别
1.新式类与经典类 在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性:反之,即不由任意内置类型派生出的类 ...