议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小)

分析:

  • 算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法;使用显示下推栈存储快速排序中的每一次划分结果 (将left和right都压入堆栈),并且首先处理划分序列较短的子序列(也就是在得到一次划分的左右部分时,首先将长序列入栈,然后让段序列入栈), 这样可以保证当快速排序退化的线性效率的时候,栈大小仍旧在㏒N范围内。算法策略类似于最小子树优先遍历规则;

  • 弱势:当序列已经就绪,每次划分元素选取为最左边或者最右边的值,一次递归划分仅去除一个元素,既是划分元素本身,而算法也演变为插入排序;

  • 优势:栈大小的最大值与㏒N成比例,但退化情况下增长到N成比例;此实现可以防止因为系统栈空间不足够线性耗用的时候,可以利用显示的堆栈替代;

  • 性质:算法不稳定,任何相等的元素有可能在交换的过程中被重排成不同的序列。快速排序中关键点是划分元素的选取。这个实现方式与上一个实现最大的差距就在于对等于划分元素值的处理上;

  • 时间:由于每一次都将较小子序列优先放入栈中,所以保证每一项都小于它下面一项的1/2,当排序N个元素时,可保证栈大小的最大值为㏒N;

样例:

 struct MyStack {
void push(int n);
int pop();
bool isEmpty();
}; void partition_5(int *array, int l, int r); void quickSort_5(int *array, int l, int r) {
/**
* 使用显示下推推展替代系统递归栈
* */
MyStack* stack=new MyStack();
/**
* 初始化堆栈
* */
stack->push(l);stack->push(r); int left, right, pivot;
while(!stack->isEmpty()) {
/**
* 从堆栈中获取序列段的端点
* */
right=stack->pop();left=stack->pop(); pivot=partition_5(array, left, right);
/**
* 如果当前序列段交叉,则跳过
* */
if(left>=right) continue;
/**
* 为了防止快速排序退化成线性处理,堆栈空间耗用
* 也为线性,此处首先处理较小的序列,也就是将较
* 长的子序列首先入栈,较小的子序列延后入栈;这样
* 可以优先处理最小子序列,从而防止退化成线性空间
* */
if((pivot-left)<(right-pivot)) {
stack->push(pivot+);stack->push(right);
stack->push(left);stack->push(pivot-);
} else {
stack->push(left);stack->push(pivot-);
stack->push(pivot+);stack->push(right);
}
}
} int main() {
int array[]={,,,,,};
quickSort_5(array,,);
for(int i=;i<;i++)
printf("%d,",array[i]);
return ;
}

议题:选择指定排序位置的元素(利用快速排序递归划分,求数值集合中第K小的元素)

分析:

  • 算法原理:为了获取序列中第K小的元素,一种办法是首先对序列进行排序,然后直接找到第k个元素,但是对于获取第K小的元素而言,全序列排序是不需要的; 所以通过使用快速划分来获得某一个划分值,有K-1个元素位于它的左边,则称这个划分元素为这个序列中第K小的值,这样的策略可以在接近线性的运算时间中 完成。与排序相关但又不需要完全进行排序的一个重要应用就是求一系列数值中排在第几位的值(第K小的值);

  • 基于快速排序的选择总体上为线性运行时间O(N)。使用Selection解决第K小问题,需要的时间与Nk成比例(也就是先寻找第一小,然后第二,直到第K小);

样例:

 int quickSelect_1(int *array, int l, int r, int k) {
/**
* 如果l和r交叉,则说明r-l+1小于k,没有第K小的元素
* 返回-1表示失败;
* */
if(l>r) return -;
/**
* 获取划分元素
* */
int pivot=partition(array, l, r);
/**
* 注意k的大小是针对序列的排序值
* 而l,r和pivot的大小是在array中的索引值,
* 所以k需要经过转化才能与pivot进行比较
* */
if(pivot>k+l-)
return quickSelect_1(array, l, pivot-, k);
else if(pivot<k+l-)
return quickSelect_1(array, pivot+, r, k-(pivot-l+));
else
return array[pivot];
} int quickSelect_2(int *array, int l, int r, int k) {
int ltemp=l, rtemp=r;
int pivot;
while(ltemp<rtemp) {
pivot=partition(array, ltemp, rtemp);
if(pivot>k+l-) {
rtemp=pivot-;
} else if(pivot<k+l-) {
ltemp=pivot+;
k=k-(pivot-l+);
} else
return array[pivot];
}
return -;
} int main() {
int array[]={,,,,,}; printf("%d\n",quickSelect_1(array,,,));
return ;
}

对快速排序算法的性能总结

  • 可以使用下面几种策略提升性能:随机选取划分元素,三元素中值确定划分元素,小子文件非递归排序;

  • 快速排序算法的性能取决于递归部分(㏒N)和划分部分(N),尽管快速排序中前面的操作会给后续的操作提供一定的排序信息从而加速后续的操作速度,但是性能仍然极大地取决于原序列的已排序程度;

  • 如果原始序列已经为正序序列,并且划分元素为数组中的最左值或最右值(实际情况中极有可能选择最右边的元素作为划分元素),这样的划分会使得极端不平等的划分,并且导致最终的性能接近于插入排序(N2);

  • 所以应该保证划分的均衡性,使用随机数组(可以将原始序列进行随机化)和随机选择划分元素(就像是上面几种实现那样)就能够在整体上保证划分的随机性,从而保证均衡划分,性能接近二分排序(N㏒N);

笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)的更多相关文章

  1. 前端如何应对笔试算法题?(用node编程)

    用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...

  2. 小小c#算法题 - 6 - 快速排序 (QuickSort)

    快速排序是排序算法中效率比较高的一种,也是面试常被问到的问题. 快速排序(Quick Sort)是对冒泡排序的一种改进.它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字 ...

  3. 笔试算法题(50):简介 - 广度优先 & 深度优先 & 最小生成树算法

    广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能 ...

  4. 笔试算法题(13):反转链表 & 左旋转字符串

    出题:反转链表(递归和非递归解法): 分析:有递归跟非递归实现,注意对原始链表头节点的处理,因为其他节点都指向下一个节点,其需要指向NULL: 解题: struct Node { int v; Nod ...

  5. 笔试算法题(52):简介 - KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm)

    议题:KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm) 分析: KMP算法用于在一个主串中找出特定的字符或者模式串.现在假设主串为长度n的数组T ...

  6. 笔试算法题(03):最小第K个数 & 判定BST后序序列

    出题:输入N个整数,要求输出其中最小的K个数: 分析: 快速排序和最小堆都可以解决最小(大)K个数的问题(时间复杂度为O(NlogN)):另外可以建立大小为K的最大堆,将前K个数不断插入最大堆,对于之 ...

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

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

  8. 笔试算法题(57):基于堆的优先级队列实现和性能分析(Priority Queue based on Heap)

    议题:基于堆的优先级队列(最大堆实现) 分析: 堆有序(Heap-Ordered):每个节点的键值大于等于该节点的所有孩子节点中的键值(如果有的话),而堆数据结构的所有节点都按照完全有序二叉树 排.当 ...

  9. php笔试算法题:顺时针打印矩阵坐标-蛇形算法

    这几天参加面试,本来笔试比较简单,但是在面试的时候,技术面试官说让我现场写一个算法,顺时针打印矩阵的坐标,如图所示 顺序为,0,1,2,3,4,9,14,19,24,23,22,21,20,15,10 ...

随机推荐

  1. NDK相关收藏【转】

    http://blog.csdn.net/column/details/anidea-ndk.html   [转] 作者:conowen@大钟

  2. 原生JavaScript之实战 模拟重力场(篮球)

    成品图如下所示: 点击篮球让篮球掉下 搭建HTML+CSS代码 html: <div id="demo"></div> css: div{ width:10 ...

  3. 版本管理工具SVN的使用

    一.安装服务器端和客户端 需要的软件: 1.服务器端:SlikSVN,下载传送门:http://www.sliksvn.com/en/download/ 2.客户端:“乌龟”,下载传送门:http:/ ...

  4. ElasticSearch | windows 上安装ES

    Elastatic需要java JAVA8 环境,确保安装好环境 在windows上安装ES还是比较简单的, 1.首先在官网上下载zip,地址 https://www.elastic.co/downl ...

  5. 《Windows核心编程系列》十一谈谈Windows线程池

    Windows线程池 上一篇博文我们介绍了IO完成端口.得知IO完成端口可以非常智能的分派线程.但是IO完成端口仅对等待它的线程进行分派,创建和销毁线程的工作仍然需要我们自己来做. 我们自己也可以创建 ...

  6. IE6 position:fixed bug hack方式

    /* IE6浏览器的特有方法 */ /* 修正IE6振动bug */ * html,* html body{background-image:url(about:blank);background-a ...

  7. Linux下VIM配置以及常用快捷键

    一.VIM配置 在目录 /etc/vim下面,有个名为vimrc的文件,这是系统中公共的vim设置文件,对所有用户都有效.而在每个用户的主目录下,都能自己建立私有的设置文件,命名为:“.vimrc”. ...

  8. Poj 3436 ACM Computer Factory (最大流)

    题目链接: Poj 3436 ACM Computer Factory 题目描述: n个工厂,每个工厂能把电脑s态转化为d态,每个电脑有p个部件,问整个工厂系统在每个小时内最多能加工多少台电脑? 解题 ...

  9. 题解报告:hdu 1408 盐水的故事

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1408 Problem Description 挂盐水的时候,如果滴起来有规律,先是滴一滴,停一下:然后 ...

  10. sdut2784&cf 126b Good Luck!(next数组)

    链接 next数组的巧妙应用  学弟出给学弟的学弟的题.. 求最长的 是前缀也是后缀同时也是中缀的串  next的数组求的就是最长的前后缀 但是却不能求得中缀 所以这里 就把尾部去掉之后再求 这样就可 ...