数组中的最大X值

时间:2016-07-20 18:35:38

标签: c++ c arrays algorithm

我正在尝试编写一个函数,该函数在数组中获取X个最大等级的数组,大小和数量。
例如:

array = { 90,45,77,43,67,88 }, maxGrades = 3

结果应为:

retArray = {90,77,88} or {90,88,77}

我的尝试:

int * GetMaxGrades(int * grades, int size, int maxGrades)
{
     int *retArray;

     if (maxGrades > size)
        return grades;

     retArray = (int*)calloc(sizeof(int) * maxGrades);

     for (int i = 0; i < size; i++)
     {
         for (int j = 0; j < maxGrades; j++)
            if (grades[i] > retArray[j])
            {
                 retArray[j] = grades[i];
                 break;
            }
     }

     return retArray;
}

但是我恢复了{90,88,67}

修改 如果我改变内循环:

        if (grades[i] > retArray[j])
        {
            if (j + 1 < maxGrades)
                retArray[j + 1] = retArray[j];

            retArray[j] = grades[i];
            break;
        }

它解决了部分问题,但这是最好的方法吗?

4 个答案:

答案 0 :(得分:4)

虽然可以使用选择算法在线性时间内完成,但通常使用存储前k个元素的最小堆来完成,在每次迭代时 - 检查堆中的最小元素是否大于你正在迭代的当前一个,如果是 - 你替换它们。

这是O(nlogk)时间且仅O(k)额外内存,并且只需要对数据进行一次遍历(因此,如果您的元素在流中传入,它将完美地运行)。

以下代码是C ++ 11(具有优雅的for-each循环),但使用相同的数据结构很容易将其转换为旧的c ++代码。

#include <iostream>
#include <vector>
#include <queue>

int main(void) {
    int array[] = { 90,45,77,43,67,88 }; 
    int maxGrades = 3;
    std::priority_queue<int, std::vector<int>, std::greater<int>> q;
    for (int x : array) { 
        // populate first maxGrades elements
        if (q.size() < maxGrades) {
            q.push(x);
        // replace if new element is higher than smallest in heap.
        } else if (q.top() < x) {
            q.pop();
            q.push(x);
        }
    }
    // print elements
    std::cout << "elements: ";
    while (!q.empty()) { 
        std::cout << q.top() << " ";
        q.pop();
    }
    return 0;
}

答案 1 :(得分:2)

使用QuickSort发明人的QuickSelect算法,可以在 O(N)平均复杂度中选择大小为N的数组中的X最大值:https://en.wikipedia.org/wiki/Quickselect

答案 2 :(得分:0)

在最后一次循环迭代开始时,你的retArray如下所示:{90,77,67}。如果您使用i=5逐步执行内循环,您会发现在67之前找到77,所以77是被替换的。您可能应该对数组进行排序并获取最大的maxGrades值,但是如果您想按照自己的方式进行操作:

for(...)
    if(grades[i] > retArray[j])
        if(retArray[j] < retArray[minVal])
            minVal = j;
if(minVal > 0)
    retArray[minVal] = grades[i];
minVal = -1;

答案 3 :(得分:0)

如果您的grades数组可能包含重复项,则解决方案变得更加困难。并且不要忘记,如果你返回指向grades数组的指针,调用者可能不知道应该或不应该释放返回的指针。

#include <stdio.h>
#include <stdlib.h>

int* GetMaxGrades(int* grades, int size, int maxGrades) {
    if (maxGrades <= 0 || size <= 0)
        return NULL;

    // first, function must allocate memory every time,
    // otherwise you can't understand when to free memory or when do not it.
    int *retArray = (int*)malloc(sizeof(int) * maxGrades);

    if (maxGrades >= size) {
        for (int i = 0; i < size; ++i)
            retArray[i] = grades[i];
        for (int i = size; i < maxGrades; ++i)
            retArray[i] = 0;
    }
    else {
        // need to save positions of found max grades,
        // because if there's duplicates among grades,
        // you will pick up only different onces.
        int *positions = (int*)malloc(sizeof(int) * maxGrades);
        for (int i = 0; i < maxGrades; ++i) {
            int position = 0;
            int maxgrade = INT_MIN;
            for (int j = 0; j < size; ++j) {
                // pick max grade
                if (grades[j] > maxgrade) {
                    // do not permit duplicates among positions
                    bool newmax = true;
                    for (int k = 0; k < i; ++k) {
                        if (positions[k] == j) {
                            newmax = false;
                            break;
                        }
                    }
                    // assign new max value & position
                    if (newmax) {
                        position = j;
                        maxgrade = grades[j];
                    }
                }
            }
            positions[i] = position;
            retArray[i] = maxgrade;
        }
        free(positions);
    }
    return retArray;
}

int main(int argc, char* argv[]) {
    int a[] = { 90,45,77,43,67,88 };
    const int max_grades = 3;
    int *p = GetMaxGrades(a, sizeof(a) / sizeof(a[0]), 3);
    for (int i = 0; i < max_grades; ++i) {
        printf("%d ", p[i]);
    }
    printf("\n");
    free(p);
    return 0;
}

如果您被允许使用qsort,那将变得更加轻松:

#include <stdio.h>
#include <stdlib.h>

int greater_comp(const void * a, const void * b) {
    return *(int*)b - *(int*)a;
}

int* GetMaxGrades(int* grades, int size, int maxGrades) {
    if (maxGrades <= 0 || size <= 0)
        return NULL;

    int alloc_size = (maxGrades < size) ? size : maxGrades;

    // copy grades array (allocate more memory)
    int *retArray = (int*)malloc(sizeof(int) * alloc_size);
    for (int i = 0; i < size; ++i)
        retArray[i] = grades[i];
    for (int i = size; i < alloc_size; ++i)
        retArray[i] = 0;

    // sort: descending order
    qsort(retArray, size, sizeof(int), greater_comp);

    return retArray;
}

int main(int argc, char* argv[]) {
    int a[] = { 90,45,77,43,67,88 };
    const int max_grades = 3;
    int *p = GetMaxGrades(a, sizeof(a) / sizeof(a[0]), 3);
    for (int i = 0; i < max_grades; ++i) {
        printf("%d ", p[i]);
    }
    printf("\n");
    free(p);
    return 0;
}

如果您使用算法库将变得更加容易:

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>

using namespace std;

vector<int> GetMaxGrades(vector<int> grades, int maxGrades) {
    // descending order
    sort(grades.begin(), grades.end(), greater<int>());
    grades.resize(maxGrades);
    return grades;
}

int main(int argc, char* argv[]) {
    vector<int> a = { 90,45,77,43,67,88 };
    vector<int> p = GetMaxGrades(a, 3);
    for (auto& i : p)
        cout << i << ' ';
    cout << endl;
    return 0;
}