返回第k个最小元素的函数

时间:2016-06-26 17:51:01

标签: c++ loops vector iteration

我正在尝试编写一个返回向量中第k个最小元素的函数。我必须迭代地执行此操作,并且无法对元素进行排序。下面是我到目前为止,但我得到一个分段错误或矢量错误的数字。任何帮助将不胜感激!

#include<vector>
#include<iostream>
using namespace std;

int iterative_kth_element(vector<int> &vec, size_t k){

   int cur = 0;
   int vecSmallestLocation = 0;
   for(int i=0; i<k; i++){
      if(vec.empty()){
         return cur;
      }
      cur = vec[0];
      for(int j=0; j<vec.size(); j++){
         if(vec[j]<cur){
            cur = vec[j];
            vecSmallestLocation = j;
         }
      }
      vec.erase(vec.begin()+(vecSmallestLocation));
   }

   cout << cur << endl;
   return cur;
}

int main(){
   vector<int> vec;
   vec.push_back(6);
   vec.push_back(21);
   vec.push_back(98);
   vec.push_back(14);
   vec.push_back(5);
   vec.push_back(7);
   vec.push_back(9);

   iterative_kth_element(vec, 3); // returns 6 but thats wrong
   //iterative_kth_element(vec, 4); // seg fault

}

5 个答案:

答案 0 :(得分:1)

它认为问题是你不在循环中初始化vecSmallestLocation,它应该是

  vecSmallestLocation = 0;             // <-- this was missing
  cur = vec[0];
  for(int j=0; j<vec.size(); j++){
     if(vec[j]<cur){
        cur = vec[j];
        vecSmallestLocation = j;
     }
  }
  vec.erase(vec.begin()+(vecSmallestLocation));

因为如果第一个元素是最小的,那么if将不会为要删除的索引设置正确的值(如果vec[0] < curcur == vec[0],则为{}})使用最后一次迭代(如果超出矢量大小,可能会导致seg错误)

实际上我建议您使用std::limits的限制,因为目前只有当所有向量元素都是&gt; 0时,您的函数才会起作用。

PS:有std算法可以做你想要的,但通常必须手动完成,因此我通常使用这样的东西

struct MinValueAndIndex {
   int index;
   int value;
   MinValueAndIndex(const std::vector<int>& v) 
        : index(0), value(v[0]) {}
};

避免这样的错误。

答案 1 :(得分:1)

边缘情况可能会给出分段错误。 你继承变量vecSmallestLocation,因为它超出了循环的范围。因此,请查看循环中的if语句:

     if(vec[j]<cur){
        cur = vec[j];
        vecSmallestLocation = j;
     }

如果是这种情况,那么向量中没有剩余变量的值小于cur这个if语句永远不会被输入,并且vecSmallestLocation永远不会被正确地分配给新的值。 当您进入循环时,删除5后,6是最小值,vecSmallestLocation将不会更新,仍然保留最后一次迭代全局最小值的值,即vec[4]。因此,您错误地再次删除位置vec[4]处的元素,即7。这是错误的。

尝试if(vec[j] <= cur)

答案 2 :(得分:1)

是的,tobi指向的是正确的,你必须在内循环之外初始化vecSmallestLocation。并且考虑到分段错误正在发生,因为您通过引用传递向量,并且您的函数正在修改向量并将其大小减小到3并且新向量中没有第4个最小元素。所以不要通过引用传递向量。

以下是您的代码的修改版本。我试着尽可能地修改它。

#include<vector>
#include<iostream>
using namespace std;
void iterative_kth_element(vector<int> vec, size_t k)
{
   int cur = 0;
   int vecSmallestLocation = 0;
   for(int i=0; i<k; i++)
   {
      if(vec.empty())
      {
         return ;
      }
      cur = vec[0];
      vecSmallestLocation = 0;
      for(int j=0; j<vec.size(); j++)
      {
         if(vec[j]<cur)
         {
            cur = vec[j];
            vecSmallestLocation = j;
         }
      }
      vec.erase(vec.begin()+(vecSmallestLocation));
   }
   cout << cur << endl;
}

int main(){
   vector<int> vec;
   vec.push_back(6);
   vec.push_back(21);
   vec.push_back(98);
   vec.push_back(14);
   vec.push_back(5);
   vec.push_back(7);
   vec.push_back(9);

   iterative_kth_element(vec, 3); 
   iterative_kth_element(vec, 4); 
}

答案 3 :(得分:1)

我不知道你怎么能这样做而不必扫描每个连续数字的整个向量(除非你密切关注左边的下一个最小数字及其位置,所以你只需要扫描每个下一个读取的右边的所有内容)。您还必须处理两个数字相同的特殊情况。请记住,算法是完全迭代的(即使在递归时),这意味着每个连续项依赖于前一个项的知识,除非您排序。记得把它分解成更简单的问题。

您也不需要修改矢量来执行此操作。我根据你的描述,不确定你为什么要在那里进行擦除。

  • 你如何找到第一个最小的数字?
    • 扫描列表中最左边的最小数字
  • 你如何找到下一个最小的数字?
    • 扫描列表以查找与最后一个号码相同但索引更大的下一个号码,或者如果不存在其他相同号码,请提供下一个更大的号码(这对于避免已返回的相同号码非常重要)
  • 您如何找到i最小的数字?
    • 重复算法,并保持计数。

将例程分解为独立,易于理解的部分。

所以,这样的事情(我避免使用迭代器,以便我可以主要处理指标。在我自己的代码中,我将它们全部化为仅适用于迭代器的模板,或者创建一个特殊的迭代器类型,这样做,所以我可以按顺序完全迭代。另请注意,此代码不处理边缘情况,如空向量或指定k的值大于向量的大小):

#include <vector>
#include <cassert>
using namespace std;

// Get the index of the smallest value
vector<int>::size_type get_smallest_index(const vector<int> &vec)
{
    vector<int>::size_type index = 0;
    int smallest = vec.front();
    for (vector<int>::size_type i = 1; i < vec.size(); ++i)
    {
        if (vec[i] < smallest)
        {
            index = i;
            smallest = vec[i];
        }
    }
    return index;
}

// Get the index of the next smallest value
vector<int>::size_type get_smallest_index(const vector<int> &vec, const vector<int>::size_type prev_index)
{
    vector<int>::size_type next = prev_index;
    int next_value = 0;
    for (vector<int>::size_type i = 0; i < vec.size(); ++i)
    {
        // If there is another value identical to the last but further along
        if (i > prev_index && vec[i] == vec[prev_index])
        {
            return i;
        }
        // If the value is greater than the previous, and either the next hasn't been set or it is less than the existing next value
        if (vec[i] > vec[prev_index] && (next == prev_index || vec[i] < next_value))
        {
            next = i;
            next_value = vec[i];
        }
    }
    return next;
}
int iterative_kth_element(vector<int> &vec, size_t k)
{
    // Get the smallest index to start with
    vector<int>::size_type index = get_smallest_index(vec);

    // Get the next smallest index * k (so it's 0-indexed)
    for (vector<int>::size_type i = 0; i < k; ++i)
    {
        index = get_smallest_index(vec, index);
    }

    return vec[index];
}

int main(){
   vector<int> vec;
   vec.push_back(6);
   vec.push_back(21);
   vec.push_back(98);
   vec.push_back(14);
   vec.push_back(5);
   vec.push_back(7);
   vec.push_back(9);

   assert(iterative_kth_element(vec, 3) == 9);
   return 0;
}

答案 4 :(得分:0)

找到最小的kth不应该改变你的初始向量,因为你正在破坏信息。您可以按如下方式更新功能。

int iterative_kth_element(const vector<int> &vec, size_t k){
   // You only need to check this once now
   // and do a double check to make sure that kth element is valid
   if(vec.empty() && vec.size() <= k){
      // return INT_MAX and not 0  because the smallest element could possible be 0
      return numeric_limits<int>::min();
   }
   int cur = numeric_limits<int>::max();
   int lastMin = numeric_limits<int>::min();
   for(int i=0; i<k; i++){
      for(int j=0; j<vec.size(); j++){
         if(vec[j] >= lastMin && vec[j] < cur){
            cur = vec[j];
         }
      }
      lastMin = cur;
      cur = numeric_limits<int>::max();
   }
   cout << lastMin << endl;
   return lastMin;
}

此方法首先不会通过删除它来销毁向量中的信息。其次,该算法的时间复杂度与您的相同,即O(kn),其中n是vec.size()。最后将运行没有错误,并给你第k个最小的元素。