找到向量矢量的最大值/最小值

时间:2015-07-22 07:02:57

标签: c++ c++11 vector max min

找到向量向量的最大/最小项目的最有效和标准(C ++ 11/14)方法是什么?

std::vector<std::vector<double>> some_values{{5,0,8},{3,1,9}};

所需的最大元素 9

所需的min元素是 0

11 个答案:

答案 0 :(得分:8)

这是一个多线程解决方案,它将迭代器(或抛出)返回到常规类型T的最大值(假设为operator<定义了T)。请注意,最重要的优化是在'列'上执行内部最大操作,以利用C ++的列主要排序。

#include <vector>
#include <algorithm>

template <typename T>
typename std::vector<T>::const_iterator max_element(const std::vector<std::vector<T>>& values)
{
    if (values.empty()) throw std::runtime_error {"values cannot be empty"};

    std::vector<std::pair<typename std::vector<T>::const_iterator, bool>> maxes(values.size());

    threaded_transform(values.cbegin(), values.cend(), maxes.begin(),
                       [] (const auto& v) {
                           return std::make_pair(std::max_element(v.cbegin(), v.cend()), v.empty());
                       });

    auto it = std::remove_if(maxes.begin(), maxes.end(), [] (auto p) { return p.second; });

    if (it == maxes.begin()) throw std::runtime_error {"values cannot be empty"};

    return std::max_element(maxes.begin(), it,
                            [] (auto lhs, auto rhs) {
                                return *lhs.first < *rhs.first;
                            })->first;
}

threaded_transform不是标准库的一部分(但是),但这是您可以使用的实现。

#include <vector>
#include <thread>
#include <algorithm>
#include <cstddef>

template <typename InputIterator, typename OutputIterator, typename UnaryOperation>
OutputIterator threaded_transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op, unsigned num_threads)
{
    std::size_t num_values_per_threads = std::distance(first, last) / num_threads;

    std::vector<std::thread> threads;
    threads.reserve(num_threads);

    for (int i = 1; i <= num_threads; ++i) {
        if (i == num_threads) {
            threads.push_back(std::thread(std::transform<InputIterator,
                                      OutputIterator, UnaryOperation>,
                                      first, last, result, op));
        } else {
            threads.push_back(std::thread(std::transform<InputIterator,
                                      OutputIterator, UnaryOperation>,
                                      first, first + num_values_per_threads,
                                      result, op));
        }
        first  += num_values_per_threads;
        result += num_values_per_threads;
    }

    for (auto& thread : threads) thread.join();

    return result;
}

template <typename InputIterator, typename OutputIterator, typename UnaryOperation>
OutputIterator threaded_transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op)
{
    return threaded_transform<InputIterator, OutputIterator, UnaryOperation>(first, last, result, op, std::thread::hardware_concurrency());
}

答案 1 :(得分:6)

如果您使用的是boost::multi_array<double, 2>而不是std::vector<std::vector<double>>,那就简单如下:

auto minmax = std::minmax_element(values.data(), values.data() + values.num_elements());

Live demo

答案 2 :(得分:5)

计算二维数组(或您的情况中的向量)中的最大元素的任何有效方法都涉及O(n^2)的复杂性,无论您做什么,因为计算涉及{{1}之间的比较在易用性方面最好的方法是在向量​​向量上使用n*n。我不会深入研究细节。这里是reference.

答案 3 :(得分:5)

你必须至少查看每个元素,因此,正如Anony-mouse所提到的,复杂性至少是 O(n ^ 2)

#include <vector>
#include <limits>
#include <algorithm>

int main() {
    std::vector<std::vector<double>> some_values;
    double max = std::numeric_limits<double>::lowest();
    for (const auto& v : some_values)
    {
        double current_max = *std::max_element(v.cbegin(), v.cend());
        max = max < current_max ? current_max : max; // max = std::max(current_max, max);
    }
}

答案 4 :(得分:4)

如果您创建一个自定义迭代器来迭代double vector vector std::minmax_elementclass MyIterator : public std::iterator<std::random_access_iterator_tag, double> { public: MyIterator() : container(nullptr), i(0), j(0) {} MyIterator(const std::vector<std::vector<double>>& container, std::size_t i, std::size_t j) : container(&container), i(i), j(j) { // Skip empty container if (i < container.size() && container[i].empty()) { j = 0; ++(*this); } } MyIterator(const MyIterator& rhs) = default; MyIterator& operator = (const MyIterator& rhs) = default; MyIterator& operator ++() { if (++j >= (*container)[i].size()) { do {++i;} while (i < (*container).size() && (*container)[i].empty()); j = 0; } return *this; } MyIterator operator ++(int) { auto it = *this; ++(*this); return it; } MyIterator& operator --() { if (j-- == 0) { do { --i; } while (i != 0 && (*container)[i].empty()); j = (*container)[i].size(); } return *this; } MyIterator operator --(int) { auto it = *this; --(*this); return it; } double operator *() const { return (*container)[i][j]; } bool operator == (const MyIterator& rhs) const { return container == rhs.container && i == rhs.i && j == rhs.j; } bool operator != (const MyIterator& rhs) const { return !(*this == rhs); } private: const std::vector<std::vector<double>>* container; std::size_t i; std::size_t j; }; ,那么就可以使用简单的// Helper functions for begin/end MyIterator MyIteratorBegin(const std::vector<std::vector<double>>& container) { return MyIterator(container, 0, 0); } MyIterator MyIteratorEnd(const std::vector<std::vector<double>>& container) { return MyIterator(container, container.size(), 0); } int main() { std::vector<std::vector<double>> values = {{5,0,8}, {}, {3,1,9}}; auto b = MyIteratorBegin(values); auto e = MyIteratorEnd(values); auto p = std::minmax_element(b, e); if (p.first != e) { std::cout << "min is " << *p.first << " and max is " << *p.second << std::endl; } } 来完成工作

iterator类似于:

$sql= "SELECT r.client_id,c.id,t.id,a.id,o.id,c.name as cname,t.title as ttitle,a.title as atitle,o.title as otitle, l.title as ltitle
FROM og_ratings r 
INNER JOIN og_companies c
ON r.client_id = c.id
INNER JOIN og_rating_types t
ON r.rating_type_id = t.id
INNER JOIN og_actions a
ON r.pacra_action = a.id
INNER JOIN og_outlooks o
ON r.pacra_outlook = o.id
INNER JOIN og_lterms l
ON r.pacra_lterm = l.id
INNER JOIN og_sterms s
ON r.pacra_sterm = s.id
WHERE c.id= '$id2'
ORDER BY r.id DESC
LIMIT 1 ";

用法可能是

df1 = 
quality1  value
A         1
B         2
C         3

df2 = 
quality2  value
D         1
E         10
F         100

Live example

答案 5 :(得分:4)

普通for loop方式:

T max_e = std::numeric_limits<T>::min();
for(const auto& v: vv) {
    for(const auto& e: v) {   
        max_e = std::max(max_e, e);
    }
}

答案 6 :(得分:3)

使用accumulate函数,您可以写:

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
  std::vector<std::vector<double>> m{ {5, 0, 8}, {3, 1, 9} };

  double x = std::accumulate(m.begin(), m.end(), m[0][0],
                             [](double max, const std::vector<double> &v)
                             {
                               return std::max(max,
                                               *std::max_element(v.begin(),
                                                                 v.end()));
                             });

  std::cout << x << '\n';
  return 0;
}

但我更喜欢好的,旧的for-loop。

可以扩展示例以查找最小值和最大值:

std::accumulate(m.begin(), m.end(),
                std::make_pair(m[0][0], m[0][0]),
                [](std::pair<double, double> minmax, const std::vector<double> &v)
                {
                  auto tmp(std::minmax_element(v.begin(), v.end()));

                  return std::make_pair(
                    std::min(minmax.first, *tmp.first),
                    std::max(minmax.second, *tmp.second));
                });

不幸的是,向量的向量不会连续存储在内存中,因此您没有包含所有值的单个块(这是向量向量不是矩阵的良好模型的原因之一)

如果它包含很多元素,你可以利用矢量矢量。

由于每个子向量都是自治的,因此可以使用std::async异步填充包含每个子向量的最大值的期货向量。

答案 7 :(得分:3)

你可以很容易地使用Eric Niebler的range-v3库(这显然不是标准的,但希望将在不太遥远的未来):

p.second

{{1}}是min元素的迭代器; {{1}}到最大

(range-v3确实有minmax_element的实现,但不幸的是,它需要一个ForwardRange,而view :: join只给我一个InputRange,所以我不能使用它。)

答案 8 :(得分:1)

最简单的方法是首先要有一个函数来确定一个向量的最大/最小元素,比如一个叫做的函数:

    double getMaxInVector(const vector<double>& someVec){}

在这种情况下通过引用传递(仅用于阅读目的)将更加节省时间和空间(您不希望您的函数复制整个矢量)。因此,在确定向量向量的最大/最小元素的函数中,您将拥有一个嵌套循环,例如:

    for(size_t x= 0; x < some_values.size(); x++){
        for(size_t y = 0; y < x.size(); y++){
            // y represents the vectors inside the vector of course
            // current max/min = getMax(y)
            // update max/min after inner loop finishes and x increments
            // by comparing it with previous max/min

上述解决方案的问题在于效率低下。据我所知,这个算法通常会运行O(n ^ 2log(n))效率,这是非常不起眼的。但当然,它仍然是一个解决方案。尽管可能有标准算法可以为您找到向量的最大值/最小值,但是编写自己的算法总是更加完善,并且使用给定的算法通常无法提高效率,因为算法通常会是相同的(对于确定最大/最小的小函数)。事实上,从理论上讲,标准函数的运行速度会慢一些,因为这些函数是模板,必须确定它在运行时处理的类型。

答案 9 :(得分:0)

假设我们有一个名为 some_values 的向量,如下所示

7 4 2 0 
4 8 10 8 
3 6 7 6 
3 9 19* 14

定义一维向量,如下所示

vector<int> oneDimVector;
for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        oneDimVector.push_back(some_values[i][j]);
    }
}

然后找出该一维向量中的最大/最小元素,如下所示

vector<int>::iterator maxElement = max_element(oneDimVector.begin(),oneDimVector.end());
vector<int>::iterator minElement = min_element(oneDimVector.begin(),oneDimVector.end());

现在你得到如下的最大/最小元素

cout << "Max element is " << *maxElement << endl;
cout << "Min element is " << *minElement << endl;

答案 10 :(得分:0)

vector<vector<int>> vv = { vector<int>{10,12,43,58}, vector<int>{10,14,23,18}, vector<int>{28,47,12,90} };
vector<vector<int>> vv1 = { vector<int>{22,24,43,58}, vector<int>{56,17,23,18}, vector<int>{11,12,12,90} };
int matrix1_elem_sum=0;
int matrix2_elem_sum = 0;
for (size_t i = 0; i < vv.size(); i++)
{
    matrix1_elem_sum += std::accumulate(vv[i].begin(), vv[i].end(), 0);
    matrix2_elem_sum += std::accumulate(vv1[i].begin(), vv1[i].end(), 0);

}
cout << matrix1_elem_sum <<endl;
cout << matrix2_elem_sum << endl;
int summ = matrix1_elem_sum + matrix2_elem_sum;
cout << summ << endl;

或优化的变体:

vector<vector<int>> vv = { vector<int>{10,12,43,58}, vector<int>{10,14,23,18}, vector<int>{28,47,12,90} };
vector<vector<int>> vv1 = { vector<int>{22,24,43,58}, vector<int>{56,17,23,18}, vector<int>{11,12,12,90} };
int summ=0;
int matrix2_elem_sum = 0;
for (size_t i = 0; i < vv.size(); i++)
{
    summ += std::accumulate(vv[i].begin(), vv[i].end(), 0)+ std::accumulate(vv1[i].begin(), vv1[i].end(), 0);


}
cout << summ << endl;
 }