我正在尝试编写一个函数,该函数在数组中获取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;
}
它解决了部分问题,但这是最好的方法吗?
答案 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;
}