元素选择问题

来源:互联网 发布:数据分析excel面试题目 编辑:程序博客网 时间:2024/05/16 09:00

问题描述:从n个元素中选择第k小的元素。此问题存在最坏情况下时间复杂度为O(n)的算法,但本文不作讨论本文介绍一种使用“快速排序”算法的思想求解此问题的方法,平均时间复杂度O(nlogn) 。

“快速排序算法”的实质是“递归与分治”,以序列中a[l:r]的某个元素a[i]为基准将序列分成3部分:a[l:i-1],a[i]和a[i+1,r],

使之满足a[l:i-1]中的元素都小于a[i],同时a[i+1,r]中的元素都大于a[i]。然后递归地对a[l:i-1]和a[i+1,r]进行排序。

此算法的下一个特点是在每一次的“分区”过程中,被选择作为“基准”的元素就落在在了其最后的位置上。根据这个特点可以设计出求解“元素选择”问题的算法。

以POJ 2388 为例,partition算法实现时,选择的第一个位置上的元素作为基准(这种选择方式实现起来还算比较简单),当然如果想选用其他位置上的元素也可以直接将它与第一个位置上的元素交换。本次实现中就是选取开头、中间和结尾“三者取中”的方式,选取的基准越能将所有元素平均分配在两边,算法的效率越高。代码如下:


/* 204K    16MS */
#include <stdio.h>
#include <stdlib.h>

int g_output[10000];

void swap(int a[], int p, int q)
{
    int tmp;

    tmp = a[p];
    a[p] = a[q];
    a[q] = tmp;
}
int partition(int arr[], int l, int r)
{
    int pivotKey;
    int low, high, mid;
    
    //采用头部、中间、尾部“三者取中”的方式,确定枢轴点
    mid = (l + r) / 2;
    if ((arr[mid] - arr[l])*(arr[mid] - arr[r]) <= 0)
    {
        swap(arr, l, mid);
    }
    else if ((arr[r] - arr[l])*(arr[r] - arr[mid]) <= 0)
    {
        swap(arr, l, r);
    }

    low = l;
    high = r;
    pivotKey = arr[low];

    while (low < high) {
        while (high > low && arr[high] >= pivotKey) {
            high--;
        }
        arr[low] = arr[high];
        while (low < high && arr[low] <= pivotKey) {
            low++;
        }
        arr[high] = arr[low];
    }
    arr[low] = pivotKey;

    return low;
}

int select(int arr[], int l, int r, int k)
{
    int i;

    i = partition(arr, l, r);
    if (k == i) {
        return arr[i];
    } else if (k < i) {
        return select(arr, l, i - 1, k);
    } else {
        return select(arr, i + 1, r, k);
    }
}
int main()
{
    int n;
    int i, rel;
    
    scanf("%d", &n);
    for (i = 0; i < n; ++i) {
        scanf("%d", &g_output[i]);
    }
    rel = select(g_output, 0, n - 1, (n-1)/2);
    printf("%d", rel);
}

下面再提供一个使用C++ 的nth_element函数实现的代码: /* 204K, 0MS*/ 由此可见C++中nth_element的实现还是很高效的。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int g_output[10000];

int main()
{
    int n;
    int i;

    scanf("%d", &n);
    for (i = 0; i < n; ++i) {
        scanf("%d", &g_output[i]);
    }

    nth_element(g_output, g_output + (n-1)/2, g_output + n);
    printf("%d", g_output[(n-1)/2]);
}


0 0
原创粉丝点击