2.4 选择第k大的元素 selection
1.目标:找到N个元素中,第k大的数。
例如:max是k=N--1;min是k=0;median是k=N/2
2.Quick-select 借鉴了快速排序的思想
(1)利用partition保证:
①a[j] is in place
②左边的元素不大于a[j],右边的元素不小于a[j]
(2)在其中一个子数组中重复划分,当j=k时结束

3.实现
package com.cx.sort;
public class QuickSelect {
public static Comparable select(Comparable[] a,int k) {
//打乱数组,避免出现最坏情况,平方时间
Shuffling.sort(a);
int lo=0,hi=a.length-1;
while(hi>lo) {
//j in place
int j=partition(a, lo, hi);
//如果j<k,只需要重新划分右边的数组
if(j<k) lo=j+1;
//如果j>k,只需要重新划分左边的数组
else if(j>k) hi=j-1;
else return a[k];
}
return a[k];
}
//划分,使得j左边的数不大于a[j],j右边的数不小于a[j]
private static int partition(Comparable[] a,int lo,int hi) {
int i=lo,j=hi+1;
//1.repeat
while(true) {
//1)循环i,直到大于a[lo]
while(less(a[++i], a[lo]))
//不可少,防止出现dcba时,i越界
if(i==hi) break;
//2)循环j,直到小于a[lo]
while(less(a[lo], a[--j]))
if(j==lo) break;
//3)判断是否交叉
if(i>=j) break;
exch(a, i, j);
}
//2.交叉后,交换lo,j
exch(a, lo , j);
//j in place
return j;
}
private static boolean less(Comparable v,Comparable w) {
return v.compareTo(w)<0;
}
private static void exch(Comparable[] a,int i ,int j ) {
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}
private static void show(Comparable[] a) {
for(int i=0;i<a.length;i++) {
System.out.print(a[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
String a[]= {"s","o","r","t","e","x","a","m","p","l","e"};
show(a);
//第几大的数(k=0..N-1)
int k=3;
System.out.println("第"+k+"大的数是:"+select(a, k));
}
}
package com.cx.sort;
public class Shuffling {
public static void sort(Comparable[] a) {
int N=a.length;
for(int i=1;i<N;i++) {
//第i次迭代,随机找r,r是0-r的随机数
int r=(int)(Math.random()*(i+1));
exch(a, i, r);
}
}
private static boolean less(Comparable v,Comparable w) {
return v.compareTo(w)<0;
}
private static void exch(Comparable[] a,int i ,int j ) {
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}
private static void show(Comparable[] a) {
for(int i=0;i<a.length;i++) {
System.out.print(a[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
String a[]= {"s","o","r","t","e","x","a","m","p","l","e"};
show(a);
sort(a);
show(a);
}
}
4.说明:
(1)quick-select:平均花费线性时间,最差的情况是~1/2N2
最差的情况发生在正序或倒序的时候,但是第一步的shuffling可以有效的避免这种情况。
线性时间可以简单的N+1/2N+1/4N+..=~2N
(2)常系数还是相对大了,还需要继续改进算法。
2.4 选择第k大的元素 selection的更多相关文章
- 寻找数组中的第K大的元素,多种解法以及分析
遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因 ...
- LeetCode703 流中第k大的元素
前言: 我们已经介绍了二叉搜索树的相关特性,以及如何在二叉搜索树中实现一些基本操作,比如搜索.插入和删除.熟悉了这些基本概念之后,相信你已经能够成功运用它们来解决二叉搜索树问题. 二叉搜索树的有优点是 ...
- [LeetCode] Kth Largest Element in a Stream 数据流中的第K大的元素
Design a class to find the kth largest element in a stream. Note that it is the kth largest element ...
- 输出数组第k大的元素
用快速排序的思想输出数组第k大的元素: #include<iostream> #include<algorithm> using namespace std; //递归实现:返 ...
- 获取一个数组里面第K大的元素
如何在O(n)内获取一个数组比如{9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20}里面第K大的元素呢? 我 ...
- POJ 2985 Treap平衡树(求第k大的元素)
这题也能够用树状数组做,并且树状数组姿势更加优美.代码更加少,只是这个Treap树就是求第K大元素的专家--所以速度比較快. 这个也是从那本红书上拿的模板--自己找了资料百度了好久,才理解这个Trea ...
- 力扣:丑数II和数组中前K大的元素
数组中的第K个元素 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k ...
- [leetcode]215. Kth Largest Element in an Array 数组中第k大的元素
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...
- 215. Kth Largest Element in an Array【Medium】【找到第 k 大的元素】
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...
随机推荐
- 【LeetCode】297. Serialize and Deserialize Binary Tree
二叉树的序列化与反序列化. 如果使用string作为媒介来存储,传递序列化结果的话,会给反序列话带来很多不方便. 这里学会了使用 sstream 中的 输入流'istringstream' 和 输出流 ...
- bootstrap框架栅格系统使用
使用的前端框架 bootstrap框架 Bootstrap是一个响应式的框架 我们在使用的时候主要使用的是它的网格系统, 1.bootstrap布局 布局容器:.container(用于固定宽度并支 ...
- CF919D Substring
思路: 拓扑排序过程中dp.若图有环,返回-1. 实现: #include <bits/stdc++.h> using namespace std; ; vector<int> ...
- 【译】x86程序员手册36-9.9异常汇总
9.9 Exception Summary 异常汇总 Table 9-6 summarizes the exceptions recognized by the 386. Table 9-6. Exc ...
- myslq 5.7 root 默认密码
sudo sumysqld_safe --skip-grant-tables --skip-networking & UPDATE mysql.user SET password=PASSWO ...
- PHP常量和数据类型考察点
PHP 常量 常量是单个值的标识符(名称).在脚本中无法改变该值. 有效的常量名以字符或下划线开头(常量名称前面没有 $ 符号). 注释:与变量不同,常量贯穿整个脚本是自动全局的. PHP常量的两种定 ...
- .Net Core 真能令微软的.Net 跨平台“蔓延”?
什么是.Net .Net 本身就是基于公共语言基础架构(CLI)实现的平台独立的公共语言开发平台,只是自2006年成为规范以来的CLI,只有Windows自己支持罢了(mono除外).微软的.Net ...
- C++学习随笔
今天试着变了下实验二里边的有关面向对象的实验,深深地觉得我对面向对象的编程的理解还是很浅显,以至于对于对象的调用也是瞎整.居然直接就去调用继承来的函数,连生成一个对象这种基础应用都不知道.对自己的基础 ...
- Beta冲刺提交-星期三
- 这个作业属于哪个课程 <https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1> 这个作业要求在哪里 <htt ...
- Shell书籍推荐
1.鸟哥私房菜 2.<Linux命令行与shell脚本编程大全> 第二本书买了,对于初学者来说一般.