求无需数组第K小的数及其位置

原创 2012年03月26日 10:07:27
#include "stdafx.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>


void swap(int & a, int & b);
int find_position(int* a,int k, int low,int high);
int find_orderk(int* a, int k, int low,int high);

int MAXCOUNT = 10;

void swap(int & a, int & b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

int get_position(int* a, int count,int value)
{
    int pos = -1;
    for ( int i = 0; i < count ; i++ )
    {
        if ( a[i] == value )
        {
            pos = i;
        }
    }
    return pos;
}

void print_array(int* a, int count)
{
    for ( int i = 0; i < count ; i++ )
    {
        if(i%10 == 0)
            printf("\n");
        printf("%d\t", a[i]);
    }
}

//随机选取数组指定范围内的一个数Value,
//把指定范围内的数以Value为分界点,左边部分大于等于Value,右边部分小于Value
//返回所选数值所在的位置
// a[low]... a[m]...a[hight]
//             ^
//  > value  value  < value
//             ^
//             p
int find_position(int* a, int low,int hight)
{
    //只有一个元素直接返回
    if (low >= hight)
    {
        return low;
    }
    
    //随机选取low与hight之间的一个数作为基准
    int m = rand() % (hight - low) + low;
    int value =  a[m];      //选取元素的值
    int p = m;              //选取元素的索引
    
    int lowpos = low;       //第一个小于Value的元素索引
    int hightpos = hight;   //最后一个大于Value的元素索引
    bool bfindl = false;    //是否存在小于Value的元素
    bool bfindh = false;    //是否存在大于Value的元素
    
    for (int i = low; i <= hight; i++)
    {        
        if(a[i] >= value && i != m)
        {
            bfindh = true; //存在大于Value的元素
            if(bfindl)
            {
                //与第一个小于Value的元素交换
                hightpos = lowpos;
                swap(a[lowpos++], a[i]);
                //跳过索引m的位置
                if (lowpos == m)
                {
                    lowpos++;
                }
            }
            else
            {
                hightpos = i;
            }
        }
        //第一个小于Value的索引
        else if( a[i] < value && !bfindl)
        {
            lowpos = i;
            bfindl = true;
        }
    }
    
    //存在大于Value的元素,并且最后一个大于Value的元素在m之后,需要交换
    if(bfindh && hightpos > m)
    {
        swap(a[p], a[hightpos]);
        p = hightpos;
    }
    
    //存在小于Value的元素,并且第一个小于Value的元素在m之前,需要交换
    if(bfindl && lowpos < m)
    {
        swap(a[p], a[lowpos]);
        p = lowpos;
    }

    return p;
}

//随机选取数组指定范围内的一个数Value,
//把指定范围内的数以Value为分界点,左边部分大于等于Value,右边部分小于Value
//返回所选数值所在的位置
// a[low]... a[m]...a[hight]
//             ^
//  > value  value  < value
//             ^
//             p
int find_position_h(int* a, int low,int hight)
{
    //只有一个元素直接返回
    if (low >= hight)
    {
        return low;
    }
    
    //随机选取low与hight之间的一个数作为基准
    int m = rand() % (hight - low) + low;
    int value =  a[m];      //选取元素的值
    int p = m;              //选取元素的索引
    
    int lowpos = low;       //第一个小于Value的元素索引
    int hightpos = hight;   //最后一个大于Value的元素索引
    bool bfindl = false;    //是否存在小于Value的元素
    bool bfindh = false;    //是否存在大于Value的元素
    
    for (int i = low; i <= hight; i++)
    {        
        if(a[i] >= value && i != m)
        {
            bfindh = true; //存在大于Value的元素
            if(bfindl)
            {
                //与第一个小于Value的元素交换
                hightpos = lowpos;
                swap(a[lowpos++], a[i]);
                
                //跳过索引m的位置
                if (lowpos == m)
                {
                    lowpos++;
                }
            }
            else
            {
                hightpos = i;
            }
        }
        //第一个小于Value的索引
        else if( a[i] < value && !bfindl)
        {
            lowpos = i;
            bfindl = true;
        }
    }
    
    //存在大于Value的元素,并且最后一个大于Value的元素在m之后,需要交换
    if(bfindh && hightpos > m)
    {
        swap(a[p], a[hightpos]);
        p = hightpos;
    }
    
    //存在小于Value的元素,并且第一个小于Value的元素在m之前,需要交换
    if(bfindl && lowpos < m)
    {
        swap(a[p], a[lowpos]);
        p = lowpos;
    }

    return p;
}

//随机选取数组指定范围内的一个数Value,
//把指定范围内的数以Value为分界点,左边部分大于等于Value,右边部分小于Value
//返回所选数值所在的位置
// a[low]... a[m]...a[hight]
//             ^
//  < value  value  > value
//             ^
//             p
int find_position_l(int* a, int low,int hight)
{
    //只有一个元素直接返回
    if (low >= hight)
    {
        return low;
    }
    
    //随机选取low与hight之间的一个数作为基准
    int m = rand() % (hight - low) + low;
    int value =  a[m];      //选取元素的值
    int p = m;              //选取元素的索引
    
    int hightpos = low;       //第一个大于Value的元素索引
    int lowpos = hight;   //最后一个小于Value的元素索引
    bool bfindl = false;    //是否存在小于Value的元素
    bool bfindh = false;    //是否存在大于Value的元素
    
    for (int i = low; i <= hight; i++)
    {        
        if(a[i] <= value && i != m)
        {
            bfindl = true; //存在小于Value的元素
            if(bfindh)
            {
                //与第一个大于Value的元素交换
                lowpos = hightpos;
                swap(a[hightpos++], a[i]);
                print_array(a, MAXCOUNT);
                //跳过索引m的位置
                if (hightpos == m)
                {
                    hightpos++;
                }
            }
            else
            {
                lowpos = i;
            }
        }
        //第一个大于Value的索引
        else if( a[i] > value && !bfindh)
        {
            hightpos = i;
            bfindh = true;
        }
    }
    

    //存在大于Value的元素,并且第一个大于Value的元素在m之前,需要交换
    if(bfindh && hightpos < m)
    {
        swap(a[p], a[hightpos]);
        print_array(a, MAXCOUNT);
        p = hightpos;
    }

        //存在小于Value的元素,并且最后一个小于Value的元素在m之后,需要交换
    if(bfindl && lowpos > m)
    {
        swap(a[p], a[lowpos]);
        print_array(a, MAXCOUNT);
        p = lowpos;
    }
    

    return p;
}

//获得数组指定范围【low,height】内第K大的数所在的位置
int find_orderk(int* a, int k, int low,int hight)
{
    //获得一个low与hight之间的一个位置p,使得a[low...p] >= a[p], a[p+1, hight] < a[p]
    int p = find_position(a, low, hight);
    
    //p与low索引之间的元素个数小于K
    if(p-low < k-1)
    {
        //获得数组指定范围【p+1,height】内第【(k-1)-(p-low)】大的数所在的位置
        p = find_orderk(a, (k-1)-(p-low), p+1, hight);
    }
    //p与low索引之间的元素个数大于K
    else if (p-low > k-1)
    {
        //获得数组指定范围【low,p-1】内第【k】大的数所在的位置
        p = find_orderk(a, k, low, p-1);
    }

    return p;
}

//获得数组指定范围【low,height】内第K大的数所在的位置
int find_orderk_h(int* a, int k, int low,int hight)
{
    //获得一个low与hight之间的一个位置p,使得a[low...p] >= a[p], a[p+1, hight] < a[p]
    int p = find_position_h(a, low, hight);
    
    //p与low索引之间的元素个数小于K
    if(p-low < k-1)
    {
        //获得数组指定范围【p+1,height】内第【(k-1)-(p-low)】大的数所在的位置
        p = find_orderk(a, (k-1)-(p-low), p+1, hight);
    }
    //p与low索引之间的元素个数大于K
    else if (p-low > k-1)
    {
        //获得数组指定范围【low,p-1】内第【k】大的数所在的位置
        p = find_orderk(a, k, low, p-1);
    }

    return p;
}

//获得数组指定范围【low,height】内第K小的数所在的位置
int find_orderk_l(int* a, int k, int low,int hight)
{
    //获得一个low与hight之间的一个位置p,使得a[low...p] <= a[p], a[p+1, hight] > a[p]
    int p = find_position_l(a, low, hight);
    
    //p与low索引之间的元素个数小于K
    if(p-low < k-1)
    {
        //获得数组指定范围【p+1,height】内第【(k-1)-(p-low)】大的数所在的位置
        p = find_orderk_l(a, (k-1)-(p-low), p+1, hight);
    }
    //p与low索引之间的元素个数大于K
    else if (p-low > k-1)
    {
        //获得数组指定范围【low,p-1】内第【k】大的数所在的位置
        p = find_orderk_l(a, k, low, p-1);
    }

    return p;
}

int main ()  
{
    srand((unsigned) time(NULL));
    
    //初始化数组
    int srcArray[100];
    int keyArray[100];
    
    int n;
    do
    {
        printf("\n初始化数组,请输入数组元素个数(1-100):");
        scanf("%d", &n);
        
    }while ( n > 100 || n <= 0);
    MAXCOUNT = n;
    int i = 0;
    while(i < n)
    {
        srcArray[i] = rand()%100;
        keyArray[i]=srcArray[i];
        i++;
    }
    
    //输出数组元素
    print_array(srcArray, n);
    
    //获得参数
    do
    {
        int k = 1;
        do
        {
            printf("\n请输入数值(1-%d):", n);
            scanf("%d", &k);
        }while ( k > n || k <= 0);
        
        //获得第K大元素位置
        int newpos = find_orderk_h(srcArray, k, 0, n-1);
        int value = srcArray[newpos];
        int srcpos = get_position(keyArray, n, value);
        printf("\n 数组中第 %d 大的数值: %d 位置: %d \n", k, value, srcpos);

        system("PAUSE");
        memcpy(srcArray, keyArray, sizeof(srcArray));

        //获得第n - k + 1小元素位置
        int no = n - k + 1;
        int newpos2 = find_orderk_l(srcArray, no, 0, n-1);
        print_array(srcArray, n);
        int value2 = srcArray[newpos2];
        int srcpos2 = get_position(keyArray, n, value2);
        printf("\n 数组中第 %d 小的数值: %d 位置: %d \n", no , value2, srcpos2);

        system("PAUSE");
        memcpy(srcArray, keyArray, sizeof(srcArray));

    }while ( true );
 
    return 0;
}





在O(n)时间内查找数组内第k小的数

前一阵子做作业,看到了这个,要求在 O(n) 时间内查找前 k 小的 k 个数,给出的提示是,先在 O(n) 时间内查找到第 k 小的数.由此想到,此前一直用的 sort 函数,排完序后找下标为 k-...
  • pku_Coder
  • pku_Coder
  • 2016年12月01日 13:02
  • 309

写一段程序,找出数组中第k大小的数,输出数所在的位置。

基本上是利用排序思想,稍微改造以适应这种需求。比如最简单的冒泡排序,冒泡到第k次时就找到了这个数(需要提前缓存原始索引位置);快速排序的思想,把数组分割成大于和小于某值的两部分后,判断每部分的元素个数...
  • qiaoquan3
  • qiaoquan3
  • 2016年05月17日 15:18
  • 989

无序数组中找到第K小的数(或者找到最小的K个数)

题目:在一个很大的无序数组中用最快的速度找到第K小的数(或者找到最小的前K个数)。(类似于,在一个有1000000个数的数组中找到最小的100个数)对于这个问题首先想到的可能是把这个数组进行按从小到大...
  • wangbingcsu
  • wangbingcsu
  • 2016年04月25日 12:15
  • 3483

寻找第K小的数

前言 寻找第K小的数属于顺序统计学范畴,通常我们可以直接在O(NlgN)的时间内找到第K小的数,使用归并排序或者堆排序对输入数据按从小到大进行排序,然后选择第K个即可。然而,我们还有更好的算法。...
  • a15994269853
  • a15994269853
  • 2014年03月19日 21:34
  • 2649

利用快排思想寻找数组中第K大(小)的数字

利用快排的思想寻找数组中第K大(小)的数字。举例:给定一个整数数组num,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。如输入数组[1,3,5,2,2],5,3,返回...
  • u012050154
  • u012050154
  • 2016年11月17日 09:59
  • 872

用快速排序的思想求第K大的数或最大的k个数

#include    using namespace std;   template class T>   int quick2_sort(T a[],int low,int high)   ...
  • guangwen_lv
  • guangwen_lv
  • 2014年09月29日 19:26
  • 2166

经典算法题:无序整数数组中找第k大的数

经典问题:写一段程序,找出数组中第k大的数,输出数所在的位置。 【解法一】先排序,然后输出第k个位置上的数 我们先假设元素的数量不大,例如在几千个左右,在这种情况下,那我们就排序一下吧。在这里,快速...
  • wangbaochu
  • wangbaochu
  • 2016年10月27日 21:02
  • 4100

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

题目描述: 给定一个无序整数数组,返回这个数组中第k小的数。 解析: 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(...
  • tham_
  • tham_
  • 2015年03月29日 14:34
  • 2069

求数组中第K大的数

使用快排,第一趟快排过后,右边的元素都比枢轴大,左边的都比枢轴小。当我们要求第K大的数,只需要左边的元素个数是len-k,len是数组总长度。 第一次快排下来,设枢轴位置是mid,如果mid>k,说...
  • liang0000zai
  • liang0000zai
  • 2015年06月25日 15:52
  • 837

面试题-找出数组中第k大小的数,输出数所在的位置

这个是我碰到的一个面试题。 因为我C++用得比较
  • yan532200
  • yan532200
  • 2014年11月16日 22:16
  • 1141
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:求无需数组第K小的数及其位置
举报原因:
原因补充:

(最多只允许输入30个字)