C++ 是否有适合解决此问题的数据结构?

C++ 是否有适合解决此问题的数据结构?,c++,data-structures,C++,Data Structures,我有四组数据: //group 1 2 2 6 2 2 7 2 3 5 2 3 6 2 3 7 3 2 5 3 2 6 3 2 7 3 3 4 3 3 5 3 3 6 3 3 7 ... ... 7 2 2 7 2 3 7 2 5 7 2 7 7 3 2 7 5 2 7 6 2 //group 2 2 2 2 2 2 3 2 2 4 2 2 5 2 3 2 2 3 3 3 3 2 3 3 3 3 4 2 ... ... 5 2 2 //group 3 2 4 2 5 3 3 3 4

我有四组数据:

//group 1
2 2 6
2 2 7
2 3 5
2 3 6
2 3 7

3 2 5
3 2 6
3 2 7
3 3 4
3 3 5
3 3 6
3 3 7
...
...
7 2 2
7 2 3
7 2 5
7 2 7
7 3 2
7 5 2
7 6 2

//group 2
2 2 2
2 2 3
2 2 4
2 2 5
2 3 2
2 3 3

3 3 2
3 3 3
3 4 2
...
...

5 2 2

//group 3
2 4
2 5

3 3
3 4
3 5
3 6
...
...
7 2

//group 4
6
7
8
我想做的是,对于给定的输入数,给出所有可能的结果。 举个例子可能有助于解释我想做什么: 假设输入为7,则输出应如下所示:

from group 1
7 2 2
7 2 3
7 2 5
7 2 7
7 3 2
7 5 2
7 6 2

from group 2
//nothing

from group 3
7 2

from group 4
7
然后我加上第二个输入2(总输入是72),结果应该是

from group 1
7 2 2
7 2 3
7 2 5
7 2 7

from group 2
//nothing

from group 3
7 2

from group 4
//nothing
from group 1
7 2 5

from group 2
//nothing

from group 3
//nothing

from group 4
//nothing
然后我加上第三个输入5(总输入是725),结果应该是

from group 1
7 2 2
7 2 3
7 2 5
7 2 7

from group 2
//nothing

from group 3
7 2

from group 4
//nothing
from group 1
7 2 5

from group 2
//nothing

from group 3
//nothing

from group 4
//nothing
看来我需要一片森林(几棵树)来做这个,对吗? 如果是这样的话,对于这项任务,森林有没有好的C++树实现呢?还是我自己动手做的更好?


非常感谢

字符串数组就可以了。每一行都是一个字符串。您可以使用分隔符来装饰这些行,使搜索更容易,例如“/7/2/2/”而不是“7/2 2”,这样您就可以搜索“/2”


我猜你的教授希望你使用更复杂的数据结构。

类似于保存数据的东西

std::set<std::vector<int> > data;
现在将其应用于
std::find_if
将查找
数据中以搜索序列开头的所有序列

编辑:要存储在单个实例中,请包装向量,例如

struct group_entry
{
  int id;
  std::vector<int> data;

  friend bool operator<(group_entry const& lhs, group_entry const& rhs)
  {
    return lhs.id < rhs.id && lhs.data < rhs.data;
  }
};
struct group\u条目
{
int-id;
std::矢量数据;

friend bool运算符因为深度似乎是固定的

std::map<int, std::map<int, std::set<int> > >
std::map

将做这项工作。尽管数据项的数量不一定值得。

< P> >“森林树木”的C++术语将是:

vector<set<string> >
向量
其中,集合中的字符串为“2 2 6”、“2 2 7”等

假设您只想使用前缀,并且所有数字都是一位数字(或者零对齐到相同的宽度),那么您可以使用您想要的前缀实现算法(在本例中,首先是“7”,然后是“7 2”,等等)

例如:

void PrintResults(const vector<set<string> >& input, const string& prefix) {
  for (int i = 0, end(input.size()); i < end; ++i) {
    cout << "from group " << i + 1 << endl;
    const set<string>& group_set = input[i];
    set<string>::const_iterator low(group_set.lower_bound(prefix)), high(group_set.upper_bound(prefix));
    if (low == high) {
      cout << "//nothing" << endl;
    } else {
      for (; low != high; ++low) {
        cout << *low << endl;
      }
    }
  }
}
void打印结果(常量向量和输入、常量字符串和前缀){
对于(int i=0,end(input.size());icout以下是一个可能的解决方案示意图:

class Group
{
    int id;

    std::vector<int> values;
}
类组
{
int-id;
std::向量值;
}
使用此类可以存储整个组(初始数据)和查询结果(应用某些筛选器后的组内容)

使用节点和边构造树;每个节点使用组向量来存储该节点的结果

class Node;

typedef Node *NodePtr;

class Edge
{
    NodePtr target;

    int value;
};

class Node
{
    // Results for each group. Maybe empty for certain groups.
    // Contains all elements for all groups in the root node.
    std::vector<Group> results;

    std::vector<Edge> children;
};
类节点;
typedef节点*NodePtr;
阶级边缘
{
NodePtr靶;
int值;
};
类节点
{
//每组的结果。某些组可能为空。
//包含根节点中所有组的所有元素。
std::矢量结果;
性病媒儿童;
};
搜索时,从根开始。要匹配,例如7 2,查找通过遍历值==7的边到达的根的子节点。然后查找该边的目标节点,并查找值==2的边。当到达路径的最后一个节点时,结果将显示在结果向量中

更新 当然,你也有构建这样一棵树的问题,你可以使用递归算法

首先从包含所有组和所有列表的根节点开始,然后,对于列表的每个第一个元素,添加一条带有相应节点和相应结果集的边


对每个子节点重复上述步骤,这一次查看列表中的第二个元素。依此类推,直到无法再扩展树。

正如其他海报所说,您需要前缀树。这里有一个简单的示例,可以让您开始,假设只包含0-7个字符。请注意,我没有添加多少安全性和数字假设给定给它的字符串后面都跟有空格(即使是最后一个),结果以相同的方式返回(这更容易)。对于真正的代码,应该涉及更多的安全性。此外,代码未编译/未测试,因此可能有错误

class number { //create a prefix node type
    number& operator=(const number& b); //UNDEFINED, NO COPY
    int endgroup;  //if this node is the end of a string, this says which group
    number* next[8];  // pointers to nodes of the next letter
public:
    number() :group(-1) { //constructor
        for(int i=0; i<8; ++i)
            next[i] = nullptr;
    }
    ~number() { // destructor
        for(int i=0; i<8; ++i)
            delete next[i];
    }
    void add(char* numbers, int group) { //add a string to the tree for a group
        if(next[numbers[0] == '\0') //if the string is completely used, this is an end
            endgroup = group;
        else {
            int index = numbers[0]-'0'; //otherwise, get next letter's node
            if (next[index] == nullptr)
                next[index] = new number; //and go there
            next[index].add(numbers+2, group); //+2 for the space
        }
    }
    void find(char* numbers, 
        std::vector<std::pair<int, std::string>>& out, 
        std::string sofar="") 
    { //find all strings that match
        if(numbers[0]) { //if there's more letters 
            sofar.append(numbers[0]).append(' '); //keep track of "result" thus far
            int index = numbers[0]-'0'; //find next letter's node
            if (next[index] == nullptr)
                return; //no strings match
            next[index].find(numbers+2, out, sofar); //go to next letter's node
        } else { //if there's no more letters, return everything!
            if (endgroup > -1) //if this is an endpoint, put it in results
                out.push_back(std::pair<int, std::string>(endgroup, sofar));
            for(int i=0; i<8; ++i) { //otherwise, try all subsequent letter combinations
                if (next[i]) {
                    std::string try(sofar);  //keep track of "result" thus far
                    try.append('0'+i).append(' ');
                    next[i].find(numbers, out, try); //try this letter
                }
            }
        }
    }
} root; //this is your handle to the tree

int main() {
    //group one
    root.add("2 2 6", 1);
    root.add("2 2 7", 1);
    //...
    //group two
    root.add("2 2 2", 2);
    //...

    std::string pattern;
    char digit;
    while(true) {
        std::cin >> digit;
        if (digit<'0' || digit > '7')
            break;
        pattern.append(digit).append(' ');
        std::vector<std::pair<int, std::string>> results;
        root.find(pattern.c_str(), results);
        for(int g=1; g<4; ++g) {
            std::cout << "group " << g << "\n";
            for(int i=0; i<results.size(); ++i) {
                if( results.first == g)
                    std::cout << results.second;
            }
        } 
    }
}
类编号{//创建前缀节点类型
编号和运算符=(常量编号和b);//未定义,无副本
int endgroup;//如果此节点是字符串的结尾,则说明是哪个组
number*next[8];//指向下一个字母的节点的指针
公众:
number():组(-1){//构造函数

对于(In i=0;Iu需要实际描述您正在使用的算法。如果我理解正确,您希望输出包含您的输出的所有行作为前缀,对吗?看起来像前缀树。C++标准库中没有一个,但我肯定您会在因特网上找到一个好的实现。听起来像是一个伟大的数据工作。base@DeadMG:我认为算法将取决于我选择使用的数据结构。如果我的示例不够清楚,请告诉我。这4组数据不一样,例如第一组和第二组总是有3个元素,第三组总是有2个元素,第四组总是有1个元素。@Gob00st,好的,在这种情况下,有一个 每个组都有数据。每个组都有数据。
find_if
。在我问这个问题之前,我知道我可以搜索4个组。我只是想知道,除了每次搜索4个组外,我是否可以使用一个数据结构来保存整个数据,并且每次只进行一次搜索?@Gob00st:好的,那么我认为前缀树就是你需要的。at每个节点都可以列出该节点的结果。@Giorgio:到目前为止,前缀树听起来是正确的方法,但我有许多不同的输入,输入可以从4或5开始。所以我可能需要一个前缀树林?
class number { //create a prefix node type
    number& operator=(const number& b); //UNDEFINED, NO COPY
    int endgroup;  //if this node is the end of a string, this says which group
    number* next[8];  // pointers to nodes of the next letter
public:
    number() :group(-1) { //constructor
        for(int i=0; i<8; ++i)
            next[i] = nullptr;
    }
    ~number() { // destructor
        for(int i=0; i<8; ++i)
            delete next[i];
    }
    void add(char* numbers, int group) { //add a string to the tree for a group
        if(next[numbers[0] == '\0') //if the string is completely used, this is an end
            endgroup = group;
        else {
            int index = numbers[0]-'0'; //otherwise, get next letter's node
            if (next[index] == nullptr)
                next[index] = new number; //and go there
            next[index].add(numbers+2, group); //+2 for the space
        }
    }
    void find(char* numbers, 
        std::vector<std::pair<int, std::string>>& out, 
        std::string sofar="") 
    { //find all strings that match
        if(numbers[0]) { //if there's more letters 
            sofar.append(numbers[0]).append(' '); //keep track of "result" thus far
            int index = numbers[0]-'0'; //find next letter's node
            if (next[index] == nullptr)
                return; //no strings match
            next[index].find(numbers+2, out, sofar); //go to next letter's node
        } else { //if there's no more letters, return everything!
            if (endgroup > -1) //if this is an endpoint, put it in results
                out.push_back(std::pair<int, std::string>(endgroup, sofar));
            for(int i=0; i<8; ++i) { //otherwise, try all subsequent letter combinations
                if (next[i]) {
                    std::string try(sofar);  //keep track of "result" thus far
                    try.append('0'+i).append(' ');
                    next[i].find(numbers, out, try); //try this letter
                }
            }
        }
    }
} root; //this is your handle to the tree

int main() {
    //group one
    root.add("2 2 6", 1);
    root.add("2 2 7", 1);
    //...
    //group two
    root.add("2 2 2", 2);
    //...

    std::string pattern;
    char digit;
    while(true) {
        std::cin >> digit;
        if (digit<'0' || digit > '7')
            break;
        pattern.append(digit).append(' ');
        std::vector<std::pair<int, std::string>> results;
        root.find(pattern.c_str(), results);
        for(int g=1; g<4; ++g) {
            std::cout << "group " << g << "\n";
            for(int i=0; i<results.size(); ++i) {
                if( results.first == g)
                    std::cout << results.second;
            }
        } 
    }
}