I'm trying to build a trie in c++ by implementing it through a B-Tree. Every single node has a key, an array of pointers to other nodes, and a boolean value determining if it's a leaf or not. By default, all pointers point to null when initializing a new node and whenever a new node is added, the previous node points to the new node.
But for some reason, my else if (currentNode.children[arrayPointer] != NULL) is never being called. I'm completely stumped. I'm not sure if it's because I'm labeling something wrong or if somethings not in the right order.
#include <iostream>
using namespace std;
numberOfWords = 0;
numberOfNodes = 0;
struct Node;
struct Node;
struct Node {
char key;
bool isLeaf;
struct Node *children[36]; //26 letters + 10 digits
};
main() {
//initializing the root
Node root;
root.key ='$';
int i = 0;
while (i < 36) {
root.children[i] = NULL;
i++;
}
root.isLeaf = 1;
numberOfNodes++;
insertWord("the", root);
insertWord("and", root);
insertWord("there", root);
cout << numberOfWords << " words found." << endl;
cout << numberOfNodes << " nodes found." << endl;
}
void insertWord(string word, Node currentNode) {
int wordLength = word.length();
char letterToInsert;
letterToInsert = word[0];
int arrayPointer;
arrayPointer = charToInteger(letterToInsert);
//if the node is not found, a new path is inserted
if (currentNode.children[arrayPointer] == NULL) {
insertNewPath(word, currentNode);
}
//if the node with the current letter is found, I want to recursively call
//insertWord and pass in the updated word and the next node.
//For some reason, this statement is never being called.
else if (currentNode.children[arrayPointer] != NULL) {
string updatedWord;
updatedWord = word.substr(1,wordLength);
Node nextNode;
currentNode.children[arrayPointer] = &nextNode;
insertWord(updatedWord, nextNode);
}
}
//This function will keep recursively calling itself and passing in the new word
//and the new node until the each letter is added.
void insertNewPath(string word, Node currentNode) {
int wordLength;
wordLength = word.length();
if (wordLength > 0) {
char letterToInsert;
letterToInsert = word[0];
int arrayPointer;
//charToInteger takes a character and converts it into an integer value - a=0,b=1,...,8=34,9=35
arrayPointer = charToInteger(letterToInsert);
Node newNode;
numberOfNodes++;
newNode.key = letterToInsert;
// Here, I set the current node's pointer to point to the new node.
// This should cause line 168 to execute when entering an existing
// letter to the trie but for some reason it never does.
currentNode.children[arrayPointer] = &newNode;
//setting every pointer in the new node to null
int i = 0;
while (i < 36) {
newNode.children[i] = NULL;
i++;
}
currentNode.isLeaf = 0;
string updatedWord;
updatedWord = word.substr(1, wordLength);
insertNewPath(updatedWord, newNode);
}
else if (wordLength == 0){
currentNode.isLeaf = 1;
//Once all the letters have been added, the last
//node/letter to be added is set as a leaf, making
//it a complete word.
}
}
The output I'm expecting to get is
3 words found.
9 nodes found.
Instead I'm getting
3 words found.
11 nodes found.
So pretty much a node is being created for ever single letter.
Related
I try to traverse a linked list of values, and add some given value to every other node in the list. It should always start adding to the first node in the list, and then add on to every other node from there.
Error is the program not giving any output but it most likely something wrong with the function
Here is what I tried:
#include <iostream>
using namespace std;
// Declare the Node structure to be used for the linked list.
// Each node should have an int for data, and
// a pointer to the next node.
struct Node {
int data;
Node *pNext;
};
// Displays the list number values
void display( Node *pTemp){
while( pTemp != NULL) {
cout << pTemp->data << "->";
pTemp = pTemp->pNext;
}
cout << endl;
}
// Create a new node, put the userInput number in it, and APPEND
// it to the END of the list.
void append(Node* &pHead, int userInput) {
Node *pTemp = new Node;
pTemp->data = userInput;
pTemp->pNext = NULL;
Node *pLast = pHead;
// Find the last node on the list
while(pLast != NULL && pLast->pNext != NULL) {
pLast = pLast->pNext;
}
if( pLast == NULL) {
// Make this new node the first node on an otherwise empty list
pHead = pTemp;
}
else {
// Append this new node to the end of the existing list
pLast->pNext = pTemp;
}
}
//-----------------------------------------------------------------------
// *** Do not change anything above this point. ***
//------------------------------------------------------------------------
// add valueToAdd to every second node in the list
void addEveryOther(Node* &pHead, int valueToAdd) {
// while there is a node after pTemp->pNext
while(pHead->pNext != NULL || pHead != NULL) {
// add valueToAdd to pTemp->data
pHead->data += valueToAdd;
// move pTemp to the next node
pHead = pHead->pNext->pNext;
}
}
//-----------------------------------------------------------------------
// *** Do not change anything below this point. ***
//------------------------------------------------------------------------
int main() {
int userInput;
Node *pHead = NULL; // pointer to the head of the list
int value;
// Create the linked list
cout << "Enter list numbers separated by space, followed by -1: ";
cin >> userInput;
// Keep looping and appending nodes on the list until
// end-of-input flag of -1 is given
while(userInput != -1) {
// Store this number on the list
append(pHead, userInput);
cin >> userInput;
}
cout << "Enter value to add on: ";
cin >> value;
addEveryOther(pHead, value);
display(pHead);
return 0;
}// end main()
Here is the input :
2 8 9 5 11 3 6 -1
Enter value to add on: 5
and expected output :
7->8->14->5->16->3->11
You need to think about the order in which you do things! And the logic in your conditions.
In the condition pHead->pNext != NULL || pHead != NULL you will dereference pHead before you check if it's a null pointer.
You need to do the checks in the opposite order, and use logical AND instead: pHead != NULL && pHead->pNext != NULL.
I am trying to delete the odd numbers that are randomly generated (see oddsOnly), and then print the list in reverse order. I can delete odds that may pop up at the beginning of the list, but I cannot find a way to delete anything after that.
I have tried various forms of if and while loops. Too many different ways for me to remember or list them all.
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
struct Node
{
int element;
Node *next;
Node *previous;
};
// Function headers
int takeNumber(int);
int writeFile(int);
struct Node *readFile(Node *&, int);
void printBackward(Node *);
struct Node *oddsOnly(Node *&, int);
void deleteList(Node *);
// Main
int main(int argc, char *argv[])
{
// Check to see if the user passed us the size to make the list.
if (argc == 2)
{
// Check to see if what the user passed us is in fact a valid number.
// Here we attempt to assign what was passes in to us to an int variable
int Size = atoi(argv[1]);
// Now we check a few things. If the !Size tells us whether or not the
// assignment above was successful. If the size is less than 20 or
// greater than 100, the input did not follow the instructions. In
// either case we ask the user to enter another number with the printed
// instructions of it must be between 20 and 100.
if (!Size || Size < 20 || Size > 100)
{
Size = takeNumber(Size);
}
// Create the pointer for Head. This is used to keep track of the beginning
// of the list.
Node *Head = new Node;
if (Head == NULL)
{
cout << "fatal error: could not create Head node." << endl;
return(1);
}
Head = NULL;
// If we are here, the head node was created successfully. As this is
// currently also the last node in the list, set the pointer to NULL.
//Head->next = NULL;
writeFile(Size);
readFile(Head, Size);
// When you allocate memory with new or malloc, you should always clean
// free up the memory when you are through.
deleteList(Head);
}
else
{
int Size = 0;
Size = takeNumber(Size);
// Create the pointer for Head. This is used to keep track of the beginning
// of the list.
Node *Head = new Node;
if (Head == NULL)
{
cout << "fatal error: could not create Head node." << endl;
return(1);
}
Head = NULL;
// If we are here, the head node was created successfully. As this is
// currently also the last node in the list, set the pointer to NULL.
//Head->next = NULL;
writeFile(Size);
readFile(Head, Size);
oddsOnly(Head, Size);
// When you allocate memory with new or malloc, you should always clean
// free up the memory when you are through.
deleteList(Head);
}
system("pause");
return 0;
}
// Function to take input (size) from the user
int takeNumber(int Size)
{
while (Size < 20 || Size > 100)
{
// Output specific instructions to the user.
cout << endl << "Please inter a number between 20 and 100 (inclusive). " << endl;
// Take a given input from the user.
cin >> Size;
// Set a while loop so that if the incorrect input is given, the user will
// be asked to enter a different input untill it fits the given discription
// in the instructions.
if (cin.fail() || Size < 20 || Size > 100)
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
// Print error message and ask for another input.
cout << "Input is not between 20 and 100 (inclusive). " << endl;
cout << "Please try again. " << endl << endl;
}
}
// Return the input.
return Size;
}
// Function to write random numbers to a binary file
int writeFile(int size)
{
// Create and open the file you will write to.
ofstream WriteFile;
WriteFile.open("numbers.bin", ios::out | ios::binary);
// Make sure to print an error message if the file was not created.
if (!WriteFile)
{
cout << "Could not create/open binary file for writing. " << endl << endl;
return (1);
}
// Seed the random fuction with the time from the computer.
srand(int(time(NULL)));
// create a variable to store the random variable gernerated.
int number = 0;
// Create a loop to generate some random data and store it in
// the number variable. Then write the number to the to the binary
// file.
for (int i = 0; i < size; i++)
{
// Generate a random number between 0 and 99.
number = (rand() % 100);
// Write the number to the binary file.
WriteFile.write(reinterpret_cast<const char *>(&number), sizeof(int));
}
WriteFile << endl;
// Close the binary file.
WriteFile.close();
return(0);
}
// Function to read the binary file and create a linked list.
struct Node *readFile(Node *&Head, int Size)
{
// Create and open a read binary file
ifstream ReadFile;
ReadFile.open("numbers.bin", ios::in | ios::binary);
// Check to make sure file has been created and opened.
if (!ReadFile)
{
cout << "Could not open the binary file for reading. " << endl << endl;
}
int Data = 0;
int counter = 1;
while (ReadFile)
{
ReadFile.read((char*)&Data, sizeof(int));
if (ReadFile.eof())
{
break;
}
if (Head == NULL)
{
Node *tmp = new Node;
if (tmp == NULL)
{
cout << "fatal error: could not create tmp node" << endl;
}
tmp->element = Data;
tmp->next = NULL;
tmp->previous = NULL;
Head = tmp;
counter = counter + 1;
}
else if (Head != NULL)
{
Node *current = new Node;
if (current == NULL)
{
cout << "fatal error: could not create current node" << endl;
}
current = Head;
while (current->next != NULL)
{
current = current->next;
}
struct Node *temp = new Node;
if (temp == NULL)
{
cout << "fatal error: could not create temp node" << endl;
}
temp->element = Data;
temp->next = NULL;
temp->previous = current;
current->next = temp;
counter = counter + 1;
}
}
cout << endl;
// Close the file
ReadFile.close();
oddsOnly(Head, Size);
printBackward(Head);
cout << endl;
return Head;
}
// Function to read the numbers.bin file and put numbers in reverse order
void printBackward(Node *Head)
{
// We now have a list. We can traverse the list and print the elements.
// We have the head, we create a current or tmp node pointer to set it
// equal to head.
Node *temp;
temp = Head;
while (temp->next != NULL)
{
temp = temp->next;
}
// We can use a counter to format the output on the console
int counter = 1;
// This is our loop to traverse the list. We start at head, and go until
// we reach the null pointer of the last node.
while (temp != NULL)
{
// This prints the number in the node, then a tab separator to the
// console.
cout << temp->element << "\t";
// This is used for formatting the output on the screen. In this case,
// after every five nodes have been printed, we insert a newline and
// reset the counter to 0.
if (counter % 5 == 0)
{
cout << endl;
counter = 0;
}
// We advance the tmp or current pointer to the next value and increment the counter.
temp = temp->previous;
counter = counter + 1;
}
}
// Function to weed out the odd numbers in the list
struct Node *oddsOnly(Node *&Head, int size)
{
int counter = 1;
while (Head->element % 2 == 0)
{
struct Node *temp = Head;
Head = Head->next;
Head->previous = NULL;
delete(temp);
return Head;
counter = counter + 1;
}
Node *tmp = Head;
while (tmp != NULL)
{
Node *current = Head;
while (current->element % 2 != 0 && current->next->next != NULL)
{
current = current->next;
tmp = current->next;
}
current->previous->next = current->next;
current->next->previous = current->previous;
delete(current);
struct Node *current1 = Head;
while (current1->next != NULL)
{
current1 = current1->next;
}
if (current1->element % 2 == 0)
{
current1->previous->next = NULL;
delete(current1);
}
tmp = tmp->next;
}
cout << endl;
return Head;
}
// Function to delete the link list.
void deleteList(Node *Head)
{
Node *tmp;
// Loop through the list, deleting one node at a time. We set tmp equal
// to the node after head, delete head and then set head equal to tmp.
while (Head != NULL)
{
tmp = Head->next;
delete(Head);
Head = tmp;
}
}
I am looking for a list that allows 5 integers before starting a new line, and that has only odd values from the linked list.
I have gotten a lot of error messages displaying 0xDDDDDDDD in the oddsOnly function. at this point though, I am only seeing that it is not deleting the evens after the first node in the list.
Refer to the following diagram:
To delete node B from the list, set A.Next to A.Next.Next, set C.Prev to C.Prev.Prev, and free node B.
To delete node D from the list, set C.Next to C.Next.Next (which is null), and free node D.
Make sure you write a function that does this. Your code suggests that you're not fully taking advantage of the encapsulation and "divide and conquer" strategy that functions provide.
Further Reading
Delete a node in a Doubly Linked List
Stealing Roberts great picture
I don't quite agree with his description (it is correct though just a bit complicated when written in English).
Node* x = findNodeToDelete();
if (x == nullptr) { // Check to make sure you have an actual node to delete.
return;
}
if (x->next != nullptr) {
x->next->prev = x->prev;
}
if (x->prev != nullptr) {
x->prev->next = x->next;
}
else {
Head = x->next;
}
// Now you have unlinked the node from the list.
x->next = nullptr; // Optional if node has a complex destructor may be worth it.
x->prev = nullptr; // Optional
// Now release the node you are deleting.
delete x;
As you know there are 3 situations in deleting being
1 - head
2 - middle
3- end
I think you covered the first one lest proceed to the second one
lets say you are in a traversing loop
while( cur != NULL ){
...
cur = cur -> next;
let's look at the middle of the node for second case
For deletion in the middle, you should know the previous node and the next node of to deleted node and you should bind them together. Luckily you both have previous and next in doubly linked list.
so lets add a statement to a code
if ( cur -> data == oddNumber ){
Node* prev = cur -> prev;
Node* next = cur -> next;
prev -> next = cur -> next;
delete cur;
cur = cur -> next;
}
that was for the middle, and for the end (3 rd case) you can simply check if the next node of the node is NULL and delete it peacefully.
I am creating a linked list program, and one of the functions is supposed to remove a node at a given index.
My idea is to locate the node one before the node at the index I wish to remove, then set it's next pointer to the ->next pointer of the node I wish to remove, therefore "skipping" it and removing it from the list.
At the moment my for loop does not seem to be working. After the the for loop has run, the value of temp->data is always the data of the second node in the list.
for example, with the list of nodes
15
14
13
12
11
10 (10 being the start of the list)
if I want to remove at the index of 4.
temp->data returns 11, instead of 14.
Here is the code I have:
NODE * removeAt(NODE * pList, int index)
{
NODE * temp = pList;
for (int i = 0; i < index - 1; i++)
{
temp = temp->next;
}
NODE * next = temp->next->next;
temp->next = next;
return temp;
}
Any help is appreciated!
First of all, you have an indexing convention problem. If you say you expect the-next-after-removed to be 14, that means you want to remove the number 13. But it is a number 3 if you start from 0.
You say "My idea is to locate the node one before the node at the index I wish to remove". Imagine you want to remove the start node (data=10), will your idea work here? There is no any "one before" node in this case. Same about the last. There would be no the-next-after-removed.
Also, you need to check for null pointers everywhere. And you must destroy the removed node to avoid memory leaks.
And you need to check how do you insert nodes. Is the start one really 10?
I would improve your code like this:
#include <iostream>
#include <vector>
using namespace std;
struct NODE
{
int data;
NODE * next;
};
NODE * removeAt(NODE * pList, int index)
{
if (!pList)
return nullptr;
NODE * temp = pList;
if (index == 0)
{
temp = pList->next;
std::cout << "removing " << pList->data << endl;
delete pList;
return temp;
}
// after this loop temp points to the node before
for (int i = 0; i < index -2; i++)
{
temp = temp->next;
if (!temp || !temp->next) // to guarantee both the-node-before and the-node-to-remove exist
return nullptr;
}
NODE * next = temp->next->next;
std::cout << "removing " << temp->next->data << endl;
delete temp->next;
temp->next = next;
return next;
}
int main()
{
std::vector<int> vec {15, 14, 13, 12, 11, 10};
NODE * root = nullptr;
for (const int v : vec)
{
std::cout << v << ' ' << endl;
NODE * cur = new NODE;
cur->data = v;
cur->next = root;
root = cur;
}
removeAt(root, 4);
return 0;
}
I have to create binary tree in which nodes store a char value. The task is to find the largest lexicographically root to leaf path created by these chars.
The given input should be a string where first char is value to store and after space there are hints in which node it is stored. L means left node, R of course right one.
The output should be a found string and number of chars given in input (not whitespaces).
This is my code. I'm pretty sure that mistake is in rootToLeafPath(), because I've already checked method which creates tree. I'm giving you also, print method if you want to see all paths.
#include <stdio.h>
#include <iostream>
#include <string.h>
int allCharCounter = 0;
char oldest_word[65];
struct Tree_node{
struct Tree_node *right;
struct Tree_node *left;
char value;
};
Tree_node* getTree(struct Tree_node* root){
char c = getchar();
char edge = c;
Tree_node* korzen = new Tree_node();
if(root == NULL){
root = new Tree_node();
}
korzen = root;
while(!feof(stdin)){
c = getchar();
if(c == 82){//R
allCharCounter++;
if(root->right == NULL){
root->right = new Tree_node();
}
root = root->right;
}else if(c == 76){//L
allCharCounter++;
if(root->left == NULL){
root->left = new Tree_node();
}
root = root->left;
}else if(c > 96 && c < 123){
allCharCounter++;
root->value = edge;
root = korzen;
edge = c;
}
}
root->value = edge;
root = korzen;
return root;
}
void printPath(char *path, int length){
int i;
for(i = 0; i <= length; i++){
printf("%c ", path[i]);
}
printf("\n");
}
void rootToLeafPath(struct Tree_node *nodeptr, char *current_path, int index){
if(nodeptr != NULL){
current_path[index] = nodeptr->value;
if(nodeptr->left == NULL && nodeptr->right == NULL){
if(strcmp(oldest_word,current_path)< 0){
//memset(oldest_word,0,sizeof(oldest_word));
strncpy(oldest_word, current_path, 65);
}
//printPath(current_path, index);
}
rootToLeafPath(nodeptr->left, current_path,index+1);
rootToLeafPath(nodeptr->right, current_path,index+1);
}
}
int main(){
struct Tree_node* root = NULL;
struct Tree_node* test = NULL;
root = getTree(root);
char current_path [65] ={};
rootToLeafPath(root, current_path,0);
std::cout<< oldest_word;
fprintf(stdout,"\n%d", allCharCounter+1); //-> ok
}
So for input:
s LR
z LRR
m RR
p LRLRL
k
w LRL
a LL
t L
h R
j LRLR
a LRRR
The output should be:
ktsza
38
But my code creates:
ktszap
38
I thought maybe I need to clear oldest_word before giving it a new value, but didn't work. For me it looks like it remembers longer value which was before. In this example, 'ktswjp' was the word in array before, but then it found new one which was 'ktsza', but the 'p' stayed.
Appreciate any help.
In rootToLeafPath, you assign a value to current_path[index] = nodeptr->value; to store the next character. When you're done with that character, you don't clear it out so it stays in the buffer, resulting in it appearing at the end of strings that should be shorter.
The solution is to reset it to the nul character before you return, with
current_path[index] = '\0';
after your recursive calls to rootToLeafPath are done.
I was trying to implement a simple Binary Search Tree for practice. I tried to just add values and print the values in the nodes. However, I am not getting the proper ascending order of values in the nodes. Here is what I have:
struct Node
{
int data;
Node* leftN;
Node* rightN;
};
typedef Node* Node_ptr;
Node_ptr head;
//INSERT_VALUE FUNCTION
Node* insert_value(Node_ptr leaf, int key)
{
//Root case when there is no set value yet
if(leaf == NULL)
{
leaf = new Node;
head = leaf;
cout << "Make the first node" << endl;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
//Left child Node
if(key < leaf->data)
{
//Search for a spot in the tree to add a Node (left value < root value < right value)
//This is only true for the left child Node
if(leaf->leftN != NULL)
insert_value(leaf, key);
//We have found a spot in the tree to add a new Node and add the value of key
else
{
cout << "Insert-left" << endl;
leaf->leftN = new Node;
leaf = leaf->leftN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
//Right child Node
else if(key >= leaf->data)
{
//Search for a spot to add a new Node in the tree (only amongst the right child Nodes)
if(leaf->rightN != NULL)
insert_value(leaf, key);
//Once we have found a spot to add a new Node, append the new Node
else
{
cout << "Insert-right" << endl;
leaf->rightN = new Node;
leaf = leaf->rightN;
leaf->data = key;
leaf->leftN = NULL;
leaf->rightN = NULL;
return leaf;
}
}
}
//PRINT FUNCTION
void printTree(Node_ptr leaf)
{
if(leaf == NULL)
return;
printTree(leaf->leftN);
cout << "Data element: " << leaf->data << endl;
printTree(leaf->rightN);
}
//MAIN
int main()
{
Node_ptr root = NULL;
int i;
//initialize values
for(i = 1; i < 12; i+=2)
root = insert_value(root, i);
root = head;
for(i = 0; i < 11; i+=2)
root = insert_value(root, i);
root = head;
printTree(root);
root = head;
cout << "Head Node: " << root->data << endl;
return 0;
}
When I printed the results, this is what I got:
0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11 and the value of the head node is 1
Because you are calling the insertion as:
root = insert_value(root, i);
the location at which you insert is always using a subtree starting at the last insertion. Except the time that you re-start to add the odd numbers, when you start inserting at the head.
If you create a class BinarySearchTree that contains a head pointer, and an insert method taking an int value that calls Node::insert( head, value ), then you can just call insert on that class, without passing it a node, and it can always see to it that the insertions use the root of the tree for the start of the recursion.
Just me, but I would have a constructor for Node that takes an int and initializes the pointers to NULL. That way you don't have to do that in the insert method.
In the leaf->node? != NULL case, I think instead of calling
insert_value(leaf, key);
you want to say
leaf->node? = insert_value(leaf->node?, key)
where ? is either L or R, of course.
Something you might consider is adding a comment to the method like so:
// Adds the given key to the (sub-)tree rooted at node* then returns the new root
// of that (sub-)tree.
node *insert_value_and_return_root(node *root, int value) { ... }