【问题标题】:Maximum X values at array数组中的最大 X 值
【发布时间】:2016-07-20 18:35:38
【问题描述】:

我正在尝试编写一个函数,该函数采用数组、大小和数组中 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;
        }

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

【问题讨论】:

  • 最简单的答案是用qsort对数组进行排序(降序),然后取前X项。或者,您需要在 retArray 的正确位置插入新项目,以便始终对数组进行排序。
  • 您正在用 88 覆盖 77,即使 67 更小。您需要替换 retArray 中的最小值,而不是您找到的第一个。
  • calloc(sizeof(int) * maxGrades) --> calloc( maxGrades, sizeof(int))
  • 可以说这是一个学习练习,qsort 是在作弊。那么你的问题是任何进入retArray 的新值都有break 语句阻止对retArray 中的后续索引进行测试。可以跳过找到新最大值的机会。我怀疑用grades[i]=0; 替换break; 会起作用,但我懒得检查。但那将是相当蛮力的。

标签: c++ c arrays algorithm


【解决方案1】:

虽然它可以使用选择算法在线性时间内完成,但通常在每次迭代时使用存储前 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;
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      如果您的 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;
      }
      

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2021-06-12
          • 1970-01-01
          • 2011-03-30
          • 2010-09-20
          • 1970-01-01
          • 2016-09-10
          • 2020-03-15
          • 1970-01-01
          • 2021-01-16
          相关资源
          最近更新 更多