简体   繁体   English

精美的代码可从3个数组中找到5个最大顶部数

[英]Elegant code to find the 5 max top number from 3 Array

I read that blog where a C# programmer show how to use LINQ to extract the 5 top numbers from 3 different Array. 我读过该博客 ,其中C#程序员展示了如何使用LINQ从3个不同的Array中提取5个最重要的数字。

I tried to do the same with C++ and wrote the following, only 5 line of code using vector, and sort. 我试图对C ++进行同样的操作,并使用vector和sort编写了以下仅5行代码。 The output is 88 89 110 888 921 as expected. 预期输出为88 89 110 888 921

But have the question is, have you a better solution ? 但是问题是,您有更好的解决方案吗?

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

using namespace std;

int main(int argc, char* argv[])
{
    int Array1 [] = { 9, 65, 87, 89, 888 };
    int Array2 [] = { 1, 13, 33, 49, 921 };
    int Array3 [] = { 22, 44, 66, 88, 110 };

    vector<int> A1(begin(Array1), end(Array1)); 
    A1.insert(end(A1), begin(Array2), end(Array2)); 
    A1.insert(end(A1), begin(Array3), end(Array3));
    sort(begin(A1), end(A1));
    vector<int> max(end(A1)-5, end(A1));

    copy(begin(max), end(max), ostream_iterator<int>(cout, " "));

    return 0;
}

I'd use boost::zip_iterator to eleganty append the 3 input arrays, and std::nth_element with std::greater to get the 5 largest elements in unspecified order 我会使用boost::zip_iterator优雅地追加3个输入数组,并使用std::nth_elementstd::greater来按未指定的顺序获取5个最大的元素

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
#include <boost/iterator/zip_iterator.hpp>

int main()
{
    int Array1 [] = { 9, 65, 87, 89, 888 };
    int Array2 [] = { 1, 13, 33, 49, 921 };
    int Array3 [] = { 22, 44, 66, 88, 110 };

    std::vector<int> v;
    v.reserve((sizeof(Array1) + sizeof(Array2) + sizeof(Array3)) / sizeof(int));

    std::for_each(
        boost::make_zip_iterator(boost::make_tuple(std::begin(Array1), std::begin(Array2), std::begin(Array3))),
        boost::make_zip_iterator(boost::make_tuple(std::end(Array1), std::end(Array2), std::end(Array3))),
        [&v](boost::tuple<int, int, int> const& t) {
            v.push_back(t.get<0>()); v.push_back(t.get<1>()); v.push_back(t.get<2>());
        }
    );

    std::nth_element(begin(v), begin(v) + 5, end(v), std::greater<int>());
    std::copy(begin(v), begin(v) + 5, std::ostream_iterator<int>(std::cout, " "));
}

Live Example . 现场例子

Complexity: linear O(N1 + N2 + N3) . 复杂度:线性O(N1 + N2 + N3)

If you want to have the largest elements in order, you could either use a std::partial_sort instead of std::nth_element or do a post-processing std::sort on the first 5 elements of v . 如果std::sort顺序排列最大的元素,则可以使用std::partial_sort而不是std::nth_element或对v的前5个元素进行后处理std::sort The complexity of std::partial_sort for the top K elements is O(N log K) , which approaches O(N log N) for a full sort. 对于前K个元素, std::partial_sort的复杂度为O(N log K) ,对于完整排序,其复杂度接近O(N log N) For K=5 , there should be little difference between std::nth_element and std::partial_sort . 对于K=5std::nth_elementstd::partial_sort之间应该没有什么区别。

Most solutions that involve sorting the array (either the complete array, or the sub-arrays individually) will be sub-optimal in terms of time complexity. 就时间复杂度而言,大多数涉及对数组进行排序(完整数组或子数组单独)的解决方案都是次优的。 All comparison-based sorting requires a minimum of O(N log N) complexity. 所有基于比较的排序都要求O(N log N)复杂度最小。 Something like a bucket sort or radix sort can reduce that, but only with fairly specific limitations (that may not apply here). 类似于存储桶排序或基数排序之类的东西可以减少这种情况,但是只能有相当具体的限制(可能不适用于此处)。

It seems to me that for this task, linear complexity should be possible, so that's what we really want. 在我看来,对于此任务,线性复杂度应该是可能的,这就是我们真正想要的。

Further, I'm going to assume that the target of 5 lines of code includes only executable statements (ie, things like #include don't count), that C++11 is allowed, and that even though the data in the question happens to be sorted, it should work even if the data isn't sorted. 此外,我将假设5行代码的目标仅包含可执行语句(即,诸如#include不计算在内),允许使用C ++ 11以及即使问题中的数据碰巧被排序了,即使数据没有被排序也应该可以工作。

With those conditions/assumptions in mind, I'd do the job like this: 考虑到这些条件/假设,我将执行以下工作:

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

int main() {
    std::vector<int> A1{ 9, 65, 87, 89, 888 };
    A1.insert(A1.end(), { 1, 13, 33, 49, 921 });
    A1.insert(A1.end(), { 22, 44, 66, 88, 110 });

    std::nth_element(A1.begin(), A1.end() - 5, A1.end());
    std::copy(A1.end() - 5, A1.end(), std::ostream_iterator<int>(std::cout, "\n"));
}

At least IMO, that qualifies as fairly elegant -- clear, concise and efficient. 至少海事组织(IMO)相当优雅-清晰,简洁,高效。

Yet another nice way to do this is boost.accumulators : 实现此目的的另一种好方法是boost.accumulators

#include <iostream>
#include <vector>
#include <string>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

int main(int argc, char* argv[])
{
    int Array1 [] = { 9, 65, 87, 89, 888 };
    int Array2 [] = { 1, 13, 33, 49, 921 };
    int Array3 [] = { 22, 44, 66, 88, 110 };

    using namespace boost::accumulators;

    // this will accumulate the 5 largest numbers 
    accumulator_set<int, features< tag::tail<right> > > acc (
        tag::tail<right>::cache_size = 5);

    // combine the arrays into a single iterator range
    // and then apply for_each once, if you like
    acc = std::for_each(Array1, Array1 + 5, acc);
    acc = std::for_each(Array2, Array2 + 5, acc);
    acc = std::for_each(Array3, Array3 + 5, acc);

    for(int n : tail(acc))
        std::cout << n << ' '; // 921, 888, 110, 89, 88
}

I interpret "better" as in better time complexity = faster algorithm. 我将“更好”解释为更好的时间复杂度=更快的算法。 If you aim for a different "better" then please neglect my post. 如果您打算换一个“更好”的东西,那么请忽略我的帖子。

Although you have not stated that the three arrays are sorted, the are infact in your program. 尽管您尚未声明这三个数组已排序,但是它们实际上在程序中。 So, assuming the three arrays are always sorted, you could do an improvment: (The following code is more pseudo-code than C++, sorry but I do not have a C++ compiler atm) 因此,假设三个数组始终排序,则可以做一个改进:(以下代码比C ++更多的伪代码,对不起,但我没有C ++编译器atm)

int i1 = Array1.size();
int i2 = Array2.size();
int i3 = Array3.size();
int n = 5;
int solution[n];

while (n > 0) {
    n = n - 1;
    if (Array1[i1] >= Array2[i2] && Array1[i1] >= Array3[i3]) {
        solution[n] = Array1[i1];
        i1 = i1 - 1;
    } else if (Array2[i2] >= Array1[i1] && Array2[i2] >= Array3[i3]) {
        solution[n] = Array2[i2];
        i2 = i2 - 1;
    } else {
        solution[n] = Array3[i3];
        i3 = i3 - 1;
    }
}

and the solution is in the "solution" array. 解决方案位于“解决方案”数组中。 If the arrays are NOT sorted, a slight improvment would be to sort the three arrays individually first and then use the above algorithm. 如果未对数组进行排序,则可以稍作改进,首先对三个数组分别进行排序,然后再使用上述算法。

You can use an O(n) algorithm to solve this problem (Your code uses sorting, which is O (n log n) . I haven't tested it yet, but it should work if your input arrays are unsorted. 您可以使用O(n)算法解决此问题(您的代码使用排序,即O (n log n) 。我尚未测试过,但是如果您的输入数组未排序,它应该可以工作。

vector<int> getTop3(vector<int> A) {
    vector<int> top3;
    int max1 = A[0];
    int max2 = A[0];
    int max3 = A[0];
    for (unsigned i = 0; i < A.size(); i++) {
        if (max1 > A[i]) {
            max3 = max2;
            max2 = max1;
            max1 = A[i];
        }
        else if (max2 > A[i]) {
            max3 = max2;
            max2 = A[i];
        }
        else if (max3 > A[i]) {
            max3 = A[i];
        }
    }

    top3.push_back(max1);
    top3.push_back(max2);
    top3.push_back(max3);

    return top3;
}

Then in your main function: 然后在您的主要功能中:

temp.insert(temp.end(), getTop3(v1).begin(), getTop3(v1).end());
temp.insert(temp.end(), getTop3(v2).begin(), getTop3(v2).end());
temp.insert(temp.end(), getTop3(v3).begin(), getTop3(v3).end());

vector<int> ans = getTop3(temp);

Basically, it finds top three elements from each of the three input vectors/arrays and insert these nine elements in the temp array. 基本上,它从三个输入向量/数组的每一个中找到前三个元素,并将这九个元素插入temp数组。 Then it finds the top three elements from the temp array, which is the ans. 然后,它从temp数组中找到最上面的三个元素,即ans。

You can have a small function that returns the max of three and call it in a smart way: 您可以使用一个小函数,该函数最多返回三个并以一种聪明的方式调用它:

#define max(a, b) ((a) > (b)) ? (a) : (b)

int maxofthree(int a, int b, int c)
{
    return max(max(a, b), c);
}

count = 0;

do {
    int val = maxofthree(a1[last1], a2[last2], a3[last3]);
    printf("%d\n", val);
    count ++;

    if (val == a1[last1]) {
        last1 --;
    } else if (val1 == a2[last2]) {
        last2 --
    } else {
        last3 --;
    }
} while (count <= 5);

This is quite similar to the old puzzle of the least number of races to find the top 5 horses given that you can race only three of them at a time. 鉴于您一次只能参加三匹比赛,因此这与寻找最少5匹比赛的最少比赛的古老难题非常相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM