Construct Binary Search Trees efficiently - c++

I have already some sort of solution for the problem:
Given an integer N, construct all possible binary search trees with N nodes.
except that I include trees with root the minimum and maximum value but this is not my main concern.
I want to put emphasis into correctly using the move semantics and memory management in C++ (as a learning exercice).
My solution is:
#include <vector>
struct Node{
int value;
Node *left = nullptr;
Node *right = nullptr;
};
std::vector<Node*> createListNodes(int min, int max)
{
// ordered vector with i.e. {0,1,2,3,4}
Node *node = new Node;
if (min == max)
{
node->value = min;
return std::vector<Node*> {node}; // it is a leaf node
}
std::vector<Node*> alterantive{};
for (int i=min; i<=max; i++)
{
auto left = createListNodes(min,i-1); // for the left side
auto right = createListNodes(i+1,max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,nullptr,elem_right});
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto elem_left : left)
{
alterantive.emplace_back(new Node{i,elem_left,nullptr});
}
}
for (auto elem_left : left)
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,elem_left,elem_right});
}
}
}
return alterantive;
}
int main()
{
int N = 4;
std::vector<Node*> combinations = createListNodes(0, N);
}
So would like to know:
Improvements I could made to my basic design, I would prefer not to use smart pointers yet but the raw ones, to make it more memory efficient (copying less values from one side to the other ...)
General improvements in the code, even though my main focus is on memory management, memory leaks ...

Related

Make RadixSort with linked lists on C++

I'm learning C++ and learning linked lists. I'm currently trying to make a radix sort for this type of lists, but my approach is not working so I was wondering if anyone could advice me on how to do it. Here's my code:
void simpleList::radixSort() {
for (int i = 0; i < numberOfDigits(); i++){
Node * tmp = firstNode;
for (int j = 0; j < counter(); j++){
int pow = 10;
for (int k = 0; k < 10; k++){
if (tmp -> data % pow == k){
insertFirst(tmp->data);
tmp = tmp -> next;
}
pow= pow * 10;
}
}
}
}
The function numberOfDigits() gets you the amount of digits on the max number of the list, and counter() the amount of elements in the list. Also insertFirst() puts the number at the beggining of the list.
A few notes to help you on your way:
Radix Sort
A radix sort is any kind of (stable n-ary bucket sort) repeated until you run out of digits in your sort keys. Make your life simple: use binary as your radix.
Keys
You are using int values in your list, but that need not be the case. In general, you need a value→key function that returns an integer key for each element of your list, where “equivalent” elements return the same key. For a list of integers the value→key function is the identity function, so easy enough.
For convenience, I will use lambdas for the value→key functions below.
Reducing Passes
You can reduce the number of times you bucket sort to only those bits that are not the same for all keys. Before the first pass through your list, you do not know anything about the keys, so we can gather information at the same time as the first bucket sort:
key_type key_mask = 0; // bits to sort
key_type common_mask = ~0; // (bits set in all keys)
auto value_to_bucket_fn = [&]( const T & element )
{
// here we gather information about the keys
key_type key = user_supplied_value_to_key_fn( element );
key_mask |= key;
common_mask &= key;
// here we return our first bucket key == bit 0
return key & 1;
};
binary_bucket_sort( value_to_bucket_fn );
Once we have made that first pass, we can get a bitmask indicating which bits need sorting in our keys:
key_mask ^= common_mask; // key_mask ← set bits == bits to sort
All remaining passes can now be managed with a simple loop, ending when we run out of bits needing sorting:
for (int shift = 1; key_mask >>= 1; shift++)
if (key_mask & 1)
binary_bucket_sort( [&]( const T & element )
{
return (user_supplied_value_to_key_fn( element ) >> shift) & 1;
} );
Bucket Sort
A linked list is perfect for bucket sorts of large, unwieldly objects. Remember: the bucket sort must be stable, meaning it must not mix up the order of “equivalent” elements. This is imperative for a radix sort to work properly.
For a binary bucket sort over a linked list, life is pretty simple — only two buckets are necessary, and you only need keep track of the last node in each bucket to append.
If you are using a doubly-linked list that bookkeeping is done for you. If you are using a singly-linked list you will have to do it manually.
Node heads[2] = { Node{}, Node{} };
Node * tails[2] = { &heads[0], &heads[1] };
while (head)
{
int bucket = value_to_bucket_fn( head->data );
tails[bucket]->next = head; // append current head to correct bucket
tails[bucket] = head; // bucket’s new tail is the current head
head = head->next; // pop current head; get new current head
}
Hopefully you can see how easy this would be to expand to any number of buckets. Still, we will stick with two.
Once you have split all the nodes into the two buckets, just join them back together into your new complete list. Don’t forget to clean up the tail’s next pointer!
head = heads[0]->next;
tails[0]->next = heads[1]->next;
tails[1]->next = nullptr;
Be sure to check out trincot’s answer to see how he defined his singly-linked list with a lastNode pointer and useful functions to make all this splitting into buckets (“partitions”) and joining the final list into invocations of very inexpensive member functions.
Generics
This answer spends some time going on about keys and non-integer values. I have defined my list type’s nodes as:
struct node_type
{
T data;
node_type * next;
};
And I have defined the sorting functions as:
template <typename ValueToBucket>
void binary_bucket_sort( ValueToBucket value_to_bucket );
template <typename ValueToKey>
void radix_sort( ValueToKey value_to_key );
Then, when I sorted my test lists, I used variations of:
list <int> xs;
...
xs.radix_sort( []( int x ) { return x; } );
You can do things like observe the stability in the sort by playing with the value→key function (lambda). For example, I could define a list of integers where the one’s digit didn’t matter:
xs.radix_sort( []( int x ) { return x / 10; } );
Or a list of floats where the fractional part only mattered to two decimal places:
xs.radix_sort( []( double x ) { return static_cast <long long> ( x * 100 ); } );
I could have a list of Student where I am only interested in sorting by the student’s ID:
xs.radix_sort( []( const Student & student ) { return student.ID; } );
As long as the value→key function returns a sufficiently unique integer value we can use radix sort.
The main problem in your approach is that the only thing that can happen with a node is that it eventually gets moved to the start of the list. But there is nothing else that can happen with a node. For instance, there is no logic that leaves a node where it is and then moves on to the next. Instead the code keeps looking at the same node until it can be moved. It should be clear that this cannot result in a sorted order.
Secondly, if you are using radix 10, you will need 10 different possible destinations for a node ("buckets"), depending on the digit that is inspected. These would be linked lists as well, but you need to somehow manage them. Then when all nodes have been distributed over this buckets, the buckets should be joined again into a single list.
I would suggest using radix 2. Then you only need two "buckets". Also, I would suggest to keep track of the last node in a list (if you haven't already done so), with a lastNode member in your class.
Here is an implementation with radix 2 and the use of two bucket linked lists in each pass:
#include <iostream>
#include <vector>
class Node {
public:
Node *next = nullptr;
int data;
Node (int data): data(data) {};
Node (int data, Node *next): data(data), next(next) {};
};
class simpleList {
public:
Node *firstNode = nullptr;
Node *lastNode = nullptr;
simpleList() {}
simpleList(std::vector<int> data) {
for (auto value: data) {
append(value);
}
}
void clear() { // Does not free nodes
firstNode = lastNode = nullptr;
}
// Three variants of append. To append:
// * A node
// * A value, for which a Node will be created
// * Another linked list, which will be emptied
void append(Node *node) {
if (!firstNode) {
firstNode = node;
} else {
lastNode->next = node;
}
lastNode = node;
node->next = nullptr;
}
void append(int data) {
append(new Node(data));
}
void append(simpleList *other) {
if (firstNode) {
lastNode->next = other->firstNode;
} else {
firstNode = other->firstNode;
}
if (other->firstNode) {
lastNode = other->lastNode;
other->clear();
}
}
Node *popFirstNode() {
auto node = firstNode;
if (firstNode) {
firstNode = firstNode->next;
if (!firstNode) {
lastNode = nullptr;
}
node->next = nullptr;
}
return node;
}
void print() {
auto node = firstNode;
while (node) {
std::cout << node->data << " ";
node = node->next;
}
std::cout << "\n";
}
void radixSort() {
bool hasMoreBits = true;
simpleList *partitions[] = {new simpleList(), new simpleList()};
for (int bit = 0; hasMoreBits; bit++) {
hasMoreBits = false;
while (firstNode) {
hasMoreBits |= ((firstNode->data >> bit) >> 1) != 0;
int digit = (firstNode->data >> bit) & 1;
partitions[digit]->append(popFirstNode());
}
append(partitions[0]);
append(partitions[1]);
}
}
};
// Demo
int main() {
auto list = new simpleList({4, 9, 1, 2, 6, 8, 3, 7, 5});
list->print();
list->radixSort();
list->print();
}
Example of a base 256 (8 bit) radix sort for linked list using 64 bit unsigned integers for data. The list structure used in the code uses a pointer to pointer for the tail to simplify the code. A base 256 (8 bit, 8 sort passes) is about 8 times as fast as a base 2 (single bit, 64 sort passes) radix sort.
typedef struct NODE_{ // node struct
struct NODE_ * next;
uint64_t data;
}NODE;
typedef struct LIST_{ // list struct
NODE * phead;
NODE ** pptail;
}LIST;
NODE * RadixSort(NODE * plist)
{
LIST alist[256]; // array of lists
NODE *pnode = plist;
uint32_t i, j, k;
size_t x;
for(k = 0; k < 64; k += 8){ // radix sort
for (i = 0; i < 256; i++) { // reset alist
alist[i].phead = 0;
alist[i].pptail = &alist[i].phead;
}
pnode = plist; // split into lists
while(pnode){
x = ((pnode->data) >> k) & 0xff;
*(alist[x].pptail) = pnode;
alist[x].pptail = &(pnode->next);
pnode = pnode->next;
}
// // concatenate lists
for(i = 0; alist[i].phead == 0; i++);
plist = alist[i].phead;
j = i;
for(++i; i < 256; ++i){
if(alist[i].phead == 0)
continue;
*(alist[j].pptail) = alist[i].phead;
j = i;
}
*(alist[j].pptail) = 0;
}
return plist;
};

Implicitly copied constructor Smart Pointers

I have the following code:
#include <vector>
#include <memory>
struct Node{
int value;
Node *left = nullptr;
Node *right = nullptr;
};
std::vector<std::unique_ptr<Node>> createListNodes(int min, int max)
{
// odered vector with i.e. {0,1,2,3,4}
std::vector<std::unique_ptr<Node>> alternative;
if (min == max)
{
alternative.emplace_back(std::make_unique<Node>(min,nullptr,nullptr)); // it is a leaf node
return alternative;
}
for (int i=min; i<=max; i++)
{
std::vector<std::unique_ptr<Node>> left = createListNodes(min,i-1); // for the left side
std::vector<std::unique_ptr<Node>> right = createListNodes(i+1,max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto elem_right : right) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,nullptr,elem_right));
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto elem_left : left) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,elem_left,nullptr));
}
}
for (auto elem_left : left) // ERROR
{
for (auto elem_right : right) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,elem_left,elem_right));
}
}
}
return alternative;
}
int main()
{
int N = 4;
std::vector<std::unique_ptr<Node>> combinations = createListNodes(0, N);
}
I am receiving an error when iterating over the vector of unique_ptr but I do not manage to understand the real problem. I have tried as well moving the unique_ptr to the vector alternative but the problem still persists.
error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<Node,
std::__1::default_delete<Node> >'
for (auto elem_left : left)
You might do something like:
You have several issue, you iterate over copy, instead of reference.
lifetime of inner nodes stop at each loop iteration.
You can make nodes own its children:
struct Node{
int value;
std::unique_ptr<Node> left = nullptr;
std::unique_ptr<Node> right = nullptr;
Node(int v, std::unique_ptr<Node> left = nullptr, std::unique_ptr<Node>right = nullptr) :
value(v), left(std::move(left)), right(std::move(right))
{}
std::unique_ptr<Node> DeepCopy() const
{
return std::make_unique<Node>(value,
left ? left->DeepCopy() : nullptr,
right ? right->DeepCopy() : nullptr);
}
};
std::vector<std::unique_ptr<Node>> createListNodes(int min, int max)
{
// odered vector with i.e. {0,1,2,3,4}
std::vector<std::unique_ptr<Node>> alternative;
if (min == max)
{
alternative.emplace_back(std::make_unique<Node>(min, nullptr, nullptr)); // it is a leaf node
return alternative;
}
for (int i=min; i<=max; i++)
{
std::vector<std::unique_ptr<Node>> left = createListNodes(min, i-1); // for the left side
std::vector<std::unique_ptr<Node>> right = createListNodes(i+1, max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto& elem_right : right)
{
alternative.emplace_back(std::make_unique<Node>(i, nullptr, std::move(elem_right)));
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto& elem_left : left)
{
alternative.emplace_back(std::make_unique<Node>(i, std::move(elem_left), nullptr));
}
}
for (auto& elem_left : left)
{
for (auto& elem_right : right)
{
alternative.emplace_back(std::make_unique<Node>(i, elem_left->DeepCopy(), elem_right->DeepCopy()));
}
}
}
return alternative;
}
Demo (with std::unique_ptr)
Demo (with std::shared_ptr)

Why a tree structure takes more space than a sum of it's nodes

Populating the following n-ary tree data structure creates 64'570'080 nodes, which should take ~1480mb of memory space (24 byte per node for x64 build). But the actual memory footprint of the program is ~1900mb (as both Visual Studio and the task manager indicate). When I don't populate a tree, but push the same amount of nodes into a vector, the footprint is ~1480mb as expected.
Why the tree takes more space than the same amount of nodes in a vector and how can I fix it? I use the latest MSVC compiler.
struct Node
{
public:
void AddChild()
{
if (first_child_ == nullptr)
{
first_child_ = std::make_unique<Node>();
first_child_->parent_ = this;
}
else
{
Node* next = first_child_.get();
while (next->next_sibling_ != nullptr)
{
next = next->next_sibling_.get();
}
next->next_sibling_ = std::make_unique<Node>();
next->next_sibling_->parent_ = this;
}
}
class NodeRange;
NodeRange GetChildren();
Node* GetNextSibling() { return next_sibling_.get(); }
private:
// Pointer to the parent node. nullptr for the root.
Node* parent_ = nullptr;
// Pointer to the first child. nullptr for a leaf node.
std::unique_ptr<Node> first_child_;
// Pointer to the next sibling. nullptr if there are no further siblings.
std::unique_ptr<Node> next_sibling_;
};
class NodeIterator
{
public:
NodeIterator(Node* node) : node_(node) {}
Node* operator*() { return node_; }
Node* operator->() { return node_; }
bool operator==(NodeIterator& other) { return node_ == other.node_; }
bool operator!=(NodeIterator& other) { return node_ != other.node_; }
void operator++() { node_ = node_->GetNextSibling(); }
private:
Node* node_;
};
class Node::NodeRange
{
public:
NodeIterator begin() { return NodeIterator(node_); }
NodeIterator end() { return NodeIterator(nullptr); }
private:
NodeRange(Node* node) : node_(node) {}
Node* node_;
friend class Node;
};
Node::NodeRange Node::GetChildren() { return first_child_.get(); }
#define MAX_DEPTH 16
#define BRANCHING_FACTOR 3
std::unique_ptr<Node> tree;
size_t nodeCount = 0;
void Populate(Node& node, int currentDepth = 0)
{
if (currentDepth == MAX_DEPTH) return;
for (size_t i = 0; i < BRANCHING_FACTOR; i++)
{
node.AddChild();
nodeCount++;
}
for (Node* child : node.GetChildren())
{
Populate(*child, currentDepth + 1);
}
}
int main()
{
tree = std::make_unique<Node>();
Populate(*tree.get());
std::cout << "Nodes: " << nodeCount << "\n";
std::cout << "Node size: " << sizeof(Node) << "\n";
std::cout << "Estimated tree size, bytes: " << (nodeCount * sizeof(Node)) << "\n";
std::cout << "Estimated tree size, mb: " << (nodeCount * sizeof(Node) / 1024.0 / 1024.0) << "\n";
}
Since each tree node is allocated separately, there is an overhead to each heap memory allocation, the heap allocator stores its housekeeping information along with each allocated block. On a 64-bit system that overhead is 8 bytes for GNU malloc, MSVC run-time library may have a different non-zero overhead (but it looks to be 8 bytes as well). See MallocInternals for more details.
One way to minimize the overhead is to allocate the tree nodes from a large pre-allocated array. An example is boost::pool.
Using std::unique_ptr for storing child nodes may cause stack overflow due to recursive calls: ~Node() invokes first_child_->~std::unique_ptr<Node>() which invokes ~Node(), which invokes first_child_->~std::unique_ptr<Node>() and so on, which may overflow the stack.
One solution is for first_child_ and next_sibling_ to be plain Node* pointers, and implement class Tree and code in ~Tree() that walks the tree without recursion and destroys tree nodes manually. In this case Tree owns its Nodes.

How to create a function that returns smallest value of an unordered binary tree

This seems like it should be really easy but I've been having trouble with this for quite some time. As the title says, I'm just trying to find the node in a Binary tree (not a BST!) with the smallest value and return it. I can write a recursive void function pretty easily that can at least assign the smallest value in the function, but I'm getting stuck on how to back track to previous nodes once I reach a NULL pointer.
I have a node class that has a pointer to a left and right child, each with its own value. Here is my (failed) attempt so far:
int preOrder(Node *node, int value, int count, int sizeOfTree)
{
count++; //keeps track of whether or not we have traversed the whole tree
if(value < node->getValue())
value = node->getValue();
if(count == sizeOfTree);
return value;
if(node == NULL)
//Want to return to the previous function call
//How do I do this for a non void function?
//for a void function, you could jsut type "return;" and the function
//back tracks to your previous place in the tree
//but since I'm returning a value, How would I go about doing this?
//these 2 calls are incorrect but the idea is that I first traverse the left subtree
//followed by a traversal of the right subtree.
preOrder(node->getLeft(), value);
preOrder(node->getRight(), value);
}
If possible, I would like to try and do this without keeping track of a "count" as well to make the code cleaner.
Let me know if anymore clarification is needed.
I don't really understand why, in your original code, you need to keep track of the amount of elements traversed. Here is my solution:
int find_min(Node* node)
{
int value = node->getValue()
Node* left_node = node->getLeft();
if (left_node != NULL)
{
int left_value = find_min(left_node);
if (left_value < value)
value = left_value;
}
Node* right_node = node->getRight();
if (right_node != NULL)
{
int right_value = find_min(right_node);
if (right_value < value)
value = right_value;
}
return value;
}
Basically what you need to do is just visit every node and keep track of the smallest value you've seen. This can actually be done fairly simply:
#include <algorithm>
#include <limits>
int preOrder(Node *node)
{
if(node == NULL) return std::numeric_limits<int>::max();
// this should never affect the calculation of the minimum
// (What could possibly be bigger than INT_MAX? At worst it's equal)
int value = std::min(
node->getValue(),
preOrder(node->getLeft())
);
value = std::min(
value,
preOrder(node->getRight())
);
return value;
}
OK, so you have an unordered binary tree and you're trying to find the lowest element in it.
Since the tree is unordered, the lowest element can be at any position in the tree, so you must search the entire tree.
The characteristics of the search will be as follows:
thorough (whole tree is searched)
recursive (rather than iterative, which would be really yucky)
base case: node is NULL
base outcome: maintain current value
Lets write it then:
#include <algorithm>
using namespace std;
int searchLowest(Node * node, int value = INT_MAX)
{
if (node == NULL) // base case
return value; // base outcome
// at this point, node must not be NULL
value = min(value, preOrder(node->getRight(), value)); // thorough, always recurse
value = min(value, preOrder(node->getLeft (), value)); // and check children
value = min(value, node->getValue());
return value;
}
Edit for thoroughness, justice, and OOness:
// Node.h
#include <algorithm>
using namespace std;
template <typename T>
class Node
{
public:
Node(T item)
{
data = item;
}
T lowest()
{
T value = data;
if (right != NULL)
value = min(value, right->lowest());
if (left != NULL)
value = min(value, left->lowest());
return value;
}
Node<T> * getRight()
{
return right;
}
Node<T> * getLeft()
{
return left;
}
private:
T data;
Node<T> * right;
Node<T> * left;
};
// main.cpp
#include <iostream>
#include "Node.h"
using namespace std;
int main(int c, char * v[])
{
Node<int> * tree = sycamore(); // makes a nice big tree
cout << tree->lowest();
}
SEE JIMMY RUN

How to convert a binary search tree into a doubly linked list?

Given a binary search tree, i need to convert it into a doubly linked list(by traversing in zig zag order) using only pointers to structures in C++ as follows,
Given Tree:
1
|
+-------+---------+
| |
2 3
| |
+----+---+ +----+---+
| | | |
4 5 6 7
| | | |
+--+--+ +--+--+ +--+--+ +--+--+
| | | | | | | |
8 9 10 11 12 13 14 15
Node Structure:
struct node
{
char * data;
node * left;
node * right;
};
Create List(zig zag order):
1 <-> 3 <-> 2 <-> 4 <-> 5 <-> 6 <-> 7 <-> 15 <-> ... <-> 8
Could someone please help me out.
This is a Breadth-first search algorithm. Wikipedia has a good explanation on how to implement it.
After implementing the algorithm, creating your linked list should be a no-brainer (since it will only be a matter of appending each visited element to the list)
That's an awkward type of tree traversal. I wonder how often anyone has ever actually needed to do such a thing in real code. Nevertheless, it's the problem to be solved here...
Here's how I would approach dealing with this:
First, when I compare the desired output to the structure of the tree, I notice that each "level" of the tree is processed in turn from top to bottom. So top node first, then all child nodes, then all grand-child notes, and so on. So probably a good solution will involve a loop that processes one level and at the same time builds up a list of nodes in the next level to be used in the next iteration of the loop.
Next, this "zig zag" order means it needs to alternate which direction the child nodes are processed in. If a particular iteration goes from left to right, then the next iteration must go from right to left. And then back to left to right for the subsequent iteration and so on. So in my idea of a loop that processes one level and builds a list of the next level, it probably needs to have some sort of alternating behavior when it builds that list of nodes for the next level. On even iterations the list is built one way. On odd iterations the list is built the other way.
Alternatively, another other way to think about this whole thing is: Design a solution to that can build the result list in 1,2,3,4,5,6,etc order. Then modify that design to have the zig zag order.
Does this give you enough of an idea on how to design a solution?
This might help you:
Create a separate list for every level of the tree
Traverse the tree and copy the values to the lists as you traverse the tree
Reverse the order of every other list
Connect the lists
In this solution below I have used two stacks to store Levels alternatively.
say nodes at level 0 will be store in stack 1 whose name is head1;now pop the element while it not become empty and push the elements in stack 2.the order i.e left or right child of insertion will depend on the level.and change the insertion order at each level.
node * convert_to_dll(node *p)
{
static int level=0;
push_in_stack(p,&head1);
printf("%d\n",p->data);
while( head1!=NULL || head2!=NULL) {
//pop_from_queue(&headq);
if(head1!=NULL && head2==NULL) {
while(head1!=NULL) {
if(level%2==0) {
node *p;
p=new node;
p=pop_from_stack(&head1);
if(p->right!=NULL) {
push_in_stack(p->right,&head2);
printf("%d\n",(p->right)->data);
}
if(p->left!=NULL)
{
push_in_stack(p->left,&head2);
printf("%d\n",(p->left)->data);
}
}
}
//traverse_stack(head2);
level++;
} else {
while(head2!=NULL) {
if(level%2!=0) {
node *q;
q=new node;
q=pop_from_stack(&head2);
if(q->left!=NULL) {
push_in_stack(q->left,&head1);
printf("%d\n",(q->left)->data);
}
if(q->right!=NULL) {
push_in_stack(q->right,&head1);
printf("%d\n",(q->right)->data);
}
}
} //traverse_stack(head2);
level++;
}
}
return p;
}
you can write a function to add nodes in a doubly linked list. You can then call this function while traversing the tree. In this way you should be able to do it.
Hmm... This is a tough one. The problem with traversal in this order is that you are doing a lot of skipping around. This is generally true in any tree traversal order that is not depth or breadth first.
Here's how I would resolve the situation. Start with a single, empty array of lists of nodes and begin traversing the tree depth first. Be sure to keep track of the depth of your traversal.
At each point in traversal, note the depth of your traversal and pick the list at the index in the array. If there isn't one there, add it first. If the depth is even (Assuming root has depth 0), add the node to the end of the list. If it's odd, add it to the beginning.
Once you've traversed all nodes, concatenate the lists.
Why use pointers?? You could just store your BST as an array A[1...n]. So, A[1] would have root, A[2] and A[3] would have nodes of the depth 1, etc. This is possible since it is an almost complete tree, and you know how many elements will be present at a given depth - i.e. 2^d at depth d (except of course at the last depth). Now all you've got to do is access the array in a zag-zag manner, and create a new BST (array) of the new order. So, how would you traverse the array in a zig-zag manner?? For any given element A[i], the left child would be A[2i] and the right child A[2i + 1]. So, if your current depth d is odd, then traverse 2^d elements, and when you reach the 2^dth element, go to its left child. If your current depth d is even, again traverse 2^d elements, but when you reach the 2^dth element, go to its right child. Storing them as arrays rather than nodes makes your data structure leaner, and your implementation simpler.
This ( http://cslibrary.stanford.edu/109/TreeListRecursion.html) has the answer with pretty pictures :)
#include<iostream>
#include<conio.h>
using namespace std;
class TreeNode
{
public:
int info;
TreeNode* right;
TreeNode* left;
//TreeNode* parent;
TreeNode()
{
info = 0;
right = left = NULL;
}
TreeNode(int info)
{
this -> info = info;
right = left = NULL;
}
};
class ListNode
{
public:
int info;
ListNode* next;
ListNode()
{
info = 0;
next = NULL;
}
ListNode(int info)
{
this -> info = info;
next = NULL;
}
};
TreeNode* root = NULL;
ListNode* start;
ListNode* end;
void addTreeNode(TreeNode*);
void convertTreeToList(TreeNode*);
void printList(ListNode*);
int findDepth(TreeNode*);
int _tmain(int argc, _TCHAR* argv[])
{
start = end = new ListNode(0);
char choice = 'y';
int info;
while(choice == 'y')
{
cout<<"Enter the info of new node:\n";
cin>>info;
addTreeNode(new TreeNode(info));
cout<<"Want to add a new node to the tree?(y/n)\n";
cin>>choice;
}
cout<<"Depth of the tree is: "<<findDepth(root);
cout<<"Converting the tree into a doubly linked list....\n";
convertTreeToList(root);
printList(start->next);
cin>>choice;
return 0;
}
void addTreeNode(TreeNode* node)
{
if(!root)
{
root = node;
}
else
{
TreeNode* currRoot = root;
while(1)
{
if(node -> info >= currRoot -> info)
{
if(!currRoot -> right)
{
currRoot -> right = node;
break;
}
else
{
currRoot = currRoot -> right;
}
}
else
{
if(!currRoot -> left)
{
currRoot -> left = node;
break;
}
else
{
currRoot = currRoot -> left;
}
}
}
}
}
void convertTreeToList(TreeNode* node)
{
if(node -> left != NULL)
{
convertTreeToList(node -> left);
}
end ->next = new ListNode(node -> info);
end = end -> next;
end -> next = start;
if(node -> right != NULL)
{
convertTreeToList(node -> right);
}
}
void printList(ListNode* start)
{
while(start != ::start)
{
cout<<start->info<<" -> ";
start = start -> next;
}
cout<<"x";
}
int findDepth(TreeNode* node)
{
if(!node)
{
return 0;
}
else
{
return (max(findDepth(node -> left), findDepth(node -> right)) + 1);
}
}
Linked list you get here is singly linked and sorted. Hope you can easily make changes in this code to get a doubly linked list. Just copy - paste this code and compile it.It will work fine.
Let us assume that the root of the binary tree is at level 0(an even number). Successive levels can be considered as alternating between odd even (children of root are at odd level, their children are at even level etc.). For a node at even level, we push its children onto a stack(This enables reverse traversal). For a node at odd level, we push its children onto a queue(This enables forward traversal). After children have been pushed, we remove the next available element (top of stack or front of queue) and recursively call the function by changing level to odd or even depending on where the removed element lies. The removed element can be inserted at the end of the doubly linked list. Pseudo-code below.
// S = stack [accessible globally]
// Q = queue [accessible globally]
//
// No error checking for some corner cases to retain clarity of original idea
void LinkNodes(Tree *T,bool isEven,list** l)
{
if(isEven) {
S.push(T->right);
S.push(T->left);
while( !S.empty() ) {
t = S.pop();
InsertIntoLinkedList(l,t);
LinkNodes(t,!isEven);
}
} else {
Q.enque(T->left);
Q.enque(T->right);
while( !Q.empty() ) {
t = Q.deque();
InsertIntoLinkedList(l,t);
LinkNodes(t,isEven);
}
}
}
In the calling function:
bool isEven = true;
list *l = NULL;
// Before the function is called, list is initialized with root element
InsertIntoLinkedList(&l,T);
LinkNodes(T,isEven,&l);
/* * File: main.cpp * Author: viswesn * * Created on December 1, 2010, 4:01 PM */
struct node {
int item;
struct node *left;
struct node *right;
struct node *next;
struct node *prev;
};
struct node *dlist = NULL;
struct node *R = NULL;
struct node* EQueue[10] = {'\0'};
int Etop = 0;
struct node* OQueue[10] = {'\0'};
int Otop = 0;
int level=-1;
struct node *insert(struct node *R, int item)
{
struct node *temp = NULL;
if (R != NULL) {
if (item < R->item) {
R->left = insert(R->left, item);
} else {
R->right = insert(R->right, item);
}
} else {
temp = (struct node *)malloc(sizeof(struct node));
if (temp == NULL) {
return NULL;
}
temp->item = item;
temp->left = NULL;
temp->right = NULL;
temp->next = NULL;
temp->prev = NULL;
R = temp;
}
return R;
}
void print(struct node *node)
{
if (node != NULL) {
print(node->left);
printf("%d<->", node->item);
print(node->right);
}
}
void EvenEnqueue(struct node *item) {
if (Etop > 10) {
printf("Issue in EvenEnqueue\n");
return;
}
EQueue[Etop] = item;
Etop++;
}
void OddEnqueue(struct node *item)
{
if (Otop > 10){
printf("Issue in OddEnqueue\n");
return;
}
OQueue[Otop] = item;
Otop++;
}
int isEvenQueueEmpty() {
if (EQueue[0] == '\0') {
return 1;
}
return 0;
}
int isOddQueueEmpty()
{
if (OQueue[0] == '\0') {
return 1;
}
return 0;
}
void EvenDQueue()
{
int i = 0;
for(i=0; i< Etop; i++)
EQueue[i]='\0';
Etop = 0;
}
void OddDQueue()
{
int i = 0;
for(i=0; i< Otop; i++)
OQueue[i]='\0';
Otop = 0;
}
void addList() {
int counter = 0;
struct node *item = NULL;
if (level%2 == 0) {
/* Its Even level*/
while(counter < Etop)
{
struct node *t1 = EQueue[counter];
struct node *t2 = EQueue[counter+1];
if ((t1!=NULL) && (t2!=NULL)) {
t1->next = t2;
t2->prev = t1;
}
counter++;
}
item = EQueue[0];
} else {
/* Its odd level */
while(counter < Otop)
{
struct node *t1 = OQueue[counter];
struct node *t2 = OQueue[counter+1];
if ((t1!=NULL) && (t2!=NULL)) {
t2->next = t1;
t1->prev = t2;
}
counter++;
}
item = OQueue[Otop-1];
}
if(dlist !=NULL) {
dlist->next = item;
}
item->prev = dlist;
if (level%2 == 0) {
dlist = EQueue[Etop-1];
} else {
dlist = OQueue[0];
}
}
void printTree()
{
int nodeCount = 0;
int counter = 0;
if (!isEvenQueueEmpty()) {
/* If even level queue is not empty */
level++;
nodeCount = pow(2,level);
printf("[");
while(counter < nodeCount) {
if (EQueue[counter] != '\0') {
struct node *t = EQueue[counter];
printf("%d<->", t->item);
if (t->left != NULL)
OddEnqueue(t->left);
if (t->right != NULL)
OddEnqueue(t->right);
} else {
break;
}
counter++;
}
addList();
printf("]");
EvenDQueue();
}
counter = 0;
if (!isOddQueueEmpty()){
/* If odd level queue is not empty */
level++;
nodeCount = pow(2,level);
printf("[");
while(counter < nodeCount){
if (OQueue[counter] != '\0') {
struct node *t = OQueue[counter];
printf("%d<->", t->item);
if (t->left != NULL)
EvenEnqueue(t->left);
if (t->right != NULL)
EvenEnqueue(t->right);
} else {
break;
}
counter++;
}
addList();
printf("]");
OddDQueue();
}
if (isEvenQueueEmpty() && isOddQueueEmpty()){
return;
}
else {
printTree();
}
}
void printLevel(struct node *node)
{
if (node == NULL)
return;
EvenEnqueue(node);
printTree();
printf("\n");
}
void printList(struct node *item)
{
while(item!=NULL) {
printf("%d->", item->item);
item = item->next;
}
}
int main(int argc, char** argv) {
int a[]={20,30,40,12,2,15,18};
int size = sizeof(a)/sizeof(int);
int i = 0;
for(i=0; i< size; i++) {
R = insert(R, a[i]);
}
printf("Inoder traversal - Binary tree\n");
print(R);
printf("\n\n");
printf("Level traversal - Binary tree\n");
printLevel(R);
printf("\n");
printf("Double link list traversal - Binary tree\n");
printList(R);
printf("\n");
return 0;
}