Printing a binary tree with specified indent level in C++ - c++

I'm having trouble printing a binary tree. Basically each node contains two values - key and data. The problem is for this assignment,
I am expected to use double-space instead of \t. Basically it means, \t = 2 spaces, \t\t = 4 spaces, \t\t\t = 6 spaces
My problem is, I have implemented the printIndented method in the following way -
void
TreeDictionary::printIndented(TreeNode * node, int level) {
if (node == NULL)
return;
if (level == 0)
{
std::cout << node->_key << ':' << node->_data << "\n";
level++;
printIndented(node->_left, level);
printIndented(node->_right, level);
}
else
{
if ((node->_left == NULL) && (node->_right == NULL))
cout << '\t';
cout << "\t" << node->_key << ':' << node->_data << endl;
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_left, level);
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_right, level);
}
}
which is giving me an output as follows -
---=WHAT I AM GETTING=---
pineapple:0
kiwi:1
grapes:3
apple:5
orange:6
lime:8
olives:9
mango:10
strawberry:4
watermelon:7
---=EXPECTED OUTPUT=--- (as you see it prints 2 spaces instead of each \t)
pineapple:0
kiwi:1
grapes:3
apple:5
NULL
NULL
NULL
orange:6
lime:8
NULL
olives:9
mango:10
NULL
NULL
NULL
NULL
strawberry:4
NULL
watermelon:7
NULL
NULL
It seems like I am unable to account for the NULL values and print NULL whenever a NULL entry is found. All help is appreciated!
NOTE : The expected output is for default indent-level that is 0 for this program.

You're not really using the information that you're getting from knowing the level that you're at. Think of it as indenting from the left most edge of the screen. Per level you want to indent it by 2*level spaces. From the output, it looks like a NULL node prints out NULL. You could try something along the lines of:
Indent(Treenode *node, int level){
std::cout << std::string(2*level, ' ');
if(node == NULL){
std::cout << "NULL" << std::endl;
}else{
std::cout << node->_key << ":" << node->_data << std::endl;
level += 1;
Indent(node->_right, level);
Indent(node->left, level);
}
}

First of all, you should also check if the first node, at level 0, has childs. Else you could run into an error if there is only one node in your tree.
Second, I encourage you to use curling braces after the if statements, this is confusing and not very readable:
if((node->_left != NULL) && (node->_right != NULL)) {
cout << "\t"; //or in your case maybe: cout << " "; //see point 3
}
Third point, when you want to print a space instead of a '\t' you should do ' ' instead of '\t'. You also use "\t", which is the syntax for printing a string instead of a character, this is not wrong but I think you need to understand the principle. '\t' = const char, "\t" = const string
4th, I don't really understand what criterium you maintain for printing with different kind of indentation, so if you can explain what you are trying to accomplish with the if statements that would be great, then I can explain it to you as well.
If you have any questions left or you find this not helpfull just tell me :)
Good luck!

Related

Simplify Do While Loop Checking for Null Pointer

I have a really basic problem that I can't figure out. I'm using chaining with hash tables to store nodes that collide with each other. I used a do while loop to print the first node at least once, and continue to print the chained nodes if they exist. However, in order to traverse the chained list, I need to change the address of the node for the next loop. Any way I try writing this, I find myself repeating code, which I was trying to avoid by using this loop. Please help
do {
cout << "Bid id: " << table.at(i)->bidId << " title: " << table.at(i)->title <<
" fund: " << table.at(i)->fund << " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next!=nullptr){//check if first node has next node
table.at(i) = table.at(i)->next; //change address to the next pointer
}// how do I avoid repeating my condition below?
}
while (table.at(i)->next!=nullptr);
This code will replicate the functionality in your loop without duplicating the check against NULL.
while(true)
{
cout << /* stuff */ endl;
auto next = table.at(i)->next;
if(next)
table.at(i) = next;
else
break;
}
From the description though, are you sure you want to reassign the values inside your hash map while looping over them? I suspect that this code may suit your intent/needs better:
auto current = table.at(i);
while(current)
{
cout << /* stuff */ endl;
current = current->next;
}
When you find yourself in a situation like this one, it's a good idea to question your premise. In this case, I am talking about your assumption that you need a do while loop.
If there is a chance that your data won't be there or that your container is empty, then a do while won't do the job because it will loop at least once.
Generally, for iterating through a collection of data you'll want to use a for or while loop.
If I understand the code correctly, you need a precondition loop and not a postcondition one, as you have right now. For example:
while (table.at(i)) {
cout << "Bunch of stuff";
table.at(i) = table.at(i)->next;
}
You could try doing:
for(auto node = table.at(i)->next;node!=nullptr;node=node->next)
cout << "Bid id: " << node->bidId << " title: " << node->title;
Where you may need to replace node = table.at(i)->next with an appropriate way of getting a link to the first entry.
You can use C++11's range based for loop here. All you want to know is that value->next is not a nullptr before doing the assignment. Rest all is taken care by the simple and modern range based for loop
for(auto const& value: table) {
if (value->next != nullptr) {
value = value->next;
}
}
Its even faster and safer this way
If really you want to be able to get last element after the loop, you may do:
do {
cout << "Bid id: " << table.at(i)->bidId
<< " title: " << table.at(i)->title
<< " fund: " << table.at(i)->fund
<< " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next == nullptr){
break;
}
table.at(i) = table.at(i)->next;
} while (true);
// table.at(i) != nullptr && table.at(i)->next == nullptr

Rotate Binary Tree

I am trying to print a non static binary tree.
It does print but it rotates towards the left. I cant find a way to correct this and make it rotate upright. 5 is the root node. Code:
template <class dataType>
void displaybinarytree(BinaryTree <dataType> * p, int indent)
{
if(p != NULL) {
if(p->right()) {
displaybinarytree(p->right(), indent+4);
}
if (indent) {
cout << setw(indent) << ' ';
}
if (p->right()){
cout<<" /\n" << setw(indent) << ' ';
}
cout<< p->getData() << "\n ";
if(p->left()) {
cout << setw(indent) << ' ' <<" \\\n";
displaybinarytree(p->left(), indent+4);
}
}
}
Output:
Expected output:
A recursive approach doesn't play nice with a line-based output, where a line consists of items from multiple sub-trees.
You should switch to a breadth-first-traversal, where you create a working set per tree level. You may need to pre-compute the space requirements of lower tree levels in order to output the desired alignments in higher levels.
A little starting code that doesn't really display the tree as a tree, but at least displays each node in the correct line.
void displaybinarytree(BinaryTree <int> * p, int indent)
{
deque<BinaryTree<int>*> current;
deque<BinaryTree<int>*> next;
next.push_back(p);
while (!next.empty())
{
current.swap(next);
while (!current.empty())
{
BinaryTree<int>* node = current.front();
current.pop_front();
if (node->left)
{
next.push_back(node->left);
}
if (node->right)
{
next.push_back(node->right);
}
// instead of a single space, appropriate spacing is needed
cout << " " << node->data;
}
// instead of a single newline, appropriate spacing and connector characters / \ are needed
cout << endl;
}
}
See the in-code-comments for things that are missing from this code. I replaced your dataType by int and used primitive fields instead of getter functions, since it doesn't really matter to the concept.
If you want the top of the tree to appear at the top of the output, you must output it first - before its branches.
Your code outputs the right branch first, and it therefore appears at the top of the output:
// Outputs right branch:
if(p->right()) {
displaybinarytree(p->right(), indent+4);
}
if (indent) {
cout << setw(indent) << ' ';
}
if (p->right()){
cout<<" /\n" << setw(indent) << ' ';
}
// Outputs "current" node:
cout<< p->getData() << "\n ";
You need to switch the order: output the current node, then the branches.
Also, the slashes are in the wrong direction, and the indent changes need to be corrected. The left branch should be indented less rather than more.
Making just these changes at least gets the tree printed "top down". You will still find the branches are not printed next to each other - that requires a significantly more complex solution.

Comparing One Link List to Another Blacklist versus Word Frequency List C++

I have created a program that will read a text file and put the words as strings into a linked list, along with their frequency count throughout the text file. It only prints one occurrence of each word with the total times it appeared.
My program also loads a blacklist, in which it is supposed to compare the blacklist linked list to the word cloud (or word frequency) linked list, and then remove the blacklisted words from the word frequency list.
I have tried doing this several ways. The following is my 3rd version. What I am wanting to do is add a Boolean value to each node, and when one node is equal to a word in the blacklist, the Boolean value will be true. However, I am not getting it to print right with the following code. I have searched, and I can't seem to find the correct syntax to add a Boolean value to a node in linked list.
EDIT #3:
void wordCloud::compareWith(wordCloud& wordList, wordCloud& badList){
wordNode *wordListTemp, *blacklistTemp, *temp = NULL;
unsigned int counter = 0;
for (blacklistTemp = badList.head; blacklistTemp; blacklistTemp = blacklistTemp->next){
cout << blacklistTemp->myWord << "\n";
for (wordListTemp = wordList.head; wordListTemp; wordListTemp = wordListTemp->next){
if (wordListTemp->myWord != blacklistTemp->myWord){
wordListTemp->blacklist = false;
if (wordListTemp->blacklist = false){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
}
}
else if (wordListTemp->myWord == blacklistTemp->myWord){
cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
wordListTemp->blacklist = true;
if (wordListTemp->blacklist = true)
cout << wordListTemp->myWord << "\n";
}
}
//counter++;
cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
}
system("pause");
}
This is not complete, but it is as far as I have gotten. The problem is it only prints the true if, and will not print any false if. Even if I switch the values, it will still only print the true if's. So I am assuming that I am going about this wrong. What would be the correct way to "flag" a node true and "flag" a node false? All the cout's are for debugging purposes. I will remove or comment those out later.
First of all, you could always debug step-by-step to see just which portion of the code freezes up your comp. The better way to detect memory leaks would be to use Valgrind.
On a side note, I would implement that comparison function as a comparison operator, and implement a comparison operator for their Nodes as well (for convenience). Doing so divides the code a bit and helps, later on, understand where your problem is. It is also a better way to do it (more readable, OOP-y, etc).
Finally!!
With a lot of old fashion debugging and cout statements, I finally got what I wanted. I know this might have been easy for some, but with not being very familiar with linked lists, this was quite the process for me.
Before I was trying to delete words that were seen in the blacklist linked list out of the wordList linked list. I decided later to just try to add a boolean value of true to the nodes in wordList, and then adjust my print function to not print nodes with the value of true. I also had to tweak a few things in insertWord(), and my freqSort() functions, but all that really consisted of was adding a pointer to the boolean value when a new node was being created.
My member function is void wordCloud::compareWith(wordCloud& wordList, wordCloud& badList), and is part of my wordCloud class. Here is the following definition:
void wordCloud::compareWith(const wordCloud& wordList, const wordCloud& badList){
wordNode *wordListTemp, *blacklistTemp;
unsigned int counter = 0;
//loop that advances wordListTemp
for (wordListTemp = wordList.head; wordListTemp; wordListTemp = wordListTemp->next){
blacklistTemp = badList.head;
//loop advances blacklistTemp - compares links in wordList to badList(blacklist)
//and sets the node to true if myWord equals any word in the blacklist
while (blacklistTemp){
if (wordListTemp->myWord == blacklistTemp->myWord){
wordListTemp->blacklist = true;
counter++;
}
blacklistTemp = blacklistTemp->next;
}
//for debugging
//cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
}
/********************* All for debugging ***************************************
cout << "True:\n\n";
wordListTemp = wordList.head; //reset wordListTemp to head
while (wordListTemp){ //print blacklisted words from wordList
if (wordListTemp->blacklist == true){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
}
wordListTemp = wordListTemp->next;
}
//prints total words blacklisted
cout << "There are " << counter << " blacklisted words.";
cout << "\n\nFalse:\n\n";
wordListTemp = wordList.head; //reset wordListTemp to head
counter = 0;
while (wordListTemp){ //print non-blacklisted words from wordList
if (wordListTemp->blacklist == false){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
counter++;
}
wordListTemp = wordListTemp->next;
}
//prints total words not blacklisted
cout << "There are " << counter << " words that are not blacklisted.\n";
system("pause");
******************** End debugging *******************************************/
}
So basically this is a comparison function that flags nodes that are found in another list. Works well and tested with all other options.

rapidxml comparing node values (testing values)

Im new to radidxml, I cant find a way to compare a node value to string.
The only way I can figure out is to print it to a string, then test that value.
if (cell_node->first_node("text:p")) {
std::string test;
print(test.begin(), *cell_node->first_node("text:p")->first_node(), 0);
if (test[0] == '#') {
std::cout << "TRUE";
cell_node->first_node("text:p")->remove_first_node();
rapidxml::xml_node<> *node3 = doc.allocate_node(
rapidxml::node_data, 0, "append this one"
);
cell_node->first_node("text:p")->append_node(node3);
}
}
Is there any other way? I was hoping for:
cell_node->first_node("text:p")->first_node()->value() == "some string";
Just use node->value(), surely?
xml_node n = cell_node->first_node("text:p"); // don't keep calling first_node
if (n && (n->value()[0] == '#'))
{
...
It returns char* rather than std::string, so beware comparing the values of two nodes...
The RapidXml manual is here: http://rapidxml.sourceforge.net/manual.html - Plenty of simple examples.
Once you have the node, you can call name() to get its name as pointer to string.
if (0 == strcmp(node->name(), "#"))
{
cout << "Found the # node!" << endl;
}

One if else statement will not execute

Below is the section I am having trouble with
if(transition == *(vec.end()-1)) { //vec contains the ASCI code
vec.pop_back();
--vec_index;
result.append(vec[vec_index]);
} else if(colors.find(modified.substr(1)) == colors.end()) {
cout << result << endl;
cout << "\033[0;37m";
cerr << "**ERROR: INVALID CLOSING COLOR TAG ON LINE: "
//cerr << "**ERROR: OVERLAPPING CLOSING COLOR TAG ON LINE: "
<< nlines << endl;
exit(0);
} else {
cout << result << endl;
cout << "\033[0;37m";
cerr << "**ERROR: INVALID CLOSING COLOR TAG ON LINE: "
//cerr << "**ERROR: OVERLAPPING CLOSING COLOR TAG ON LINE: "
<< nlines << endl;
exit(0);
}
In the above code, my else-if statement does not seem to execute at all. What I am trying to do is when modified.substr(1) is not found in the map is print the first error otherwise (the color string is in the map but it's not the same one as the last one in the vector) print the "else" error. However, my else case is always printing. The reason why it's modified.substr(1) is because modified (in this case) starts with a /.
transition = colors[modified.substr(1)];
will create an entry in map<> color; if it's not existing and value initialize it. That's why your else if condition will never be true. Use map::find instead of operator [] to find the entry. Something like,
map<string,string>::const_iterator it = colors.find(modified.substr(1)];
And use it instead of transition. You can de-reference it (as it->first for key and it->second for string-value) when needed to get the underlying string.
In your code vec is empty, so
if(transition == *(vec.end()-1))
leads to undefined behavior.