【问题标题】:Finding the Kth Smallest Element in an unsorted vector (Iteratively)在未排序的向量中找到第 K 个最小元素(迭代)
【发布时间】:2013-10-17 23:39:27
【问题描述】:

我正在尝试编写一个返回向量中第 k 个最小元素的代码。 例如: 假设您有一个包含元素 {0, 3, 2, 5} 的向量 rand 用户输入 2 作为 K 的值。 然后该函数应从向量中返回元素 2,因为它是向量中的第二(第 k)个最小元素。

到目前为止,这是我的代码:

int iterative_kth_element(vector<int>& vec, size_t k)
{
    int index = 0;
    int min = vec[0];


    for(int i = k;i<vec.size();i--) {
            for (int j = 1; j < vec.size();j++) {
            if ( min > vec[j] ) {
                min = vec[j];
                index = i;
            }
        vec.erase(vec.begin() + index);

        if (i == 1) {
            return min;
        }

            }
    }

}

它不断返回一些甚至不在向量中的巨大数字。

【问题讨论】:

  • 除非你真的需要做其他事情(例如,这是家庭作业)使用std::nth_element
  • 实际上对向量进行排序并从前面返回第 k 个元素可能是一种更快的方法,除非你真的想迭代地解决它
  • 是的,我必须用未排序的向量来做
  • 你不能只为 min 存储 1 个值。您需要存储 k 个最小的项目并在对向量进行 1 次迭代时维护此信息数组/列表。一次迭代后,返回 k 个项目中最大的一个。

标签: c++ algorithm vector


【解决方案1】:
for(int i = k;i<vec.size();i--)

似乎不对,假设k 总是&lt; vec.size(),那么条件i&lt;vec.size() 在这里完全没用。相反,您可能更愿意添加:

for(int i = k; i > 0; i--)

嵌套循环实际上应该检查所有元素,因此它应该从0 开始(它会跳过第一个元素):

for (int j = 0; j < vec.size(); j++) {
             ^

我相信

index = i;

本来是:

index = j;

并确保所有可能的执行路径都返回一些值,注意编译器给你的警告。在函数末尾再添加一条return 语句:

return min;

但是您的主要问题是:

  • 您应该在嵌套循环开始执行之前更新min
  • 嵌套循环的范围不应包含erase 调用

试试:

int foo(std::vector<int>& vec, const size_t k)
{
    int index = 0;
    int min = -1;

    for(size_t i = 0; i < k; ++i) {
        if (vec.empty()) return min;
        min = vec[0];
        for (size_t j = 0; j < vec.size(); ++j) {
            if (vec[j] < min) {
                min = vec[j];
                index = j;
            }
        }
        vec.erase(vec.begin() + index);
    }
    return min;
}

int main() {
    int a[] = {0, 3, 2, 5};
    std::vector<int> v(a, a+4);
    std::cout << foo(v, 2);
}

【讨论】:

  • 我使用 i
  • 这是一个迭代解决方案。他不需要从 0 开始,因为他可以在前 k 项最小的假设下开始。他只是忘记创建前 k 个项目的列表。他将需要它来比较和存储找到的 k 个最小的项目。
【解决方案2】:

从这里开始:http://en.wikipedia.org/wiki/Selection_algorithm

int iterative_kth_element(vector<int>& vec, size_t k)
{
     int minIndex, minValue;
     for (int i = 0; i < k; i++)
     {
         minIndex = i;
         minValue = vec[i];
         for (int j = i+1; j < n; j++)
         {
             if (vec[j] < minValue)
             {
                 minIndex = j;
                 minValue = vec[j];
             }
         }
         int tmp = vec[i];
         vec[i] = vec[minIndex];
         vec[minIndex] = tmp;
     }
     return vec[k];
}

【讨论】:

    【解决方案3】:

    1/ 你有一个向量,但你几乎只将它用作一个数组

    2/ 考虑使用迭代器。

    3/ 你接收向量作为参考,这意味着对它的修改(例如擦除元素)在方法范围之外是有效的,你真的要这样做吗?

    【讨论】:

      【解决方案4】:

      这是我的解决方案的一些不完整代码。它只需要通过向量 1 次。这将在相对于 vec 的线性时间内运行。希望它可以解决问题。我之前的文字有点啰嗦。不过我把它留在了这个来源下面。

      int iterative_kth_element(vector<int>& vec, size_t k)
      {
          int mins[k];
          //assume first k elements are min
          for(int i=0; i<k; i++)
          {
              mins[i] = vec[i];
          }
      
          //TODO:
          //sort mins array here
          //bubble sort is okay if k is small, or pivot
      
          for(int i=k; i < vec.size(); i++)
          {
              //since mins is sorted, mins[k-1] is the highest value
              if(vec[i] < mins[k-1])
              {
                  mins[k-1] = vec[i];
              }
      
              //TODO:
              //sort mins array here
              //you could do a slick bubble sort starting from 
              //the back of mins until you find the location 
              //for the new min item
          }
      
          return mins[k-1];
      }
      

      //上一段文字

      如果您要找到第 k 个最小的项目。您应该使用第一个 k 项初始化一个数组。或者将索引存储到找到最小项目的 vec 中。(将从 0,1,2,3,...,k 开始)

      int index = 0;
      int min = vec[0];
      

      应该是

      int* mins = new int[k];
      for(int i=0; i < k; i++) {
          mins[i] = vec[i];
      }
      

      我还建议对这个由 k 个最小整数组成的数组进行排序。如果您知道最大的项目在哪里,您只需将 vec 中的每个元素与以分钟为单位的最大项目进行对比。不过,您需要一个 sort 方法,每当您发现小于您的分钟数时都会调用该方法。

      在 vec 的一次迭代之后,您应该在该数组中拥有 k 个最小的项目。只需返回最大的项目。存储在数组中的位置 0 或 k-1。

      还有一点需要注意:如果 k 大于 vec.size() / 2,你应该寻找 (vec.size() - k) 最大的项。

      这应该是 log(k*n) 时间,最大内存占用为 1.5n(k 正好是 vec.size()/2 的情况是最坏的情况)。

      其中 n 是 vec 的大小,k 是函数中的参数。(如果您实现该注释,则 k 的上限为 n/2)。

      最坏的情况是得到一个按降序排列的数字列表,其中 k 是 n 的一半。

      【讨论】:

      • 你在该代码中遗漏了一些东西,而且这是 c++ 而不是 c
      • 好电话,忘记将 malloc 转换为 int*。我只是将其更改为 new int[k]。
      • 所以用这种方法我不需要第二个循环?还是我必须调整它?
      • 之前的所有解决方案都建议您对向量进行排序,然后返回第 k 个项目。另一种解决方案是使用 k 次选择排序,始终从该列表中删除最小的项目。我的解决方案只涉及 1 次遍历数组。尽管您可能需要对 min[] 进行多次传递才能使其保持排序。
      • @JustinDanielson:我的回答修复了他的相同方法,它不会对向量进行排序。
      【解决方案5】:

      整数数组已设置。

      1. 从数组中删除所有分配的正元素 在最大和最小元素之间。

      2. 计算数组负单元格的总和。

      3. 计算素数的最小值

      【讨论】:

        猜你喜欢
        • 2012-10-22
        • 2017-03-04
        • 2013-02-17
        • 2022-01-04
        • 1970-01-01
        • 2015-01-15
        • 2021-09-07
        相关资源
        最近更新 更多