使用一个变量的最小值提取struct数组

时间:2014-12-14 22:22:06

标签: c++

所以我想说我有以下结构

struct BadQuestion
{
   float a;
   float b;

} BadArray[10];

现在我需要检查哪个数组[i]的第二个最小值为'float a'。因为我后来需要从具有最小'float a'的数组中提取'float b'。

我看过像this这样的例子,但似乎有点过分了。有没有更简单快捷的方法来实现这一目标?

更新1:

bool cmp(const BadQuestion& lhs, const BadQuestion& rhs)
{
    return lhs.a < rhs.a;
}

auto mini = std::min_element(BadArray, BadArray + 10, cmp);
mini->a

这会给我一个最小的值,这是一个很好的步骤。但我需要second最低值。

2 个答案:

答案 0 :(得分:0)

直截了当的方法很简单:

// n is assumed to be at least 2
int i0 = array[0].a<array[1].a ? 0 : 1, i1 = 1 - i0;
for (int i=2; i<n; i++) {
    if (array[i].a < array[i1].a) {
        if (array[i].a < array[i0].a) {
            i1 = i0; i0 = i;
        } else {
            i1 = i;
        }
    }
}
// i0 is index of smallest a value, i1 is index of second-smallest

并且我非常确定现代编译器会将其转换为合理优化的机器代码(但是使用floats可能不是速度的好主意。)

答案 1 :(得分:0)

根据您是否关心订单,有两种解决方案。

如果您在此操作之后关心任何元素的排序,则可以使用标准算法nth_element。它会重新排序您的元素:

template <typename Iter, typename Cmp>
typename std::iterator_traits<Iter>::value_type
nth_smallest_reorder(Iter begin, Iter end, int n, Cmp cmp) {
    std::nth_element(begin, begin + n, end, cmp);
    return *(begin + n);
}

如果你关心订购,那么你可以做两件事之一。首先,您可以直接复制整个阵列:

template <typename Iter, typename Cmp>
typename std::iterator_traits<Iter>::value_type
nth_smallest_copy(Iter begin, Iter end, int n, Cmp cmp) {
    std::vector<typename std::iterator_traits<Iter>::value_type> cpy(begin, end);
    std::nth_element(cpy.begin(), cpy.begin() + n, cpy.end(), cmp);
    return cpy[n];
}

或者,您可以保留最多n+1的运行排序列表:

template <typename Iter, typename Cmp>
typename std::iterator_traits<Iter>::value_type
nth_smallest_no_copy(Iter begin, Iter end, int n, Cmp cmp) {
    std::vector<typename std::iterator_traits<Iter>::value_type> n_best;
    n_best.reserve(n + 2);

    for (; begin != end; ++begin) {
        if (n_best.empty() || cmp(*begin, n_best.back())) {
            n_best.insert(
                std::lower_bound(n_best.begin(), n_best.end(), *begin, cmp),
                *begin);

            if (n_best.size() > n + 1) n_best.resize(n + 1);
         }
    }

    return n_best.back();
}