按公共顶部和底部排序

时间:2015-03-11 17:37:09

标签: c++ algorithm sorting variadic-templates

想象一下,元组中有n组元素。例如,元组可能是

std::tuple<topBottomStr, topBottomStr, topBottomStr> or
std::tuple<fraction, fraction, fraction>

所以也许有一些代表“topbottomthings”的模板

template<typename T>
class TopBottomThing
{
private:
    T top;
    T bottom;
};

关键在于元组中的内容具有顶部和底部的概念。我的问题是,我需要一个返回

的函数
std::vector<std::tuple<TopBottomThing>> ArrangeTopBottomThingFunc(std::vector<std::tuple<TopBottomThing>> tup)

返回值中的项目

std::vector<std::tuple<TopBottomThing>> retVal;

的排列方式是每个连续条目的TopBottomThing,std::vector<n>的底部与std::vector<n + 1>的顶部匹配,匹配std::vector<n + 2>等的底部, std::vector<n>的顶部与std::vector<n + 1>的顶部匹配, std::vector<n>的底部与std::vector<n + 1>的底部匹配。只保证一个案例作为对函数的约束。如果输入向量的长度为n,则保证0匹配或n-1匹配。

例如,如果std::vector<std::tuple<TopBottomThing>> tup表示标准分数:

2/3 4/5 3/2,

使用std::vector<tup>作为输入的ArrangeTopBottomThingFunc将返回按此标准排序一个std :: vector,如下所示:

[0] = 3/2 [1] = 2/3 [2] = 4/5(两个匹配上/下)

如果std :: tuple tup有这些分数:

4/7 3/2 1/2

[0] = 3/2 [1] = 1/2 [2] = 4/7(两个匹配底部/底部)

4/5 7/8 4/6

[0] 4/5 [1] = 4/6 [2] = 7/8(两场比赛顶/顶)

或退化案例

4/5 6/3 2/7(不匹配)

会按照给定的顺序返回。

或者说std :: tuple tup表示像这样的字符串

“Straberry / Banana”“蓝莓/猕猴桃”“Kiwi / Banana”

[0] =“Kiwi / Banana”[1] =“Straberry / Banana”[2] =“蓝莓/猕猴桃”

三个(n)顶部或底部中的至少两个保证匹配。如果算法适用于任何长度的

,那将是很好的
std::vector<std::tuple<TopBottomThing>> input. 

它只是对std :: vector进行排序和返回,其顶部/顶部,底部/底部或顶部/底部按升序排列。以这种方式不匹配的其余部分只需按任何顺序添加。

最后,如果调用函数通过返回这样的枚举来理解事物的排序方式会很好:

enum class WHICHSORT { NO_MATCHES, BOTH_TOP, BOTH_BOTTOM, MIXED_TOP_BOTTOM };

2 个答案:

答案 0 :(得分:1)

如果我正确理解您的问题,我想您要说的是,您要确定所有TopBottomThing的顶部与其他条目匹配,或者底部与其他条目匹配。然后你想用min(顶部,底部)对那些TopBottomThing进行排序。

这是我用来做这样的事情的算法。创建一个std :: map,它存储从类型T(从TopBottomThing的定义)到size_t的映射。迭代您的输入,并为每个TopBottomThing添加顶部以及底部(但仅当与顶部不同)项目添加到地图。添加新条目时,将值初始化为零。否则,增加现有值。

下一步是创建两个向量:一个用于保存匹配某些东西的TopBottomThing,另一个用于那些不匹配的向量。再次遍历TopBottomThing列表,并从地图中选择max(map [top],map [bottom])。如果该最大值至少为1,则结果与至少一个其他条目匹配,因此将其添加到匹配向量。否则,将其添加到非匹配向量。之后,对匹配向量进行排序,然后附加非匹配向量,并返回该结果。代码如下:

#include <algorithm>
#include <iostream>
#include <map>
#include <random>
#include <vector>

using namespace std;

template<class T>
class TopBottom {
public:
    T top;
    T bottom;

    TopBottom(T _top, T _bottom) : top(_top), bottom(_bottom) {
    }
};

void print(vector<TopBottom<int>> myThings) {
    for (auto topBottom = myThings.begin(); topBottom != myThings.end(); ++topBottom) {
        cout << (topBottom == myThings.begin() ? "(" : "  ");
        cout << topBottom->top << '/' << topBottom->bottom;
    }
    cout << ')';
}

template<class T>
void Arrange(vector<TopBottom<T>> &topBottoms) {
    // Determine the number of TopBottom's with each value for either top or bottom
    map<T, size_t> countOfObjects;
    for (auto topBottom = topBottoms.cbegin(); topBottom != topBottoms.cend(); ++topBottom) {
        ++countOfObjects[topBottom->top];
        if (topBottom->top != topBottom->bottom) {
            ++countOfObjects[topBottom->bottom];
        }
    }

    // Split the input into two lists; one with things that match, and the remainder
    vector<TopBottom<T>> matches;
    vector<TopBottom<T>> nonMatches;
    for (auto topBottom = topBottoms.cbegin(); topBottom != topBottoms.cend(); ++topBottom) {
        auto matchingObjectCount = max(countOfObjects[topBottom->top],
            countOfObjects[topBottom->bottom]) - 1;
        (0 < matchingObjectCount ? matches : nonMatches).push_back(*topBottom);
    }

    // Here you can sort the matches however you want

    // Populate the result
    topBottoms.clear();
    topBottoms.insert(topBottoms.end(), matches.cbegin(), matches.cend());
    topBottoms.insert(topBottoms.end(), nonMatches.cbegin(), nonMatches.cend());
}

int main(int argc, char *argv[]) {
    vector<TopBottom<int>> myThings;
    mt19937 rng;

    for (auto i = 0; i < 20; ++i) {
        myThings.clear();
        myThings.push_back(TopBottom<int>(rng() % 10, rng() % 10));
        myThings.push_back(TopBottom<int>(rng() % 10, rng() % 10));
        myThings.push_back(TopBottom<int>(rng() % 10, rng() % 10));
        myThings.push_back(TopBottom<int>(rng() % 10, rng() % 10));

        print(myThings);
        cout << "  =>  ";

        Arrange(myThings);
        print(myThings);
        cout << endl;
    }

    cin.get();
    return 0;
}

运行此代码会生成以下输出:

(2/2  5/4  1/4  5/9)  =>  (5/4  1/4  5/9  2/2)
(3/8  5/5  6/0  0/9)  =>  (6/0  0/9  3/8  5/5)
(4/9  6/7  9/9  9/3)  =>  (4/9  9/9  9/3  6/7)
(6/6  3/6  1/0  9/2)  =>  (6/6  3/6  1/0  9/2)
(8/9  5/6  3/3  8/7)  =>  (8/9  8/7  5/6  3/3)
(6/4  0/5  6/7  4/5)  =>  (6/4  0/5  6/7  4/5)
(2/7  3/8  6/0  6/2)  =>  (2/7  6/0  6/2  3/8)
(7/6  6/4  1/9  8/6)  =>  (7/6  6/4  8/6  1/9)
(0/2  2/2  3/1  2/5)  =>  (0/2  2/2  2/5  3/1)
(9/9  6/1  0/9  8/8)  =>  (9/9  0/9  6/1  8/8)
(3/8  0/9  3/6  3/2)  =>  (3/8  3/6  3/2  0/9)
(9/0  4/9  5/4  6/7)  =>  (9/0  4/9  5/4  6/7)
(1/2  4/0  9/1  5/8)  =>  (1/2  9/1  4/0  5/8)
(0/2  8/1  7/1  8/6)  =>  (8/1  7/1  8/6  0/2)
(8/7  4/6  9/2  0/8)  =>  (8/7  0/8  4/6  9/2)
(5/4  3/7  9/3  5/5)  =>  (5/4  3/7  9/3  5/5)
(5/2  0/1  6/0  1/8)  =>  (0/1  6/0  1/8  5/2)
(0/4  5/8  6/4  0/2)  =>  (0/4  6/4  0/2  5/8)
(0/3  6/9  5/5  8/5)  =>  (5/5  8/5  0/3  6/9)
(8/5  5/8  1/7  3/3)  =>  (8/5  5/8  1/7  3/3)

答案 1 :(得分:0)

只需使用std :: sort:

template<typename T>
bool MIXED_TOP_BOTTOM(const TopBottom<T>& v1,  const TopBottom<T>&v2)
{
    if( v1.bottom == v2.top )
            return true;
    return false;
}

...

std::vector<TopBottom<int> > data;

data.push_back(TopBottom<int>(2, 3));
data.push_back(TopBottom<int>(4, 5));
data.push_back(TopBottom<int>(3, 2));

std::sort(data.begin(), data.end(), MIXED_TOP_BOTTOM<int>);

产生

3/2 2/3 4/5