[二分法]线性时间内在数组中找出第k大的数

#include "stdafx.h"
#include "iostream"
using namespace std;
//参数为  数组指针,开始下标, 结束下标, 第K大数(k从0开始)
int rand_par(int array[], int start, int end, int th){
	if( start < 0 || end < 0 || th < 0 || end < start ){
		return -1;
	}
	int left = start;
	int right = end;
	int key = array[right];
	while( left < right ){
		while( left < right &&  array[left] <= key){ //找到左边第一个大于key的下标
			left++;
		}
		array[right] = array[left];

		while( left < right && array[right] >= key ){  //找到左边第一个小于key的下标
			right--;
		}
		array[left] = array[right];       //让他们交换
	}
	array[left] = key;
    //如果碰对了结果就返回,否则通过二分法,继续递归
	if( left == th ){
		return array[left];
	}else if( left > th ){
		return rand_par( array, start, left - 1 , th );
	}else{
		return rand_par( array, left + 1, end , th );
	}
	return 0;
}

int _tmain( void )
{
	int array[] = {432,13,61,6,425,132,422,4213,521};
        //测试数据,参数为数组 开始下标, 结束下标, 第K大数(k从0开始)
	int r1 = rand_par(array,0, 8, 0);
	int r2 = rand_par(array,0, 8, 1);
	int r3 = rand_par(array,0, 8, 8);
	int r4 = rand_par(array,0, 8, 5);
	cout<<r1<<endl;
	cout<<r2<<endl;
	cout<<r3<<endl;
	cout<<r4<<endl;
	return 0;
}

  算法导论里基础内容,算法基本上和快速排序没什么区别。今天学习不太认真,所以只能拿这个凑博文了。

   我想在

  int array[] = {432,13,61,6,425,132,422,4213,521};

    找到第K大的数。比如K=6.

   这里运用到了二分法的思想。每次计算都把范围减少一半。

数组开始下标为 start = 0

结束下标为 end = 8

     1. 取数组最后一项array[end]当作重要线索key,这key有特殊用途。

              432, 12, 61, 6, 425, 132, 422, 4213, 521 

下标 0     1    2    3   4     5     6        7     8

2. 通过排序,让所有大于key的移动到key的右边,小于key的移动到key的左边。key的下标因此会发生改动(不再是最后一项了,假设变成了m)。我们可以知道数组第m大的项是key

排序后成了这样   432, 12, 61, 6, 425, 132, 422, 521, 4213

下标 0     1    2    3   4     5     6       7     8       看图可知 m == 7 , array[m] == 521

   3.我们算出了第7大数...但并没有算出第K大数

       很明显, m> k

      这时候将数组分为两段:   432, 12, 61, 6, 425, 132, 422   和  521, 4213。

所求的第6大的数一定在前面这个数组里。因为左边的数都比521小。右边的数都会比521大。

   ---------------------------------------------------------------------------

start = 0

end  = 6

将这个数组进行排序:    432, 12, 61, 6, 425, 132, 422

                               下标    0    1   2    3   4     5        6

    排序后的结果是            12,  61, 6, 132, 422,432,425

                               下标    0    1   2    3     4     5     6

    得到了数组中第4大的元素是422。依然不是我们想得到的答案。

这时又可以把数组分为两部分。 12,  61, 6, 132, 422  和  432,425

    m < k,所以答案肯定在右边的数组找。

-------------------------------------------------------------------------------------

就这样一直计算下去,一定能碰到我们所求的第K大数。偷懒了, 最后答案是425

时间: 2024-10-01 06:23:38

[二分法]线性时间内在数组中找出第k大的数的相关文章

从数组中找出第K大的数

利用改进的快排方法 public class QucikFindMaxK { static void swap(int[] arr, int a, int b) { int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } // 升序排列,比arr[pivotIndex]值小的数都在arr[pivotIndex]左边,大的数都在右边 static int partition(int arr[], int left, int right, int p

笔试题--在一个整数数组中找出第5大的数

/** * 在一个整数数组中找出第5大的数 * 思路是首先在数组中找到最小数,然后依次找到第五大的数 * * @param array * @return */ public static int[] selectionSort(int[] array) { if (array.length == 0) return array; for (int i = 0; i < array.length; i++) { int minIndex = i; for (int j = i; j < arr

找出第k大的数

编程题#3:找出第k大的数 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 用户输入N和K,然后接着输入N个正整数(无序的),程序在不对N个整数排序的情况下,找出第K大的数.注意,第K大的数意味着从大到小排在第K位的数. 输入 N K a1 a2 a3 a4 ..... aN 输出 b 样例输入 5 2 32 3 12 5 89 样例输出 32 提示 这是一道很经典的算法问

【基础算法】排序-复杂排序之二(找出第K大的数)

切割的思想是高速排序最精髓的地方.每一次切割出来的元素K一个排在第K位,所以利用这样的思想我们至少知道3点 1. 被切割出来的元素K最后一定排在第K位. 2. 在K左边的元素一定比K小或者相等. 3. 在K右边的元素一定比K大或者相等. 所以我们能够通过这些性质定位到随意一个元素. 比方我们partition完一个数组后,得到A={5,3,4,2,6,8,10,12,11,9} A[K]=8,所以我们知道排好序后的A[5]=8, A[4]一定在8左边,A[6]一定在8右边 所以,我们一定知道8这

C语言 选择排序算法原理和实现 从数组中 找出最小的元素然后交换位置

#include <stdio.h> int main(void) { /* 选择排序算法 原理:从数组中 找出最小的元素然后交换位置: */ int a[10] = {9,5,10,7,2,3,1,6,8,4}; int i=0,j=0; int n = sizeof(a)/4; //外循环n-1轮 for(i=0;i<n-1;i++){ int pos = i;//始终指向最小的位置 for(j=i+1;j<n;j++){ if(a[j]<a[pos]){ pos = j

C语言:对传入sp的字符进行统计,三组两个相连字母“ea”&quot;ou&quot;&quot;iu&quot;出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。

//对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. 1 #include <stdio.h> 2 #include <string.h> 3 #pragma warning (disable:4996) 4 void fun(char*sp ,int *ct) 5 { 6 int a=0, b=0, c=0; 7 while (*sp != '\0') 8 { 9 if (*s

刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的题.去发现问题. 题目:     给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 解析: 实际这里就是给你的一个列表的数字,给你一个预期,让你返

[面试题]在数组中找出3个数使得它们和为0

给定一个数组S,试找出3个数a, b, c,使得a+b+c=0.也即从集合中找出所有的和为0的3个数. 例如:集合S={-1,0, 1, 2, -1, 4},则满足条件的3个数有2对:(-1, 0, 1)和(-1, 2, -1).注意(-1,1,0)与(-1,0,1)算同一个解,所以不用重复考虑. 当然该例子集合的解也可以写成:(0, 1, -1)和(2, -1, -1). 参考了:http://blog.csdn.net/wangran51/article/details/8858398,他给

数组中找出最小的K个数

题目 给出一个数组,找出K个最小的值 例如给出数组{5,2,4,3,1},给定K值3,则输出结果为{2,3,1} 程序 先给出第一个版本的程序 1 public static void printKNum(int[] source, int k) {//算法入口 2 if (k <= 0) { 3 System.out.println("请出入合法的K值"); 4 } else if (source.length <= k) {//如果数组的长度小于等于K,则全部输出 5