笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)
议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小)
分析:
算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法;使用显示下推栈存储快速排序中的每一次划分结果 (将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)的更多相关文章
- 前端如何应对笔试算法题?(用node编程)
用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...
- 小小c#算法题 - 6 - 快速排序 (QuickSort)
快速排序是排序算法中效率比较高的一种,也是面试常被问到的问题. 快速排序(Quick Sort)是对冒泡排序的一种改进.它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字 ...
- 笔试算法题(50):简介 - 广度优先 & 深度优先 & 最小生成树算法
广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能 ...
- 笔试算法题(13):反转链表 & 左旋转字符串
出题:反转链表(递归和非递归解法): 分析:有递归跟非递归实现,注意对原始链表头节点的处理,因为其他节点都指向下一个节点,其需要指向NULL: 解题: struct Node { int v; Nod ...
- 笔试算法题(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 ...
- 笔试算法题(03):最小第K个数 & 判定BST后序序列
出题:输入N个整数,要求输出其中最小的K个数: 分析: 快速排序和最小堆都可以解决最小(大)K个数的问题(时间复杂度为O(NlogN)):另外可以建立大小为K的最大堆,将前K个数不断插入最大堆,对于之 ...
- 笔试算法题(54):快速排序实现之单向扫描、双向扫描(single-direction scanning, bidirectional scanning of Quick Sort)
议题:快速排序实现之一(单向遍历) 分析: 算法原理:主要由两部分组成,一部分是递归部分QuickSort,它将调用partition进行划分,并取得划分元素P,然后分别对P之前的部分和P 之后的部分 ...
- 笔试算法题(57):基于堆的优先级队列实现和性能分析(Priority Queue based on Heap)
议题:基于堆的优先级队列(最大堆实现) 分析: 堆有序(Heap-Ordered):每个节点的键值大于等于该节点的所有孩子节点中的键值(如果有的话),而堆数据结构的所有节点都按照完全有序二叉树 排.当 ...
- php笔试算法题:顺时针打印矩阵坐标-蛇形算法
这几天参加面试,本来笔试比较简单,但是在面试的时候,技术面试官说让我现场写一个算法,顺时针打印矩阵的坐标,如图所示 顺序为,0,1,2,3,4,9,14,19,24,23,22,21,20,15,10 ...
随机推荐
- webpack 4.0 相关
Webpack 4.0发布了!! https://www.jianshu.com/p/3a13f1b37300 webpack详解 https://juejin.im/post/5aa3d2056fb ...
- HDU1072:Nightmare
传送门 题意 给出一张n*m的图 0.墙 1.可走之路 2.起始点 3.终点 4.时间重置点 问是否能到达终点 分析 我的训练专题第一题,一开始我设个vis数组记录,然后写炸,不能处理重置点根vis的 ...
- bzoj 3470: Freda’s Walk【拓扑排序+期望dp】
dfs会T,只好正反两遍拓扑了-- #include<iostream> #include<cstdio> #include<queue> #include< ...
- bzoj P1979 华容道【bfs+spfa】
调死我了-- 首先观察移动方式,需要移动的格子每次移动到相邻格子,一定是先把空白格子挪过去,所以我们得到一种做法,就是bfs预处理出每一个格子的四联通格子之间的空白格子移动距离建边,注意这个移动是不能 ...
- bzoj 3052: [wc2013]糖果公园【树上带修改莫队】
参考:http://blog.csdn.net/lych_cys/article/details/50845832 把树变成dfs括号序的形式,注意这个是不包含lca的(除非lca是两点中的一个) 然 ...
- ES6 我的总结学习
1 let 和 const let 的作用域与 const 命令相同:只在声明所在的块级作用域内有效.且不存在变量提升 . 1.1 let let 所声明的变量,可以改变. let a = 123 a ...
- JS 自写datapage.js 通用分页
var Page = function () { }; Page.prototype = { Loading: "<img src='/Content/Scripts/Data ...
- Allure对单测结果以及robotframework结果的处理
Allure对单测结果以及robotframework结果的处理 Allure只能针对pytest的单测结果生成相应的报告: 如果需要对unittest的测试框架结果进行展示,可以使用pytest执行 ...
- python包管理工具他们之间的关系
python包管理工具之间的关系 现在的python包管理工具有很多,非常混乱,必须理清他们之间的关系才能更好的使用python构建强大的包关系系统工具. 首先:python官方推荐的第三方库是PyP ...
- [UOJ386]鸽子固定器
题解 堆+贪心 题意就是给你\(n\)个物品,让你最多选\(m\)个 每个物品有两个属性\(a_i,b_i\) 最大化\((\sum_{a_i})^{dv}+(max(b_i)-min(b_i))^{ ...