Unweighted directed graph dfs_iterator operator++ C++ - c++

I am working on the construction of the graph (unweighted, directed) class that accepts dfs_iterator and bfs_iterator with operations ++ to move to next value, * to get current vertex, == and != to compare the vertices. I am implementing the code in C++. The graph class is implemented using an adjacency list and it has private members vector<VType> vertices, vector<list<size_t>> adj_list and member functions add_vertex(vertex), add_edge(index1, index2), remove_edge(index1, index2), get_vertex(index), has_edge(index1, index2), get_neighbors(index) etc., and within the graph class I've implemented dfs_iterator class that does ++, *, ==, != operations. Below is the code I am trying to implement.
class graph {
private:
std::vector<VType> vertices;
std::vector<std::list<std::size_t>> adj_list;
public:
//... other member function implementations ...//
class dfs_iterator {
private:
std::vector<std::list<std::size_t >> adjList; // to hold the adj_list of graph class
std::vector<VType> vertexProp; //to hold the vertices of graph class
std::size_t index; // to keep track of current index
std::list<std::size_t>::iterator li_it; // to handle the list of each adjList[index]
public:
dfs_iterator(std::vector<std::list<std::size_t >> adj_list_, std::vector<VType> vertex_props_, std::size_t start_idx) {
this->adjList = adj_list_;
this->vertexProp = vertex_props_;
this->index = start_idx;
this->li_it = adjList[index].begin();
};
VType &operator*() {
return vertexProp[index];
};
dfs_iterator &operator++() { // explanation in the description below
if (this->li_it != adjList[index].end()) { // iterating over the depth until we hit the leaf with zero elements
this->index = *li_it; // jumping to index of list element
li_it = adjList[index].begin(); // changing the li_it to new list
} else {
/* have to handle the cases where we hit the end and search from a new branch of the parent and keep doing all the possible paths are closed. */
}
return *this;
};
};
dfs_iterator dfs_begin(std::size_t vertex_idx) {
return dfs_iterator(adj_list, vertices, vertex_idx);
};
dfs_iterator dfs_end(std::size_t vertex_idx) {
return dfs_iterator(adj_list, vertices, vertex_idx);;
};
}
}
Now, my * oepration works as expected but the ++ operator has few issues.
if my adjacency list is as mentioned below:
**index. list_of_neighbours/edges**
0. {4, 2, 6, 8}
1. {3, 5}
2. {}
3. {7}
4. {3}
5. {}
6. {}
7. {8}
8. {}
on doing
string delim = "";
for (auto it = graph.dfs_begin(0); it != graph.dfs_end(8); ++it) {
cout << delim << *it;
delim = " -> ";
}
cout << "\n";
my output is:
Traversing the graph in depth first fashion:
0 -> 4 -> 3 -> 7
as expected. but if in the 0th index, instead of {4, 2, 6, 8} my neighbors list is {2, 4, 6, 8}, then my operator++ on checking the list in index 2, which is dead, it should retreat from proceeding further and start from 2nd item of 0th index, i.e., 4 and dfs 0 -> 4 -> 3 -> 7.
I am looking for any suggestions or tips that help me proceed further. Open to answer further queries.

Related

How to remove non contiguous elements from a vector in c++

I have a vector std::vector<inputInfo> inputList and another vector std::vector<int> selection.
inputInfo is a struct that has some information stored.
The vector selection corresponds to positions inside inputList vector.
I need to remove elements from inputList which correspond to entries in the selection vector.
Here's my attempt on this removal algorithm.
Assuming the selection vector is sorted and using some (unavoidable ?) pointer arithmetic, this can be done in one line:
template <class T>
inline void erase_selected(std::vector<T>& v, const std::vector<int>& selection)
{
v.resize(std::distance(
v.begin(),
std::stable_partition(v.begin(), v.end(),
[&selection, &v](const T& item) {
return !std::binary_search(
selection.begin(), selection.end(),
static_cast<int>(static_cast<const T*>(&item) - &v[0]));
})));
}
This is based on an idea of Sean Parent (see this C++ Seasoning video) to use std::stable_partition ("stable" keeps elements sorted in the output array) to move all selected items to the end of an array.
The line with pointer arithmetic
static_cast<int>(static_cast<const T*>(&item) - &v[0])
can, in principle, be replaced with STL algorithms and index-free expression
std::distance(std::find(v.begin(), v.end(), item), std::begin(v))
but this way we have to spend O(n) in std::find.
The shortest way to remove non-contiguous elements:
template <class T> void erase_selected(const std::vector<T>& v, const std::vector<int>& selection)
{
std::vector<int> sorted_sel = selection;
std::sort(sorted_sel.begin(), sorted_sel.end());
// 1) Define checker lambda
// 'filter' is called only once for every element,
// all the calls respect the original order of the array
// We manually keep track of the item which is filtered
// and this way we can look this index in 'sorted_sel' array
int itemIndex = 0;
auto filter = [&itemIndex, &sorted_sel](const T& item) {
return !std::binary_search(
sorted_sel.begin(),
sorted_sel.end(),
itemIndex++);
}
// 2) Move all 'not-selected' to the end
auto end_of_selected = std::stable_partition(
v.begin(),
v.end(),
filter);
// 3) Cut off the end of the std::vector
v.resize(std::distance(v.begin(), end_of_selected));
}
Original code & test
If for some reason the code above does not work due to strangely behaving std::stable_partition(), then below is a workaround (wrapping the input array values with selected flags.
I do not assume that inputInfo structure contains the selected flag, so I wrap all the items in the T_withFlag structure which keeps pointers to original items.
#include <algorithm>
#include <iostream>
#include <vector>
template <class T>
std::vector<T> erase_selected(const std::vector<T>& v, const std::vector<int>& selection)
{
std::vector<int> sorted_sel = selection;
std::sort(sorted_sel.begin(), sorted_sel.end());
// Packed (data+flag) array
struct T_withFlag
{
T_withFlag(const T* ref = nullptr, bool sel = false): src(ref), selected(sel) {}
const T* src;
bool selected;
};
std::vector<T_withFlag> v_with_flags;
// should be like
// { {0, true}, {0, true}, {3, false},
// {0, true}, {2, false}, {4, false},
// {5, false}, {0, true}, {7, false} };
// for the input data in main()
v_with_flags.reserve(v.size());
// No "beautiful" way to iterate a vector
// and keep track of element index
// We need the index to check if it is selected
// The check takes O(log(n)), so the loop is O(n * log(n))
int itemIndex = 0;
for (auto& ii: v)
v_with_flags.emplace_back(
T_withFlag(&ii,
std::binary_search(
sorted_sel.begin(),
sorted_sel.end(),
itemIndex++)
));
// I. (The bulk of ) Removal algorithm
// a) Define checker lambda
auto filter = [](const T_withFlag& ii) { return !ii.selected; };
// b) Move every item marked as 'not-selected'
// to the end of an array
auto end_of_selected = std::stable_partition(
v_with_flags.begin(),
v_with_flags.end(),
filter);
// c) Cut off the end of the std::vector
v_with_flags.resize(
std::distance(v_with_flags.begin(), end_of_selected));
// II. Output
std::vector<T> v_out(v_with_flags.size());
std::transform(
// for C++20 you can parallelize this
// with 'std::execution::par' as first parameter
v_with_flags.begin(),
v_with_flags.end(),
v_out.begin(),
[](const T_withFlag& ii) { return *(ii.src); });
return v_out;
}
The test function is
int main()
{
// Obviously, I do not know the structure
// used by the topic starter,
// so I just declare a small structure for a test
// The 'erase_selected' does not assume
// this structure to be 'light-weight'
struct inputInfo
{
int data;
inputInfo(int v = 0): data(v) {}
};
// Source selection indices
std::vector<int> selection { 0, 1, 3, 7 };
// Source data array
std::vector<inputInfo> v{ 0, 0, 3, 0, 2, 4, 5, 0, 7 };
// Output array
auto v_out = erase_selected(v, selection);
for (auto ii : v_out)
std::cout << ii.data << ' ';
std::cout << std::endl;
}

N-ary Tree Level Traversal bug (C++)

I'm doing a coding challange on LeetCode and I'm asked to traverse each level and at the end return a nested vectors with values node values for each values.
So if I have a tree like:
Which is
Input: root = [1,null,3,2,4,null,5,6]
And expected output is
Output: [[1],[3,2,4],[5,6]]
The definition for the Node is as follows:
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
I'm attempting an iterative solution that is as follows:
class Solution {
public:
vector<vector<int>> answer;
stack<Node*> nodes;
vector<vector<int>> levelOrder(Node* root) {
if(root == NULL)
return answer;
nodes.push(root);
answer.push_back(vector<int>() = {root->val});
while(!nodes.empty())
{
Node* curr = nodes.top();
nodes.pop();
vector<int>temp;
for(int i = 0; i < curr->children.size(); i++)
{
nodes.push(curr->children[i]);
temp.push_back(curr->children[i]->val);
}
if(temp.size() != 0)
answer.push_back(temp);
}
return answer;
}
};
However it consistently fails 20th test case where the input is:
[1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
The expectation is:
[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]
My output is
[[1],[2,3,4,5],[9,10],[13],[8],[12],[6,7],[11],[14]]
I'm having trouble visualising and drawing this N-ary tree on paper, so I have a hard time comprehending where my algorithm went wrong.
The problem with your code is that for each node you visit, you append all its children as a new list to the answer list. Your code does not group children on the same level but with different parents into one list, as would be expected by the solution.
Let us step through your code to see what happens:
Before the loop, you push the root node onto the stack and push a singleton set with the root node value to the answer:
stack = {1}
answer = { {1} }
The first iteration pops the 1 from the stack. You then iterate over the children 2,3,4,5, which are pushed on the stack. Afterwards, the list of children is pushed to the answer list.
stack = {2,3,4,5}
answer = { {1}, {2,3,4,5} }
The next iteration pops the 5 from the stack. You then iterate over the children 9, 10. They are pushed onto the stack. Afterwards, the list of children is pushed to the answer list.
stack = {2,3,4,9,10}
answer = { {1}, {2,3,4,5}, {9, 10} }
The next iteration pops the 10 from the stack. It has no children, so nothing happens.
stack = {2,3,4,9}
answer = { {1}, {2,3,4,5}, {9, 10} }
The next iteration pops the 9 from the stack. You then iterate over the single child 13, which is pushed to the stack. A singleton list containing 13 is pushed to the answer set.
stack = {2,3,4}
answer = { {1}, {2,3,4,5}, {9, 10}, {13} }
The next iteration pops the 4 from the stack. You then iterate over the single child 8, which is pushed to the stack. A singleton list containing 8 is pushed to the answer set.
stack = {2,3,8}
answer = { {1}, {2,3,4,5}, {9, 10}, {13}, {8} }
Your can see that your answer list is wrong from here. The 8 is on the same level as 9 and 10, so it should have been added to the {9,10} sub-list in the answer list, instead of creating a new list {8}. This should be sufficient to illustrate the problem, so I will not step through the code further.
To ensure that nodes on the same level are grouped into the same sub-list in the answer list, we have to keep track of the current level when visiting each node. We can do this by extending the stack to hold pairs of the current node and its depth. Each node value at depth d will then be appended to the dth sub-list in the answer list. This ensures that nodes on the same level are grouped into one sub-list.
std::vector<std::vector<int>> get_vals_per_level(const Node *root) {
std::vector<std::vector<int>> vals_per_level{};
std::stack<std::pair<const Node *, int>> stack{};
stack.emplace(root, 0);
while (!stack.empty()) {
auto [current, depth]{stack.top()};
stack.pop();
if (vals_per_level.size() == depth) {
vals_per_level.emplace_back();
}
// Append node value to the answer list for the current depth
vals_per_level[depth].push_back(current->val);
auto& children{current->children};
for (auto it{children.rbegin()}; it != children.rend(); it++) {
stack.emplace(*it, depth + 1);
}
}
return vals_per_level;
}
The code uses structured bindings from C++17.

BFS paths C++ implementation returning return an extra value

I'm trying to implement a function using Breadth First Search to find the paths given a start and end nodes. I'm new to c++, I implemented the same in python already and it works.
With the following graph, it should give the paths {{1, 3, 6}, {1, 2, 5, 6}}:
map<int, vector<int> > aGraph = {
{1, {2, 3}},
{2, {1, 4, 5}},
{3, {1, 6}},
{4, {2}},
{5, {2, 6}},
{6, {3, 5}}
};
I created a function called BFSPaths to solve the problem, however I keep on getting an extra digit in the answer {{1, 2, 3, 6}, {1, 2, 4, 5, 6}}. I haven't been able to figure out why the 2 and the 4 are being added to the answer. This is how the functions looks like:
vector<vector<int>> BFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
vector<vector<int>> out;
vector<int> init {head};
vector<tuple<int, vector<int>>> queue = { make_tuple(head, init) };
while (queue.size() > 0)
{
int vertex = get<0>(queue.at(0));
vector<int> path = get<1>(queue.at(0));
queue.erase(queue.begin());
vector<int> difference;
sort(graph.at(vertex).begin(), graph.at(vertex).end());
sort(path.begin(), path.end());
set_difference(
graph.at(vertex).begin(), graph.at(vertex).end(),
path.begin(), path.end(),
back_inserter( difference )
);
for (int v : difference)
{
if (v == tail)
{
path.push_back(v);
out.push_back(path);
}
else
{
path.push_back(v);
tuple<int, vector<int>> temp (v, path);
queue.push_back(temp);
}
}
}
return out;
}
This is how I'm calling my function (to print to the shell):
void testBFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
vector<vector<int>> paths = BFSPaths(graph, head, tail);
for (int i=0; i<paths.size(); i++)
{
print(paths.at(i));
}
}
int main ()
{
// graph definition goes here ....
testBFSPaths(aGraph, 1, 6);
}
I would appreciate if someone can give me a push in the right direction.
As far as I understand your calculating the set difference between reachable vertices and the path to the current vertex here:
set_difference(
graph.at(vertex).begin(), graph.at(vertex).end(),
path.begin(), path.end(),
back_inserter( difference )
);
But it does not make any sense in terms of BFS. As you can see further, you are adding vertices from this difference to your answer no matter if they lies on path from head to tail or not.
You should look to another approach in this case and change your algorithm a little bit.
Steps that I would recommend:
Add the head vertex as you do, but without a path.
Extract queue's head and add all adjacent vertices to queue with a link to their predecessor.
Repeat until queue is not empty or tail is reached.
Get the path from head to tail by following links to predecessors.
Btw, I would recommend you not to use queue.erase(...) method when you want to delete a head of queue (use queue.pop() instead). And also, you can change map.at(key) method to simple map[key].
The last thing -- it looks for me not very clear why do you store adjacent vertices in vector<int> if you have to sort them often. Use smth like set<int> instead so you will not have to worry about it.
The problems was that the path was being updated path.insert(path.end(), v). I need to use a temporary path so that the original path was not needlessly changed by visited nodes during the iteration.
I also used sets (not much of a difference, it only removes the sorting step).
The function after fixed looks like this:
vector<set<int>> BFSPaths(map<int, set<int>> &graph, int head, int tail)
{
vector<set<int>> out;
set<int> init {head};
queue<tuple<int, set<int>>> aQueue;
aQueue.push( make_tuple(head, init) );
while (aQueue.size() > 0)
{
int vertex = get<0>(aQueue.front());
set<int> path = get<1>(aQueue.front());
aQueue.pop();
vector<int> difference;
set_difference(
graph[vertex].begin(), graph[vertex].end(),
path.begin(), path.end(),
back_inserter( difference )
);
for (int v : difference)
{
set<int> tempPath;
tempPath.insert(path.begin(), path.end());
tempPath.insert(tempPath.end(), v);
if (v == tail)
{
out.push_back(tempPath);
}
else
{
tuple<int, set<int>> temp (v, tempPath);
aQueue.push(temp);
}
}
}
return out;
}
The tempPath is now what's passed to the queue or added to the out vector.

Segment tree implementation

I was learning segment tree from this page : http://letuskode.blogspot.com/2013/01/segtrees.html
I am finding trouble to understand various fragments of code.I will ask them one by one.Any help will be appreciated.
Node declaration:
struct node{
int val;
void split(node& l, node& r){}
void merge(node& a, node& b)
{
val = min( a.val, b.val );
}
}tree[1<<(n+1)];
1.What will the split function do here ?
2.This code is used for RMQ . So I think that val will be the minimum of two segments and store it in some other segment.Where the value will be saved?
Range Query Function:
node range_query(int root, int left_most_leaf, int right_most_leaf, int u, int v)
{
//query the interval [u,v), ie, {x:u<=x<v}
//the interval [left_most_leaf,right_most_leaf) is
//the set of all leaves descending from "root"
if(u<=left_most_leaf && right_most_leaf<=v)
return tree[root];
int mid = (left_most_leaf+right_most_leaf)/2,
left_child = root*2,
right_child = left_child+1;
tree[root].split(tree[left_child], tree[right_child]);
//node l=identity, r=identity;
//identity is an element such that merge(x,identity) = merge(identity,x) = x for all x
if(u < mid) l = range_query(left_child, left_most_leaf, mid, u, v);
if(v > mid) r = range_query(right_child, mid, right_most_leaf, u, v);
tree[root].merge(tree[left_child],tree[right_child]);
node n;
n.merge(l,r);
return n;
}
1.What is the use of the array tree and what values will be kept there ?
2.What will this statement : tree[root].split(tree[left_child], tree[right_child]); do ?
3.What will those statements do ? :
node n;
n.merge(l,r);
return n;
Update and Merge Up functions:
I am not understanding those two functions properly:
void mergeup(int postn)
{
postn >>=1;
while(postn>0)
{
tree[postn].merge(tree[postn*2],tree[postn*2+1]);
postn >>=1;
}
}
void update(int pos, node new_val)
{
pos+=(1<<n);
tree[pos]=new_val;
mergeup(pos);
}
Also what should I write inside the main function to make this thing work?
Suppose I have an array A={2,3,2,4,20394,21,-132,2832} , How I can use this code to find RMQ(1,4)?
1.What will the split function do here ?
Nothing: the function body is empty. There may be some other implementation where an action is required. (See Example 3) And see answer to 2b
2.... Where the value will be saved?
In the "val" field of the class/struct for which "merge" is called.
1b.What is the use of the array tree and what values will be kept there ?
Array "node tree[...]" stores all the nodes of the tree. Its element type is "struct node".
2b.What will this statement : tree[root].split(tree[left_child], tree[right_child]); do ?
It calls split for the struct node that's stored at index root, passing the nodes of the split node's children to it. What it actually does to tree[root] depends on the implementation of "split".
3b.What will those statements do ? :
node n; // declare a new node
n.merge(l,r); // call merge - store the minimum of l.val, r.val into n.val
return n; // terminate the function and return n
I'll have to figure out the answers to your last Qs in the context of that code. Will take a little time.
Later
This should build a tree and do a range query. I'm not sure that the code on that page is correct. Anyway, the interface for range_query is not what you'd expect for easy usage.
int main(){
int a[] = { -132, 1, 2, 3, 4, 21, 2832, 20394};
for( int i = 0; i < 8; i++ ){
node x;
x.val = a[i];
update( i, x);
}
node y = range_query(0, 8, 15, 8 + 1, 8 + 4 );
}

Using recursion and backtracking to generate all possible combinations

I'm trying to implement a class that will generate all possible unordered n-tuples or combinations given a number of elements and the size of the combination.
In other words, when calling this:
NTupleUnordered unordered_tuple_generator(3, 5, print);
unordered_tuple_generator.Start();
print() being a callback function set in the constructor.
The output should be:
{0,1,2}
{0,1,3}
{0,1,4}
{0,2,3}
{0,2,4}
{0,3,4}
{1,2,3}
{1,2,4}
{1,3,4}
{2,3,4}
This is what I have so far:
class NTupleUnordered {
public:
NTupleUnordered( int k, int n, void (*cb)(std::vector<int> const&) );
void Start();
private:
int tuple_size; //how many
int set_size; //out of how many
void (*callback)(std::vector<int> const&); //who to call when next tuple is ready
std::vector<int> tuple; //tuple is constructed here
void add_element(int pos); //recursively calls self
};
and this is the implementation of the recursive function, Start() is just a kick start function to have a cleaner interface, it only calls add_element(0);
void NTupleUnordered::add_element( int pos )
{
// base case
if(pos == tuple_size)
{
callback(tuple); // prints the current combination
tuple.pop_back(); // not really sure about this line
return;
}
for (int i = pos; i < set_size; ++i)
{
// if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
// add element to the current combination
tuple.push_back(i);
add_element(pos+1); // next call will loop from pos+1 to set_size and so on
}
}
}
If I wanted to generate all possible combinations of a constant N size, lets say combinations of size 3 I could do:
for (int i1 = 0; i1 < 5; ++i1)
{
for (int i2 = i1+1; i2 < 5; ++i2)
{
for (int i3 = i2+1; i3 < 5; ++i3)
{
std::cout << "{" << i1 << "," << i2 << "," << i3 << "}\n";
}
}
}
If N is not a constant, you need a recursive function that imitates the above
function by executing each for-loop in it's own frame. When for-loop terminates,
program returns to the previous frame, in other words, backtracking.
I always had problems with recursion, and now I need to combine it with backtracking to generate all possible combinations. Any pointers of what am I doing wrong? What I should be doing or I am overlooking?
P.S: This is a college assignment that also includes basically doing the same thing for ordered n-tuples.
Thanks in advance!
/////////////////////////////////////////////////////////////////////////////////////////
Just wanted to follow up with the correct code just in case someone else out there is wondering the same thing.
void NTupleUnordered::add_element( int pos)
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
// add element to the current combination
tuple.push_back(i);
add_element(i+1);
tuple.pop_back();
}
}
And for the case of ordered n-tuples:
void NTupleOrdered::add_element( int pos )
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
// if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
// add element to the current combination
tuple.push_back(i);
add_element(pos);
tuple.pop_back();
}
}
}
Thank you Jason for your thorough response!
A good way to think about forming N combinations is to look at the structure like a tree of combinations. Traversing that tree then becomes a natural way to think about the recursive nature of the algorithm you wish to implement, and how the recursive process would work.
Let's say for instance that we have the sequence, {1, 2, 3, 4}, and we wish to find all the 3-combinations in that set. The "tree" of combinations would then look like the following:
root
________|___
| |
__1_____ 2
| | |
__2__ 3 3
| | | |
3 4 4 4
Traversing from the root using a pre-order traversal, and identifying a combination when we reach a leaf-node, we get the combinations:
{1, 2, 3}
{1, 2, 4}
{1, 3, 4}
{2, 3, 4}
So basically the idea would be to sequence through an array using an index value, that for each stage of our recursion (which in this case would be the "levels" of the tree), increments into the array to obtain the value that would be included in the combination set. Also note that we only need to recurse N times. Therefore you would have some recursive function whose signature that would look something like the following:
void recursive_comb(int step_val, int array_index, std::vector<int> tuple);
where the step_val indicates how far we have to recurse, the array_index value tells us where we're at in the set to start adding values to the tuple, and the tuple, once we're complete, will be an instance of a combination in the set.
You would then need to call recursive_comb from another non-recursive function that basically "starts off" the recursive process by initializing the tuple vector and inputting the maximum recursive steps (i.e., the number of values we want in the tuple):
void init_combinations()
{
std::vector<int> tuple;
tuple.reserve(tuple_size); //avoids needless allocations
recursive_comb(tuple_size, 0, tuple);
}
Finally your recusive_comb function would something like the following:
void recursive_comb(int step_val, int array_index, std::vector<int> tuple)
{
if (step_val == 0)
{
all_combinations.push_back(tuple); //<==We have the final combination
return;
}
for (int i = array_index; i < set.size(); i++)
{
tuple.push_back(set[i]);
recursive_comb(step_val - 1, i + 1, tuple); //<== Recursive step
tuple.pop_back(); //<== The "backtrack" step
}
return;
}
You can see a working example of this code here: http://ideone.com/78jkV
Note that this is not the fastest version of the algorithm, in that we are taking some extra branches we don't need to take which create some needless copying and function calls, etc. ... but hopefully it gets across the general idea of recursion and backtracking, and how the two work together.
Personally I would go with a simple iterative solution.
Represent you set of nodes as a set of bits. If you need 5 nodes then have 5 bits, each bit representing a specific node. If you want 3 of these in your tupple then you just need to set 3 of the bits and track their location.
Basically this is a simple variation on fonding all different subsets of nodes combinations. Where the classic implementation is represent the set of nodes as an integer. Each bit in the integer represents a node. The empty set is then 0. Then you just increment the integer each new value is a new set of nodes (the bit pattern representing the set of nodes). Just in this variation you make sure that there are always 3 nodes on.
Just to help me think I start with the 3 top nodes active { 4, 3, 2 }. Then I count down. But it would be trivial to modify this to count in the other direction.
#include <boost/dynamic_bitset.hpp>
#include <iostream>
class TuppleSet
{
friend std::ostream& operator<<(std::ostream& stream, TuppleSet const& data);
boost::dynamic_bitset<> data; // represents all the different nodes
std::vector<int> bitpos; // tracks the 'n' active nodes in the tupple
public:
TuppleSet(int nodes, int activeNodes)
: data(nodes)
, bitpos(activeNodes)
{
// Set up the active nodes as the top 'activeNodes' node positions.
for(int loop = 0;loop < activeNodes;++loop)
{
bitpos[loop] = nodes-1-loop;
data[bitpos[loop]] = 1;
}
}
bool next()
{
// Move to the next combination
int bottom = shiftBits(bitpos.size()-1, 0);
// If it worked return true (otherwise false)
return bottom >= 0;
}
private:
// index is the bit we are moving. (index into bitpos)
// clearance is the number of bits below it we need to compensate for.
//
// [ 0, 1, 1, 1, 0 ] => { 3, 2, 1 }
// ^
// The bottom bit is move down 1 (index => 2, clearance => 0)
// [ 0, 1, 1, 0, 1] => { 3, 2, 0 }
// ^
// The bottom bit is moved down 1 (index => 2, clearance => 0)
// This falls of the end
// ^
// So we move the next bit down one (index => 1, clearance => 1)
// [ 0, 1, 0, 1, 1]
// ^
// The bottom bit is moved down 1 (index => 2, clearance => 0)
// This falls of the end
// ^
// So we move the next bit down one (index =>1, clearance => 1)
// This does not have enough clearance to move down (as the bottom bit would fall off)
// ^ So we move the next bit down one (index => 0, clearance => 2)
// [ 0, 0, 1, 1, 1]
int shiftBits(int index, int clerance)
{
if (index == -1)
{ return -1;
}
if (bitpos[index] > clerance)
{
--bitpos[index];
}
else
{
int nextBit = shiftBits(index-1, clerance+1);
bitpos[index] = nextBit-1;
}
return bitpos[index];
}
};
std::ostream& operator<<(std::ostream& stream, TuppleSet const& data)
{
stream << "{ ";
std::vector<int>::const_iterator loop = data.bitpos.begin();
if (loop != data.bitpos.end())
{
stream << *loop;
++loop;
for(; loop != data.bitpos.end(); ++loop)
{
stream << ", " << *loop;
}
}
stream << " }";
return stream;
}
Main is trivial:
int main()
{
TuppleSet s(5,3);
do
{
std::cout << s << "\n";
}
while(s.next());
}
Output is:
{ 4, 3, 2 }
{ 4, 3, 1 }
{ 4, 3, 0 }
{ 4, 2, 1 }
{ 4, 2, 0 }
{ 4, 1, 0 }
{ 3, 2, 1 }
{ 3, 2, 0 }
{ 3, 1, 0 }
{ 2, 1, 0 }
A version of shiftBits() using a loop
int shiftBits()
{
int bottom = -1;
for(int loop = 0;loop < bitpos.size();++loop)
{
int index = bitpos.size() - 1 - loop;
if (bitpos[index] > loop)
{
bottom = --bitpos[index];
for(int shuffle = loop-1; shuffle >= 0; --shuffle)
{
int index = bitpos.size() - 1 - shuffle;
bottom = bitpos[index] = bitpos[index-1] - 1;
}
break;
}
}
return bottom;
}
In MATLAB:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% combinations.m
function combinations(n, k, func)
assert(n >= k);
n_set = [1:n];
k_set = zeros(k, 1);
recursive_comb(k, 1, n_set, k_set, func)
return
function recursive_comb(k_set_index, n_set_index, n_set, k_set, func)
if k_set_index == 0,
func(k_set);
return;
end;
for i = n_set_index:length(n_set)-k_set_index+1,
k_set(k_set_index) = n_set(i);
recursive_comb(k_set_index - 1, i + 1, n_set, k_set, func);
end;
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Test:
>> combinations(5, 3, #(x) printf('%s\n', sprintf('%d ', x)));
3 2 1
4 2 1
5 2 1
4 3 1
5 3 1
5 4 1
4 3 2
5 3 2
5 4 2
5 4 3