我正在尝试编写一个返回向量中第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
}
答案 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] < cur
为cur == 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个最小的元素。