I have defined a Node struct:
struct Node {
char val;
bool isEnd;
Node* childs[26];
Node* getChild(char c) {
return childs[c - 'a'];
}
Node getChild1(char c) {
return *childs[c - 'a'];
}
};
Now in order to search through the sub-tree of this node, I defined a searchSubTree() function, as below:
void searchSubTree(string word, Node* cur) {
for (int i = 0; i < word.size(); ++i) {
...
cur = cur->getChild(word[i]);
}
}
This all works fine, because Node* cur is a pointer, and I am using "cur" variable to temporarily points to a node and its child.
However, how should I be able to avoid using the "temporary" pointer and use a temporary object in each iteration instead? I know that just using the Node::getChild1() signature is not enough, because in the line:
cur = cur.getChild1(word[i])
This will result in a shallow copy of "cur", and update actual content of each node, whereas I only want cur to be temporary so that it can iterate through each child. Is there an elegant way to do this?
Related
Here is how I defined and initialized a linked list
struct listrec
{
struct listrec *prev;
float value;
struct listrec *next;
};
listrec *head, *tail;
int main() {
int number;
cin >> number;
float content = 2.0;
for (float i = 0; i < number; i++)
{
if (i == 0)
{
head = new listrec;
head->prev = nullptr;
head->value = 1.0;
head->next = nullptr;
tail = head;
}
else
{
auto *newNode = new listrec;
newNode->value = content++;
newNode->next = nullptr;
newNode->prev = tail;
tail->next = newNode;
tail = tail->next;
}
}
return 0;
}
This is how the linked list looks like
I need to " write a function that takes two input parameters - the pointer head OR tail plus a parameter of which direction to traverse - to traverse the linked list and return the number of elements in the list. "
I have no idea how to write a function like that…
I know, if I want to count the number of elements from the first node, then I can write a function like this:
float listSize(listrec* head)
{
int count = 0;
listrec* current = head; // Initialize current
while (current != NULL)
{
count++;
current = current->next;
}
return count;
}
Or, if I want to count the elements from the last element, then
float listSize2(listrec* tail)
{
int count = 1;
listrec* current = tail;
while (tail->prev != NULL)
{
count++;
tail = tail->prev;
}
return count;
}
But how can I combine these two? Any hints would be appreciated!
Here is the function, assuming a doubly linked list:
enum class Direction {FORWARD, REVERSE};
struct Node
{
Node * previous;
Node * next;
};
unsigned int Count(Node * p_begin, Direction traverse_dir)
{
unsigned int node_count = 0U;
while (p_begin != nullptr)
{
++node_count;
if (traverse_dir == FORWARD)
{
p_begin = p_begin->next;
}
else
{
p_begin = p_begin->previous;
}
}
return node_count;
}
Per the requirement, the function takes 2 parameters, a pointer to a head or tail node, and a direction and returns the quantity of nodes traversed.
The function starts at the pointer passed, then goes forward or reverse (depending on the direction parameter), and increments the node counter. The loop stops when a null pointer is encountered, which usually signals the beginning or end of a list.
Since only a node class is used, you can inherit from the Node to make various list types:
struct Integer_Node : public Node
{
int data;
};
The data field does not play a role in traversing the list, so it was removed from the fundamental node object.
You don't need to "combine" them. You need to call one or the other depending on the direction:
enum class Direction { Forward, Backwards };
int listSize(listrec* p, Direction dir)
{
if (dir == Direction::Forward)
return listSize(p);
else
return listSize2(p);
}
This is not a review site, that being said I cannot in good conscience leave this answer without some advice for your code:
in C++ you should use RAII. A consequence of that is that you should never use explicit calls to new / delete and you should not use owning raw pointers.
count is an integer, so returning float in your functions makes no sense. Floating point data has its problems, don't use it for integers.
better name your functions. listSize and listSize2 are terrible names. Your functions don't list, they just return the size. So a better name is getSize. Also differentiating between then by a number is another terrible idea. You can use getSize and getSizeReverse.
there is no need to pass pointers to your function. Passing by reference, or even by value in your case is preferred.
you need better OOP abstractions. listrec is a list record (aka a list node). On top of this you need a class that abstracts a list. This would contain a pointer to the head of the list and a pointer to the tail of the list.
you should create a function for insertion into the list (and one for each operation on the list) and not do it manually in main.
I am feeling confused by the pointers in c++, where I am trying to implement BST.
Instead of (method 1)having a type of node, I want to use reference pointer (method 2).
How could I rewrite if statement, so it would work in a method where pointers been used?
How node p in (2) could be assigned to another temp node?
Thank you so much.
//1
node* delete(node* p, int k) // deleting k key from p tree
{
if( k < p->key )
p->left = remove(p->left,k);
}
//2
void delete(int key, node*& p) {
// recursive call while key is less and assign a new left child.
if( k < p->key ) {
//??
}
}
node *getNode(int key, node *haystack){
if(!haystack)
return NULL;
if(haystack->val == key)
return haystack;
if(haystack->val < key)
return getNode(key, haystack->left);
return getNode(key, haystack->right);
}
void getNode(int key, node *haystack, node *&result){
if(!haystack){
result = NULL;
return;
}
if(haystack->val == key){
result = haystack;
return;
}
if(haystack->val < key){
return getNode(key, haystack->left, result);
}
return getNode(key, haystack->left, result);
}
They end up being pretty much the same. If you actually want to delete, however, there's quite a bit more work involved, since you need to set the deleted node's pointer to the deleted node to NULL if the deleted node is a leaf, or you need to add the children of the deleted node to the tree (or delete those, too).
I'm assuming you want to pass a reference so you can zero out the pointer?
something like this should work:
void delete_node(int key, node*&p)
{
if (key < p->key) {
delete_node(key, p->left);
delete(p);
p = nullptr;
}
}
But it's a little naughty. It restricts the number of cases in which your function can be called and it adds some potentially surprising behaviour in that it alters its input argument. It also means that your node's left member is being zeroed out un-necessarily when nodes are deleted recursively (since the current node will itself be deleted anyway).
Hello I have a problem to returned variable from my pop function.
I will be happy if you could help me.
The function receives a pointer to the top of the list and should return the answer but I have a problem with a pointer to the list and intger the answer.
Function Code -
int pop(Node* top)
{
Node* tmp = top;
int ans = tmp->next;
top = top->next;
delete tmp;
return ans;
}
Node -
struct Node
{
int num;
Node* next;
}
Node* top = new Node;
The line int ans = tmp->next; appears to be the source of the problem. This is attempting to take the next pointer in the node, convert it to an int, and return it. What you (almost certainly) want is to retrieve the data from the node and return that, with something like int ans = tmp->num;.
Of course, that's not saying the code is perfect otherwise (e.g., it seems to lack any attempt at checking for, not to mention dealing with, errors), but at least with that change, it stands some chance of working correctly under some (ideal) circumstances.
Usually such a function throws an exception if the stack is empty or it has undefined behaviour. I used return value 0 in case when the stack is empty.
int pop( Node * &top )
{
int value = 0;
if ( top )
{
value = top->num;
Node *tmp = top;
top = top->next;
delete tmp;
}
return value;
}
There is another approach when function poo has type void that is when it returns nothing but simply removes the element on the top.
As mentioned in my comment you should split this up to two separate functions. One to get the value, and another one to pop (remove) the Node
void pop(Node*& top) { // Note the reference. You want to change the current top node.
// ^
if ( top ) {
Node *tmp = top;
top = top->next;
delete tmp;
}
}
int& top(Node* top) {
if ( top ) {
return top->num;
}
// Throw an appropriate exception if the stack is empty
throw std::out_of_range("Stack is empty.");
}
First, you are trying to delete tmp node, but top node still exist and value has to be returned as ans or top->next or in this situation top->num. Why do you initialize node tmp in the function when node tmp is a parameter? Why should node * &top be in the function parameters instead of tmp.
value = top->num doesn't fix the problem, because he wants the pointer from the top of the linked list not the random node inputed through the function parameters. To fix this problem Node * tmp should equal top and then value should be equal to tmp->num. Otherwise all other problems have been fixed.
//EDIT
Ignore everything before //edit because all that is questions about his question that I now already know. I have compiled this code and it completely worked for me.
struct Node
{
int data;
Node *next;
};
int pop(Node *head)
{
while(head->next != NULL)
{
head = head->next;
}
int value;
Node *tmp;
tmp = new Node;
value = head->data;
tmp = head;
delete tmp;
return value;
}
Compiled code link - http://ideone.com/7EgBhf
I'm learning C++ language and I'm trying to write BST, but something goes wrong.
I try to add element to empty tree, root is NULL, but after adding element root is still NULL despite of the fact that addiing was successful (I saw it in debug mode, node is set as tmp). I have no idea why it happens.
struct Node
{
int data;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
};
Tree createTree()
{
Tree tmp;
tmp.root = NULL;
return tmp;
}
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
void add(Tree* tree, int value)
{
addToNode(tree->root, value);
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree tree = createTree();
add(&tree, 10);
printf("%d", tree.root->data);
scanf("%*s");
return 0;
}
When you are passing your pointer into the function, you create a local version of the pointer. This local variable (node) does indeed point into the same memory that the outer pointer you were passing. However, any attempt to change this variable (not the memory it points to, but the pointer variable itself) will only change the local variable.
So your node points to the same memory location as your tree, but the node variable itself isn't equal to the tree variable, so your changes are not visible from the outer function.
It sounds complicated, sorry, but it's exacly the same thing as in this:
void foo( int a )
{
a++;
}
int main()
{
int var = 5;
foo( var );
std::cout << var;
}
Of course in this case the var will not change, it's the a that is being changed inside the function.
To fix the issue, pass a reference to the pointer instead of the pointer itself:
void addToNode(Node*& node, int value)
In the function addToNode when you assign to node, that assignment is not visible in the function calling addToNode because node is a local variable.
You should pass it as a reference instead:
void addToNode(Node*& node, int value)
{
...
}
Joachim already beat me to the answer, but I'll add this observation in anyway.
Your code leaks memory.
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
Every call to addToNode creates a new Node instance in tmp, but if the parameter Node* node is not NULL, this new Node is not deleted and does not become accessible by the rest of the application.
There are a number of ways to avoid this. The simplest would be to check if node is NULL before creating a new instance.
I need to make a linked list with classes. Each list will store two values: a URI and IP. After doing all the adding, I need to be able count the total number of items in the linked list. I have tried the following code but it doesn't compile. We are not allowed to use std::list. Any suggestions please?
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class ip_uri_store {
protected:
string ip;
string uri;
ip_uri_store *next;
public:
ip_uri_store(string huri, string hip);
void additem(string auri, string aip);
void deleteitem(string duri);
void findbyuri(string furi);
void findbyip(string fip);
int totalitems();
};
ip_uri_store *head = NULL;
ip_uri_store *curr = NULL;
void ip_uri_store::additem(string auri, string aip)
{
curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->uri = auri;
curr->next = new ip_uri_store;
curr->ip = aip;
curr->next = new ip_uri_store;
curr = curr->next;
curr = head;
}
int ip_uri_store::totalitems()
{
int i = 0;
curr = head;
while (curr->next != NULL) {
i += 1;
curr = curr->next;
}
return i;
}
int main(int argc, char *argv[])
{
if (argc == 1) {
cout << "123456, 123456#student.rmit.edu.au, Gordon Brown" << endl;
return (0);
}
head = new ip_uri_store;
curr = head;
int i;
for (i = 1; i < argc; i++) {
if (argv[i][0] == 'A') //add item
{
ip_uri_store.additem(argv[i + 1], argv[i + 2]);
i += 2;
}
else if (argv[i][0] == 'N') //print total tiems
{
cout << ip_uri_store.totalitems() << endl;
}
else {
cout << "command error\n";
return 0;
}
}
return (0);
}
Your ip_uri_store::additem() is pretty messed up. In it you change the curr object before you assign a new value to it:
curr->uri = auri;
curr->next = new ip_uri_store;
In doing so you change the last item in the list instead of assigning auri to the new item added later. (Interestingly, you got the order right with ip.)
I like the idea of giving pieces of code names, so that you can read what they do. Functions are what this is done with. For example, I'd factor out the code that finds the last list node
ip_uri_store *find_last_node(ip_uri_store *curr)
{
while (curr->next != NULL) {
curr = curr->next;
}
return curr;
}
and call it from ip_uri_store::additem():
void ip_uri_store::additem(string auri, string aip)
{
ip_uri_store *curr = find_last_node(head);
// ...
Now create a new object and remember its address in curr->next
// ...
curr->next = new ip_uri_store(auri,aip);
}
Your ip_uri_store::totalitems() returns an int. Why? Do you ever expect the count of objects to be negative? Better return an unsigned type.
You should consider what happens when you delete a list node. If it still points to a next object, chances are the pointer isn't stored anywhere else, and so the object (and those it points to) is (are) leaking. One way to deal with that is to write a destructor for ip_uri_store which deletes next. (If you want to delete a node without having it delete its own tail, you could assign NULL to its next pointer first.)
Also, according to the Rule of Three, you need to think about copying of list nodes. That's not easy to get right in the first try, so you might just want to forbid it:
class ip_uri_store {
private:
ip_uri_store(const ip_uri_store&); // not implemented
ip_uri_store& operator=(const ip_uri_store&); // not implemented
// ...
Instead of using global variables, you put them into class. That way you could have more than one list. Rename ip_uri_store to ip_uri_store_impl and pout it into a new ip_uri_store class:
class ip_uri_store {
private:
class ip_uri_store_impl { /* ... */ };
ip_uri_store_impl* head;
};
Since this class manages dynamically allocated objects, you need to think about destruction and copying such objects.
The wrapper class should have public methods that invoke the methods of ip_uri_store_impl whenthey nedd to. Functions like totalitems(), which operate on the whole list (instead of a node), should probably be implemented in the wrapper class.
You need to provide the two arguments to the constructor of your ip_uri_store class:
// The constructor call needs two arguments
curr->next = new ip_uri_store(huri, hip);
You cannot call instance methods on the class itself:
// Invalid, totalitems() is valid only on instances of ip_uri_store.
cout << ip_uri_store.totalitems() << endl;
Why are the variables head and curr global? They really should be data members of a class.
Pull out the ip, uri and next members of ip_uri_store and put them in their own structure, say ip_uri_store_node. Then, ip_ur_store_node can define a constructor that initializes them. Then make ip_uri_store hold the head and curr pointers to ip_uri_store_node instances.
This is what I mean:
struct ip_uri_store_node
{
string ip;
string uri;
ip_uri_store_node* next;
ip_uri_store_node(const char* u, const char* i)
: ip(i), uri(u), next(0) {}
};
class ip_uri_store
{
private:
ip_uri_store_node* head;
ip_uri_store_node* curr;
public:
// Initializes head and curr
ip_uri_store();
// These functions woud act on head and curr.
void additem(string auri, string aip);
void deleteitem(string duri);
void findbyuri(string furi);
void findbyip(string fip);
int totalitems();
};
int main()
{
ip_uri_store list;
// Do things with the list...
return 0;
}
The function additem can create new instances of ip_uri_store_node like this:
curr->next = new ip_uri_store_node(auri, aip);
The rest is up to you.