我有四组数据:
//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(所以总输入为7 2),然后结果应为
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
然后我添加第3个输入5(所以总输入为7 2 5),那么结果应该是
from group 1
7 2 5
from group 2
//nothing
from group 3
//nothing
from group 4
//nothing
这似乎是我需要森林(几棵树),对吗? 如果是这样,是否有任何良好的c ++树实现这个任务,或者我最好亲自制作一个?
非常感谢
答案 0 :(得分:3)
喜欢拿着数据的东西
std::set<std::vector<int> > data;
现在,如果不能保证每个组中的项目数相同,或者如果您知道每个组是特定数量的项目,那么您可以为每个组创建其中一个,然后将它们全部放入同一套。
然后将std::find_if
与上述data
的自定义谓词一起使用。在这个谓词中有一个std::vector
,这是你要查找的序列。
struct search_sequence
{
bool operator()(std::vector<int> const& cVal) const
{
if (sequence.size() <= cVal.size())
return std::equal(sequence.begin(), sequence.end(), cVal.begin());
return false;
}
std::vector<int> sequence;
};
现在使用std::find_if
应用此选项会在data
中找到以搜索序列开头的所有序列。
编辑:要存储在单个实例中,请包装矢量,例如
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;
}
};
现在你的设置包含
std::set<group_entry> data;
添加所有组的所有数据
修改谓词:
struct search_sequence
{
bool operator()(group_entry const& cVal) const
{
if (sequence.size() <= cVal.data.size())
return std::equal(sequence.begin(), sequence.end(), cVal.data.begin());
return false;
}
std::vector<int> sequence;
};
答案 1 :(得分:3)
用c ++术语表示的“树林”将是:
vector<set<string> >
集合中的字符串为“2 2 6”,“2 2 7”等
假设您只想使用前缀,并且所有数字都是一位数(或对齐到相同宽度的零),您可以在所需的前缀上使用set::lower_bound和set::upper_bound实现算法(在示例中,首先是“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;
}
}
}
}
你可以使用一个尝试向量,但是没有std库版本。
答案 2 :(得分:2)
由于深度似乎是固定的
std::map<int, std::map<int, std::set<int> > >
会做这个工作。考虑到数据项的数量,不确定它是否值得。
答案 3 :(得分:2)
以下是可能解决方案的草图:
class Group
{
int id;
std::vector<int> values;
}
您可以使用此类存储整个组(初始数据)和查询结果(应用某些过滤器后组的内容)。
使用节点和边构造树;每个节点使用Group的向量来存储该节点的结果。
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;
};
搜索时,从根开始。匹配,例如7 2,您通过遍历值为== 7的边来查找到达的根的子节点。然后,您查看该边的目标节点,并查找值为== 2的边。当您到达时在路径的最后一个节点,你有结果向量的结果。
<强>更新强> 当然,你也有构建这样一棵树的问题。您可以使用递归算法来完成它。
您从包含所有组和所有列表的根节点开始。然后,对于列表的每个第一个元素,添加具有相应节点和相应结果集的边。
您为每个子节点重复上述步骤,这次查看列表中的第二个元素。等等,直到你再也不能扩展树了。
答案 4 :(得分: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;
}
}
}
}
答案 5 :(得分:1)
字符串数组可以解决问题。每一行都是一个字符串。您可以使用分隔符装饰线条以使搜索更容易,例如“/ 7/2/2 /”而不是“7 2 2”,这样您就可以搜索“/ 2”。
我猜你的教授希望你使用更复杂的数据结构。