找到数组中的第n个最小元素而不进行排序?

时间:2009-06-28 12:09:07

标签: c

我想编写一个程序来查找第n个最小的元素,而不使用任何排序技术。

我们可以递归地进行,分割和征服风格,如快速排序吗?

如果没有,怎么样?

7 个答案:

答案 0 :(得分:12)

您可以在此处找到有关该问题的信息:Selection algorithm

答案 1 :(得分:9)

您所指的是选择算法,如前所述。具体来说,您对quicksort的引用表明您正在考虑partition based selection

以下是它的工作原理:

  • 就像在Quicksort中一样,你先选择一个好东西 枢纽:你认为差不多的东西 在你的清单中间。那么你 浏览整个项目列表 交换东西直到 所有项目都少于你的支点 在列表的开头,和 所有比你的支点更重要的事情 在最后。你的枢轴进入中间的剩余点。
  • 通常在快速排序中你会递归 在枢轴的两侧,但为 你只会选择算法 在包含的那一侧递归 你感兴趣的索引。所以,如果 你想找到第三低的 价值,在任何一方递减 包含索引2(因为索引0是 第一个最低值)。
  • 你可以停止递归 将该地区缩小到一个地区 指数。最后,你会有一个 未列出的“m-1”最小的列表 对象,以及“n-m”最大的另一个未排序列表 对象。 “m”对象将位于中间。

此算法也适用于查找最高m个元素的排序列表...只需选择第m个最大元素,然后对其上方的列表进行排序。或者,对于速度稍快的算法,请使用Quicksort算法,但拒绝递归到与要查找排序值的区域不重叠的区域。

关于这一点非常巧妙的是它通常在O(n)时间内运行。第一次,它看到整个列表。在第一次递归时,它看到大约一半,然后是四分之一等等。因此,它查看大约2n个元素,因此它在O(n)时间内运行。不幸的是,就像在quicksort中一样,如果你一直选择一个不好的支点,你将在O(n 2 )时间内运行。

答案 2 :(得分:1)

使用heap structure(具体来说,priority queue基于Fibonacci heap,此任务很可能在大约O(n)时间内完成(n是列表的长度) {{3}}),O(1)插入时间和O(log n)删除时间。

考虑从列表中检索第m个最小元素的任务。通过简单地循环遍历列表并将每个项目添加到优先级队列(大小为m),您可以在O(n)时间内有效地创建列表中每个项目的队列(或者可能更少使用一些优化,虽然我不确定这是非常有帮助的)。然后,删除队列中具有最低优先级的元素(最高优先级是最小项目)是一件简单的事情,总共只需要O(log m)个时间,然后就完成了。

总的来说,算法的时间复杂度为O(n + log n),但由于log n << n(即n的增长速度比log n快得多),因此简化为简单O(n)。在一般情况下,我认为你不会得到比这更有效的东西。

答案 3 :(得分:1)

如果你不想使用斐波那契堆,你可以使用二进制堆。

ALGO:

  1. 从数组构造最小二进制堆,此操作将花费O(n)时间。

  2. 由于这是一个最小二进制堆,因此根元素是最小值。

  3. 所以继续删除元素frm root,直到你得到你的第k个最小值。 o(1)操作

  4. 确保在每次删除后重新存储堆kO(logn)操作。

  5. 所以这里的运行时间是O(klogn)+ O(n)............所以它是O(klogn)......

答案 4 :(得分:0)

可以像这样使用两个堆栈来定位一次传递中的第N个最小数字。

  • 从空Stack-A和Stack-B
  • 开始
  • 将第一个数字推入Stack-A
  • 下一个号码,如果号码小于其顶部,则选择将PUSH推入Stack-A
  • 当您必须推入Stack-A时,请执行以下步骤
    • 当Stack-A的TOP大于新数字时,Stack-A的POP TOP并将其推入Stack-B
    • 当Stack-A变空或其TOP小于新号码时,在新号码中按PUSH并在其上恢复Stack-B的内容
    • 此时您已将新号码插入Stack-A中的正确(已排序)位置,而Stack-B再次为空白
    • 如果Stack-A深度已足够您已达到搜索结束

我普遍同意Noldorins的优化分析 这个堆栈解决方案是朝着一个简单的方案工作(相对更多的数据移动 - 跨越两个堆栈)。堆方案将第N个最小数的提取减少到树遍历(log m)。

如果您的目标是最佳解决方案(例如,对于大量数字或可能用于编程分配,优化及其演示至关重要),您应该使用堆技术。

通过在K个元素的相同空间内实现两个堆栈(其中K是数据集的大小),可以在空间要求中压缩堆栈解决方案。因此,缺点是插入时额外的堆栈移动。

答案 5 :(得分:0)

Here is the Ans to find Kth smallest element from an array:

#include<stdio.h>
#include<conio.h>
#include<iostream>
using namespace std;
int Nthmin=0,j=0,i;
int GetNthSmall(int numbers[],int NoOfElements,int Nthsmall);
int main()
{
    int size;
    cout<<"Enter Size of array\n";
    cin>>size;
    int *arr=(int*)malloc(sizeof(int)*size);
    cout<<"\nEnter array elements\n";
    for(i=0;i<size;i++)
        cin>>*(arr+i);
    cout<<"\n";
    for(i=0;i<size;i++)
        cout<<*(arr+i)<<" ";
    cout<<"\n";
    int n=sizeof(arr)/sizeof(int);
    int result=GetNthSmall(arr,size,3);
    printf("Result = %d",result);
    getch();
    return 0;
}

int GetNthSmall(int numbers[],int NoOfElements,int Nthsmall)
{
    int min=numbers[0];
    while(j<Nthsmall)
    {
        Nthmin=numbers[0];
        for(i=1;i<NoOfElements;i++)
        {
            if(j==0)
            {
                if(numbers[i]<min)
                {
                    min=numbers[i];
                }
                Nthmin=min;
            }
            else
            {
                if(numbers[i]<Nthmin && numbers[i]>min)
                    Nthmin=numbers[i];
            }
        }
        min=Nthmin;
        j++;
    }
    return Nthmin;
}

答案 6 :(得分:0)

在不使用任何排序方法的情况下在数组中查找第n个最大元素的最简单方法。

public static void kthLargestElement() {
    int[] a = { 5, 4, 3, 2, 1, 9, 8 };
    int n = 3;
    int max = a[0], min = a[0];
    for (int i = 0; i < a.length; i++) {
        if (a[i] < min) {
            min = a[i];
        }
        if (a[i] > max) {
            max = a[i];
        }

    }

    int max1 = max, c = 0;
    for (int i = 0; i < a.length; i++) {
        for (int j = 0; j < a.length; j++) {
            if (a[j] > min && a[j] < max) {
                max = a[j];
            }
        }
        min = max;
        max = max1;
        c++;
        if (c == (a.length - n)) {
            System.out.println(min);
        }
    }
}