顺序统计:寻找序列中第k小的数

最直观的解法,排序之后取下标为k的值即可。

但是此处采取的方法为类似快速排序分块的方法,利用一个支点将序列分为两个子序列(支点左边的值小于支点的值,支点右边大于等于支点的值)。

如果支点下标等于k,则支点就是查找的值,如果支点的下标大于k,则在左子序列里继续寻找,如果支点下标小于k,则继续在支点右子序列里面继续寻找第(k-支点下标)小的值。

c#实现算法如下:


 public class FindSpecialOrderElement<T> where T : IComparable<T>
{
public T FindElementWithOrder(T[] array, int startIndex, int endIndex, int order)
{
int pivot = Partition(array, startIndex, endIndex);
//pivot支点为第(pivot-startIndex+1)小的值
int pivotOrder = pivot - startIndex + 1;
if (pivotOrder == order)
{ return array[pivot]; }
else if (pivotOrder > order)
{
return FindElementWithOrder(array, startIndex, pivot - 1, order);
}
else//pivotOrder < order
{
return FindElementWithOrder(array, pivot + 1, endIndex, order - pivotOrder);
}
}
public static int Partition(T[] array, int leftIndex, int rightIndex)
{
//leftIndex的位置空出来了
T pivotValue = array[leftIndex];
//将所有<pivotValue的值移动到pivotValue的左边(不稳定排序,因为相等值得相对位置可能被此步骤改变)
//将所有>=pivotValue的值移到右边
//移动的结果就是所有<pivotValue的值都在pivotValue的左边,>=它的都在右边
//记录之后pivotValue所在位置,返回该位置,完成一次分区划分。
while (leftIndex < rightIndex)
{
//因为是leftIndex先空出来位置,所以第一步要从右侧rightIndex向左寻找小于pivotValue的数值位置
while (leftIndex < rightIndex && array[rightIndex].CompareTo(pivotValue) >= 0) rightIndex--;
//将找到的小于pivotValue的位置的元素放到空出的leftIndex位置,leftIndex++
if (leftIndex < rightIndex) array[leftIndex++] = array[rightIndex];
//leftIndex向右寻找>=pivotValue的值的位置
while (leftIndex < rightIndex && array[leftIndex].CompareTo(pivotValue) < 0) leftIndex++;
//将找到的>=pivotValue的位置的leftIndex元素放到上一步空出的rightIndex位置
//此时leftIndex所在位置变成待插入位置,重新回到外圈循坏的初始状态
if (leftIndex < rightIndex) array[rightIndex--] = array[leftIndex];
}
//最后while循环结束的位置就是leftIndex==rightIndex,并且这个位置是空出来的,正好把pivotValue放到这个位置
//这就是轴的概念,轴两边的值时由轴正好分开的,一边小于轴,一边大于等于轴
array[leftIndex] = pivotValue;
return leftIndex;
}

}

方法调用方法:


 static void Main(string[] args)
{
FindSpecialOrderElement<int> ESOE = new FindSpecialOrderElement<int>();
int[] data1 = new int[10] { 1, 2, 3, 20, 5, 6, 7, 8, 9, 10 };
Console.WriteLine();
data1.ToList<int>().ForEach(i => Console.Write("{0},", i));
int e = ESOE.FindElementWithOrder(data1, 0, data1.Length - 1, 4);
Console.WriteLine("Find the 4th small element:{0}", e);

int[] data2 = new int[10] { 6, 90, 8, 9, 10, 1, 2, 3, 4, 5 };
Console.WriteLine();
data2.ToList<int>().ForEach(i => Console.Write("{0},", i));
int f = ESOE.FindElementWithOrder(data2, 0, data1.Length - 1, 7);
Console.WriteLine("Find the 7th small element:{0}", f);
Console.ReadKey();
}

作者:Andy Zeng

欢迎任何形式的转载,但请务必注明出处。

http://www.cnblogs.com/andyzeng/p/3695478.html

顺序统计:寻找序列中第k小的数,布布扣,bubuko.com

时间: 2024-10-12 07:29:28

顺序统计:寻找序列中第k小的数的相关文章

查找序列中第K小的数与快速排序

#include <algorithm>#include <iostream> int Partition(int X[], int left, int right){ int pivot = X[left]; int L = left; int R = right; while(L < R) { while(X[L] <= pivot && L < right) { ++L; } while(X[R] > pivot &&

[经典算法题]寻找数组中第K大的数的方法总结

[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据中查找到第k个大的值. 名称是:设计一组N个数,确定其中第k个最大值,这是一个选择问题,当然,解决这个问题的方法很多,本人在网上搜索了一番,查找到以下的方式,决定很好,推荐给大家. 所谓"第(前)k大数问题"指的是在长度为n(n>=k)的乱序数组中S找出从大到小顺序的第(前)k个数的问题.

选择问题(选择数组中第K小的数)

由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小的时间复杂度返回正确结果. 代码如下: #include<iostream> using namespace std; #define Cutoff 3 int A[13] = {81,94,11,96,12,35,17,95,28,58,41,75,15}; void Swap(int &

求数组中第k小的数,有快速排序的验证

// The_Least_K_number.cpp : 定义控制台应用程序的入口点. //数组中第k小的数,例如a[1000]中第250小的数// #include "stdafx.h" #include <iostream> using namespace std; void swap(int *p, int *q) { int temp = *p; *p = *q; *q = temp; } int patition(int a[], int first, int la

算法导论:快速找出无序数组中第k小的数

题目描述: 给定一个无序整数数组,返回这个数组中第k小的数. 解析: 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1).使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n). 在<算法导论>有详细叙述 这里主要用C++实现,实现思路就是先选取当前数组的第一个数作为"主轴",将后面所有数字分成两部分,前面一部分小于"主轴",后面一部

寻找数列中第K大的数

版权所有 未经允许 请勿擅自商用 转载请指明出处 最早看到这个问题是在那本Mark写的数据结构与算法分析的书中引论部分,当时就是瞅瞅,到了最近,在实际应用中,我需要查找一些列的数中第k大的数时,我才重新回顾品味这个问题.现在,实际问题中,我还暂时没有解决问题,但是这段思考过程很有意思,在这里给大家品味下. 具体的问题有点复杂,在这里就不赘述了,暂且将这个问题形式化的描述如下: 给定一个有限无序数列记做{an},从这个数列中找出第k大的数. 输入:数列{an},k 输出:第k大的数 首先,有个最简

寻找数列中第k大的数算法分析

问题描述:给定一系列数{a1,a2,...,an},这些数无序的,现在求第k大的数. 看到这个问题,首先想到的是先排序,然后直接输出第k大的数,于是得到啦基于排序的算法 算法一: #include<iostream>#include<algorithm>using namespace std;bool cmp(int a, int b){ return a > b; }int main(){ int k; int a[9] = { 6, 5, 9, 8, 2, 1, 7, 3

最快效率求出乱序数组中第k小的数

题目:以尽量高的效率求出一个乱序数组中按数值顺序的第k 的元素值 思路:这里很容易想到直接排序然后顺序查找,可以使用效率较高的快排,但是它的时间复杂度是O(nlgn),我们这里可以用一种简便的方法,不一定需要排序,使用快速排序中双向分区的扫描方法,扫描出主元下标,然后根据主元的值将数组划分成一半大,一半小.然后再根据主元下标与k进行比较,如果相等,说明主元就是我们要找的数,如果大于k,说明k所代表的值在小的那边,继续向小的那部分递归,如果小于k,说明k代表的值在大的那边,继续向大的那部分递归.这

快排思想求给定序列中第k大的数

思想:快排的思想就是每排一次,就会把一个数(也就是我们选定的那个key)放到它在这个序列中正确的位置,所以每排一次就返回这个数所在下标看它是不是我们所要找的那个数(对应下面代码的ret是否等于size-k) #include <iostream> #include <vector> int QuockSort(int* array, int size, int k,std::vector<int>& vtmparr) { int first = 0; int l