I have a function that is supposed to tell whether a given binary tree A is contained by a given binary tree B. The function defines "contained" as "A is covered by B, or any complete subtree of B." If, for instance, tree A is an empty tree and tree B is not, would A therefore be contained in B? What about if they're both empty?
Thanks!
In mathematic sense empty set (tree is just specialization of set) is contained in every other set including other empty set.
So yes on both your questions.
Empty set has even its wiki: http://en.wikipedia.org/wiki/Empty_set
Anyway it will become obvious from your implementation that the empty tree is contained in every other tree, an example implementation will look like this:
bool Tree::contains(const Tree& otherTree)
{
for (n: otherTree)
{
if (!contains(n))
return false;
}
return true;
}
Of course I can imagine better implementation especially when trees are sorted - but the point is that if for(n: otherTree) will cause no iterations then the result is true.
Related
I want to write a function to check if two binary trees are the same.
The code looks like:
bool checkSame(Node* first, Node* second) {
// Check if nodes are the same
// Check left nodes: checkSame(first->left, second->left)
// Check right nodes: checkSame(first->right, second->right)
}
The issue is that I'm not sure what to return here. All the implementations of DFS I've found have a void return value. Is there one where it returns a bool?
Also, I'm looking for a recursive solution, not an iterative one.
You do it in exactly the same way as if you were calling some other functions instead of recursing.
(Recursion's big secret is that there's nothing special about recursion.)
The trees are equal if and only if
the nodes are equal, and
both its subtrees are equal
so
return first->data == second->data
&& checkSame(first->left, second->left)
&& checkSame(first->right, second->right);
Handling the empty cases left as an exercise.
I have a balanced binary search tree of integers and I want to find the leftmost node which stores the integer greater or equal to a fixed number like a using a function like ask(a).
for example suppose that I have added the following points in my tree, 8,10,3,6,1,4,7,14,13
Then the tree would be like this:
now ask(1) should be 1, ask(3) should be 3, ask(2) should be 3 and so on.
I think that I can use Inorder traversal to write my ask function, But I don't know how.
Iv written this piece of code so far:
inorderFind(node->left, a);
if (node->key.getX() >= a)
return node;
inorderFind(node->right, a);
The first argument is the current tree node and a is the a that is described above. I know that I can use a bool variable like flag and set it to true when the if condition holds, and then it would prevent from walking through other nodes of the tree and returning a false node. Is there anything else that I can do?
Trees have the wonderful property of allowing queries through simple, recursive algorithms. So, let's try to find a recursive formulation of your query.
Say LEFTMOST(u) is a function which answers this question :
Given the binary search subtree rooted at node u, with(possibly null) left and
right children l and r, respectively, what is the left-most node
with a value >= a?
The relation is quite simple:
LEFTMOST(u) = LEFTMOST(l) if it exists
LEFTMOST(r) otherwise
That's it. How you translate this to your problem and how you handle concepts like "null" and "does not exist" is a function of your representation.
I understand how binary trees are implemented for most native elements such as ints or strings. So I can understand an implementation of std::set that would have a constructor like
switch(typeof(T)) // T being the typename/class in the implementation
{
case int:
{
/* create a binary tree structure that uses the bitshift operator to
add elements, e.g. 13=1101 is created as
/
/
/
/
1
/
/
/
1
\
\
0
/
1
*/
}
case string:
{
/* Do something where the string is added to a tree by going letter-by-letter
and looking whether the letter is in the second half of the alphabet (?)
*/
}
// etcetera for every imaginable type
}
but obviously this is not how std::set is actually implemented, because it is able to create a tree even when I use a homemade data structure like
struct myStruct
{
char c;
bool b;
};
std::set<myStruct> mySet;
Could it be possible to create a generic binary tree class that looks at all the bits of a data structure and does something like the int case I mentioned above?
For instance, in the case of myStruct, the size of the structure is 2 bytes of 16 bits, so a myStruct element S with S.c = '!' and S.b = true could look like
00010101 00000001
(c part) (b part)
=
\
\
0
\
\
0
\
\
0
/
/
1
\
[etcetera]
since the ASCII value for '!' is 21 and a bool = true as an int is 1. Then again, this could be inefficient to do generically because a very large data structure would correspond to a gigantic tree that might take more time to traverse then just doing a basic linear search on the elements.
Does that make sense? I'm truly confused an would love if some people here could set me straight.
What you want is a good book on templates and template meta-programming.
In short, the std::set class only defines a prototype for a class, which is then instantiated at compile-type using the provided arguments (some Key-type Key, some value-type T, which deduces std::less<Key> and std::allocator<std::pair<Key, T>> if not given, or whatever else).
A big part of the flexibility comes from being able to create partial specialisations and using other templates and default arguments.
Now, std::less is defined for many standard-library types and all basic types, but not for custom types.
There are 3 ways to provide the comparison std::map needs:
Override the default template argument and provide it to the template (if the override has state, it might make sense to provide an object to the constructor).
Specialise std::less.
Add a comparison operator (operator<).
Let's try out your example:
#include <set>
struct myStruct {
char c;
bool b;
};
int main() {
std::set<myStruct> mySet;
mySet.insert(myStruct());
}
If we compile this, we actually get an error. I've reduced the error messages to the interesting part and we see:
.../__functional_base:63:21: error: invalid operands to binary expression ('const myStruct' and 'const myStruct')
{return __x < __y;}
We can see here that std::set, to do the work it needs to do, needs to be able to compare these two objects against each other. Let's implement that:
bool operator<(myStruct const & lhs, myStruct const & rhs) {
if (lhs.c < rhs.c)
return true;
if (lhs.c > rhs.c)
return false;
return lhs.b < rhs.b;
}
Now the code will compile fine.
All of this works because std::set<T> expects to be able to compare two T objects via std::less<T> which attempts to do (T) lhs < (T) rhs.
This is highly implementation specific: actual implementations can vary here. I hope to just give you an idea of how it works.
A binary tree typically will hold actual values at each spot in the tree: your diagram makes me think the values are only present at leaf nodes (are you thinking of a trie?). Consider a string binary tree, with memebers cat, duck, goose, and dog:
dog
/ \
cat duck
\
goose
Note here that each node is a value that exists in the set. (Here, our set has 4 elements.) While perhaps you could do some sort of 0/1 prefix, you'd need to be able to convert the object to a bitstring (looking at the raw underlying bytes is not guaranteed to work), and isn't really needed.
You need to understand templates in C++; Remeber that a set<T> is "templated" on T, that is, T is whatever you specify when you use a set. (a string (set<string>, your custom struct (set<MyStruct>), etc.) Inside the implementation of set, you might imagine a helper class like:
template<typename T>
struct node {
T value;
node<T> *left, *right;
}
This structure holds a value and which node is to the left and right of it. set<T>, because it has T to use in it's implementation, can use that to also template this node structure to the same T. In my example, the bit labeled "dog" would be a node, with value being a std::string with the value "dog", left pointing to the node holding "cat", and right pointing to the node holding "duck".
When you look up a value in a set, it looks through the tree for the value, starting at the root. The set can "know" which way to go (left or right) by comparing the value you're looking for / inserting / removing with the node it's looking at. (One of the requirements for a set is that whatever you template it on be comparable with <, or you give it a function to act in place of <: so, int works, std::string works, and MyStruct can work if you either define < or write a "comparator".)
You can always compare two of a kind by comparing their byte array, no matter what.
So, if the set is represented as a sorted binary tree, a memcmp with result -1 indicates insert left, and one with +1 says, insert right.
Later
I was so eager to show that there's no need to branch according to the bits of a set element that I did not consider that there's a restriction that requires a std::set element to implement operator<.
Am I forgiven?
I would like to create an iterator over the binary tree so as to be able to use range-based for loop. I understand I ought to implement the begin() and end() function first.
Begin should probably point to the root. According to the specification, however, the end() functions returns "the element following the last valid element". Which element (node) is that? Would it not be illegal to point to some "invalid" place?
The other thing is the operator++. What is the best way to return "next" element in tree? I just need some advice to begin with this programming.
I would like to expand/augment my question*. What if I wanted to iterate over a tree with an arbitrary arity? Let each node have a vector of children and let begin() point to the "real" root. I would probably have to implement a queue (for breadth-first) inside the iterator class to store the unique_ptr's to nodes, right? Then, when the queue is empty I would know that I have passed all nodes and thus should return TreeIterator(nullptr) when oprator++() is called. Does it make sense? I want it as simple as possible and only forward iteration.
*Or should I create a new thread?
Where your begin() should point to pretty much depends on the order in which you want to traverse your tree. Using the root may be sensible, e.g., for a breadth first walk of the tree. The end() doesn't really sit on a tree node: this position is accessed and indicates that the end of the sequence is reached. Whether it indicates anything related to the tree somewhat depends on what sort of iteration you want to support: when supporting only forward iteration it can just indicate the end. When also supporting bidirectional iteration, it needs to know how to find the node right before the end.
In any case, the place pointed to isn't really accessed and you need a suitable indicator. For a forward iteration only iterator end() could just return an iterator pointing to null and when you move on from the last node you just set the iterator's pointer to null as well: equality comparing the two pointers would yield true, indicating that you have reached the end. When wanting to support bidirectional iteration you'll need some sort of link record which can be used to navigate to the previous node but which doesn't need to store a value.
The ordered associated containers (std::map<K, V>, std:set<V>, etc.) are internally implemented as some sort of tree (e.g., a Red/Black-tree). The begin() iterator starts with the left-most node and the end() iterator refers to the position after the right-most node. The operator++() just finds the next node to the right of the current:
if the iterator sits on a node without a right child node, it walks along the chain of parents until it finds a parent reaching its child via the left branch of the tree
if it sits on a node with a right child node it walks to the child and then down the sequence of left children of this child (if any) to find the left-most child in the right subtree.
Obviously, if you don't walk your tree from left to right but rather, e.g., from top to bottom, you'll need a different algorithm. The easiest approach for me is to draw a tree on a piece of paper and see how to get to the next node.
If you haven't implemented a data structure using your own iterators I'd recommend trying things out on a simple sequential data structure, e.g., a list: There it is pretty obvious how to reach the next node and when the end is reached. Once the general iteration principle is clear, creating a tree is just a matter of getting the navigation right.
Look at SGI implementation of RBTree (this is the base for std::set/std::map... containers).
http://www.sgi.com/tech/stl/stl_tree.h
You will see that begin() is the leftmost node.
You will see that end() is a special "empty" node header which is the super root - I mean a real root (preset only if the tree is not empty) is its child node.
operator ++ is to go to right child and then find this child leftmost node.
If such child does not exist - we go to left parent of the rightmost parent node. As in this example (red lines are skip move, blue ones ends are the given steps of iteration):
The code copied from SGI:
void _M_increment()
{
if (_M_node->_M_right != 0) {
_M_node = _M_node->_M_right;
while (_M_node->_M_left != 0)
_M_node = _M_node->_M_left;
}
else {
_Base_ptr __y = _M_node->_M_parent;
while (_M_node == __y->_M_right) {
_M_node = __y;
__y = __y->_M_parent;
}
if (_M_node->_M_right != __y)
_M_node = __y;
}
}
When a tree is empty - begin() is leftmost of header - so it is header itself - end() is also header - so begin() == end(). Remember - your iteration scheme must match this condition begin() == end() for empty trees.
This seems to be very smart iteration scheme.
Of course you can define you own scheme - but the lesson learned is to have special node for end() purpose.
An iterator for a tree is going to be more than just a pointer, although it will likely contain a pointer:
struct TreeIterator {
TreeIterator(TreeNode *node_ptr) : node_ptr(node_ptr) { }
TreeIterator &operator++();
TreeIterator operator++(int);
bool operator==(const TreeIterator &) const;
private:
TreeNode *node_ptr;
};
TreeIterator begin(const Tree &tree) { ... }
TreeIterator end(const Tree &tree) { ... }
You can make your end() function return something special, like TreeIterator(nullptr)
What your begin iterator points to will depend on the type of traversal that you want. If you are doing breadth-first traversal, then starting at the root makes sense.
In this question I'm not asking how to do it but HOW IS IT DONE.
I'm trying (as an excersise) implement simple map and although I do not have problems with implementing links and they behavior (how to find next place to insert new link etc.) I'm stuck with the problem how to implement iterating over a map. When you think about it and look at std::map this map is able to return begin and end iterator. How? Especially end?
If map is a tree how can you say which branch of this map is an end? I just do not understand it. An how to iterate over a map? Starting from the top of the tree and then what? Go and list everything on the left? But those nodes on the left have also links to the right. I really don't know. I will be really glad if someone could explain it to me or give me a link so I could read about it.
A map is implemented using a binary search tree. To meet the complexity requirements it has to be a self-balancing tree, so a red-black tree is usually used, but that doesn't affect how you iterate over the tree.
To read the elements out of a binary search tree in order from least to greatest, you need to perform an in-order traversal of the tree. The recursive implementation is quite simple but isn't really practical for use in an iterator (the iterator would have to maintain a stack internally, which would make it relatively expensive to copy).
You can implement an iterative in-order traversal. This is an implementation taken from a library of tree containers I wrote a while ago. NodePointerT is a pointer to a node, where the node has left_, right_, and parent_ pointers of type NodePointerT.
// Gets the next node in an in-order traversal of the tree; returns null
// when the in-order traversal has ended
template <typename NodePointerT>
NodePointerT next_inorder_node(NodePointerT n)
{
if (!n) { return n; }
// If the node has a right child, we traverse the link to that child
// then traverse as far to the left as we can:
if (n->right_)
{
n = n->right_;
while (n->left_) { n = n->left_; }
}
// If the node is the left node of its parent, the next node is its
// parent node:
else if (n->parent_ && n == n->parent_->left_)
{
n = n->parent_;
}
// Otherwise, this node is the furthest right in its subtree; we
// traverse up through its parents until we find a parent that was a
// left child of a node. The next node is that node's parent. If
// we have reached the end, this will set node to null:
else
{
while (n->parent_ && n == n->parent_->right_) { n = n->parent_; }
n = n->parent_;
}
return n;
}
To find the first node for the begin iterator, you need to find the leftmost node in the tree. Starting at the root node, follow the left child pointer until you encounter a node that has no left child: this is the first node.
For an end iterator, you can set the node pointer to point to the root node or to the last node in the tree and then keep a flag in the iterator indicating that it is an end iterator (is_end_ or something like that).
The representation of your map's iterator is totally up to you. I think it should suffice to use a single wrapped pointer to a node. E.g.:
template <typename T>
struct mymapiterator
{
typename mymap<T>::node * n;
};
Or something similar. Now, mymap::begin() could return such instance of the iterator that n would point to the leftmost node. mymap::end() could return instance with n pointing to root probably or some other special node from which it is still possible to get back to rightmost node so that it could satisfy bidirectional iteration from end iterator.
The operation of moving between the nodes (operators++() and operator--(), etc.) are about traversing the tree from smaller to bigger values or vice versa. Operation that you probably have already implemented during insertion operation implementation.
For sorting purposes, a map behaves like a sorted key/value container (a.k.a. a dictionary); you can think of it as a sorted collection of key/value pairs, and this is exactly what you get when you query for an iterator. Observe:
map<string, int> my_map;
my_map["Hello"] = 1;
my_map["world"] = 2;
for (map<string, int>::const_iterator i = my_map.begin(); i != my_map.end(); ++i)
cout << i->first << ": " << i->second << endl;
Just like any other iterator type, the map iterator behaves like a pointer to a collection element, and for map, this is a std::pair, where first maps to the key and second maps to the value.
std::map uses a binary search internally when you call its find() method or use operator[], but you shouldn't ever need to access the tree representation directly.
One big trick you may be missing is that the end() iterator does not need to point to anything. It can be NULL or any other special value.
The ++ operator sets an iterator to the same special value when it goes past the end of the map. Then everything works.
To implement ++ you might need to keep next/prev pointers in each node, or you could walk back up the tree to find the next node by comparing the node you just left to the parent's right-most node to see if you need to walk to that parent's node, etc.
Don't forget that the iterators to a map should stay valid during insert/erase operations (as long as you didn't erase the iterator's current node).