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).
Related
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?
Function I'm attempting to write:
bool LinkedList::removeFirst(Node *node, int v);
If v is found in the list, return true and remove the first element of the list. If v is not in the list, return false.
My attempt at the solution:
bool LinkedList::removeFirst(Node *node, int v) {
if(h==NULL)
return false;
if(h->value==v)
return true;
else {
bool result = findNum(h->next,v);
if(result == true){
Node *n = node;
free(n);
} else {
return false;
}
}
}
I understand that my current solution will remove every node in the list, but I can't think of a way to only remove the first in a recursive implementation.
This is one way to do it:
bool LinkedList::removeFirst (int v)
{
return removeFirstInSublist (&head, v);
}
bool LinkedList::removeFirstInSublist (Node ** node, int v)
{
if (!node || !*node) return false;
Node * p = *node;
if (v == p->value)
{
*node = p->next;
delete p; // or free(p);
return true;
}
Node * q = p->next;
bool b = removeFirstInSublist (&q, v);
if (q != p->next)
p->next = q; // This is the line that actually removes the node from the list.
return b;
}
I believe this will work (but be warned that I haven't tried it.) Basically, the removeFirstInSublist method does the work, and we need to take a pointer to pointer because we need to return the address of the node that replaced the one we passed in if we did end up removing it. The removeFirst method just calls the actual function with the correct value.
You can choose to make the sublist method private or leave it public, but obviously the interface is a little clunky. I choose pointer to pointer instead of a more friendly reference to pointer because (should you choose to make it public) I wanted the user to know that the pointer they pass in might get changed.
So I already have this Insert function for a Value in my Tree how can I convert it to this type of void function?
void InsertValue(Node* root, int value){
this is my normal function:
Node* Insert(Node* root,int value) {
if(root == NULL) { // empty tree
root = CreateNode(value);
}
// if data to be inserted is lesser, insert in left subtree.
else if(value <= root->value) {
root->left = Insert(root->left,value);
}
// else, insert in right subtree.
else {
root->right = Insert(root->right,value);
}
return root;
}
Thanks for your help
You can do one of two things:
Make root a pointer to a pointer. This can work well but the syntax can be a bit awkward, requiring you to dereference root prior to use.
Use a reference to a pointer. A reference gives you the "power" of the double pointer mentioned above without any of the awkward syntax and it's trivial to do.
So option #2 it is. How to do it? Simply change he function to accept root as a reference to a pointer.
void InsertNode(Node*& root, int value)
{
// your existing code!
}
Without a return value preserving a potentially added new node passed back to the caller, you have to return the potential inserted node somehow. If you want a void result type, you need to pass the target pointer by address (Node **), or by reference (Node *&). Given this is tagged C++, I'd use the latter.
void Insert(Node*& root, int value)
{
if(root == NULL)
root = CreateNode(value);
else if(value <= root->value)
Insert(root->left,value);
else
Insert(root->right,value);
}
Note that this always hangs duplicates on the left side of a node. To hang duplicates on the right side, change this:
else if(value <= root->value)
Insert(root->left,value);
to this:
else if(value < root->value)
Insert(root->left,value);
Finally, if you want unique keys in your tree (i.e., ignore duplicates) the following will do that:
void Insert(Node*& root, int value)
{
if(root == NULL)
root = CreateNode(value);
else if (value < root->value)
Insert(root->left,value);
else if (root->value < value)
Insert(root->right, value);
// else key is already present; do nothing.
}
This assumes a strict weak ordering of the key values, which exhibits the following property:
if (!(a<b || b<a))
then a == b
Best of luck.
I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.
I'm a programming student in my first C++ class, and recently we covered linked lists, and we were given an assignment to implement a simple one. I have coded everything but my pop_back() function, which is supossed to return a pointer to the Node that needs to be deleted in Main(). No Node deletion is to be done in the actual function. So my question is:
Would you be willing to help point me in the right direction for my pop_back() function? Also, if you notice anything else that I'm doing wrong, let me know.
Also, this linked list is just to work with strings. In this case, a grocery list, so one string for the quantity of the item(1,2), and one string for the item type. (Milk, Eggs, etc.)
Below I've included my List & Node class implementations, so you can get an idea of what I've done so far.
Node.cpp
Node::Node(void)
{
descrip = " ";
quantity = " ";
previous = NULL;
next = NULL;
}
Node::Node(string q, string d)
{
descrip = d;
quantity = q;
previous = NULL;
next = NULL;
}
Node* Node::GetNext()
{
return next;
}
Node* Node::GetPrevious()
{
return previous;
}
void Node::SetNext(Node * setter)
{
next = setter;
}
void Node::SetPrevious(Node * setter)
{
previous = setter;
}
List.cpp
List::List(void)
{
first = NULL;
last = NULL;
numNodes = 0;
}
Node* List::GetFirst()
{
return first;
}
Node* List::GetLast()
{
return last;
}
void List::SetFirst(Node* setter)
{
first = setter;
}
void List::SetLast(Node* setter)
{
last = setter;
}
int List::GetNumNodes()
{
return numNodes;
}
void List::push_front(Node* item)
{
if (first == NULL)
{
first = item;
last = item;
}
else
{
Node* pFirst = first;
item->SetNext(pFirst);
first = item;
numNodes++;
}
}
void List::push_back(Node * item)
{
if (last == NULL)
{
first = item;
last = item;
}
else
{
last->SetNext(item);
last = item;
numNodes++;
}
}
Node* List::pop_front()
{
Node* temp = first;
first = first->GetNext();
if (first == NULL)
{
temp = first->GetNext();
first = p;
}
if (first == NULL)
{
last = NULL;
}
if (numNodes > 0)
{
numNodes--;
}
return temp;
}
Node* List::pop_back() // this whole function may be wrong, this is just my attempt at it
{
Node* temp;
temp = first;
while((temp->GetNext()) != NULL)
// im stuck here
}
Some pointers:
0x1243bfa3
0x45afc56e
0xdeadbeef
Some more pointers:
You should prefer to initialize your class members in the initialization list, not in the constructor's body.
In C++, unlike C89, we declare and define a function with no parameters as void f();, not void f(void);.
In C++ we commonly reset pointers with 0, not NULL.
See below for what I mean in code.
Good C++ code will try to take advantage of RAII. This implies avoiding primitive pointers for the most part. In this case plain old std::auto_ptr<> would make a perfectly sufficient substitute for the primitve Node* pointers. However, I do reckon part of the exercise here is pointer arithmetics, and so I just leave this as a side-note.
It would be useful for us if you'd attach the class declarations. I assumes all those accessors and mutators, GetFirst() and SetFirst() etc., are there because they are public. That's a bad idea. First, they expose the private pointers, which defeats the whole point of accessor. Second, they don't do anything special so they're just extra code -- which means extra room for bugs. This brings me to the next point.
Your mutators are incorrect. You blindly assign a new value to the private member pointer, without deleting what you had before. That's a memory leak.
Ever tried to pop_front() when the list is empty?
Finally, 8 being a round number it's time we get to the question at hand. pop_back(). My question to you is, why are you traversing the list all the way to the end if you so meticulously maintain a pointer to the last node of your list? Indeed, if you wouldn't bother with maintaining a pointer to the end of the list then you'd have to traverse all the way to the last node in order to pop it. And for that you were in the right direction. Except that ...
When you access members through pointers, as in first->GetNext(), always make sure first isn't a null pointer -- or else state in the function's documentation comment that you assume the pointer is not null.
These should get you started.
Points 1, 2 and 3 in code:
Node::Node()
: descrip(" "), quantity(" "), previous(0), next(0)
{
}
So if I understand this right you just want to run through your linked list until you get to the last node in the linked list and return the pointer to it?
I'm pretty sure what you have there will do it except
Node* List::pop_back() // this whole function may be wrong, this is just my attempt at it
{
Node* temp;
temp = first;
while(temp->GetNext() != NULL)
{
temp = temp->GetNext();
}
return temp;
}
So if I read it right, there it will continually loop around until it gets to the node with none in the line behind it, then return it.
I like the previous posters answer, but one thing you might want to keep in mind is if you have an empty list. Then your first pointer will equal NULL and you would be trying to call NULL->GetNext() basically and Seg Fault. I think you can edit the above code slightly and still get have it work like this:
Node* List::pop_back()
{
Node* temp;
temp = first;
while(temp != NULL && temp->GetNext() != NULL)
{
temp = temp->GetNext();
}
return temp;
}
This will have the function return NULL if there is nothing in the list and still work properly.
It would definitely have helped me if you also had posted your class declaration. I cannot guarantee that the below is correct but it makes sense to me
Node* List::pop_back()
{
Node *temp = NULL;
if(numNodes == 1)
{
temp = first;
// setting the list pointers to NULL
first = NULL;
// setting the list pointers to NULL
last = NULL;
//You should also probably remove the links from your node
//to the next and previous nodes but since you didn't specify
//this it is up to you
numNodes--;
}
else if(numNodes > 1) //more than one element
{
//the pointer you want to return
temp = last;
//For clarity I am creating another variable here
Node *newLast = temp->GetPrevious();
//Setting the new last node to point at nothing so now temp
//is "disconnected from the list"
newLast->next = NULL;
//the last pointer of the list is now pointing at the new last node
last = newLast;
//You should also probably remove the links from your node
//to the next and previous nodes but since you didn't specify this it is up to you
numNodes--; //decrement the counter
}
return temp;
}