I am writing a code to delete a node from a linked list when only the pointer to the node is given and the head node is not given
/*
struct Node {
int data;
struct Node *next;
Node(int x) {
data = x;
next = NULL;
}
}*head;
*/
// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
node=(node->next);
}
does not delete the present pointer in the list, but,
/*
struct Node {
int data;
struct Node *next;
Node(int x) {
data = x;
next = NULL;
}
}*head;
*/
// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
*node=*(node->next);
}
Deletes the node from the linked list
Why? what is the difference between the approach?
let's take a simpler example with integers instead of nodes:
void Modify_1 (int *piVal, int *piNewVal)
{
//piVal has adresse of i passed as argument
// similar to node = (node->next);
piVal = piNewVal; // This change just the VALUE of the pointer passed as argument !
//piVal has adresse of j now
}
void Modify_2 (int *piVal)
{
// similar to *node=*(node->next);
*piVal = 0; // This change de content of pointer
}
int main ()
{
int i = 3;
int j = 5;
Modify_1 (&i, &j);
cout << i << endl; // This print 3 !
Modify_2 (&i);
cout << i << endl; // This print 0
return 0;
}
piVal is a pointer that contains i address VALUE. Exemple : 0x00bcfdb4
This address is passed as a value (0x00bcfdb4) if you want to function.
As long as you do not write *piVal, you are not going to change the pointed content but just the VALUE of the address.
If you want to change the pointer, you need an **int (in your case **node)
void Modify_3 (int **piVal, int *piNewVal)
{
*piVal = piNewVal; // this change de pointer adresse
}
int main ()
{
int x = 5;
int *pi = &x;
Modify_3 (&pi, &x);
cout << *pi << endl; // This print 5
}
Assigning to a (non-reference) argument of a function has no effect outside that function.
(The most important thing to learn about pointers is that there is nothing special about pointers.)
It's the same as how
void f(int x) { x = 1000; }
int main()
{
int x = 0;
f(x);
std::cout << x << std::endl;
}
will print 0, not 1000.
Thus, your first attempt does not modify anything and has no observable effect.
Your second attempt also has a problem - it copies the next node but doesn't delete it.
If your nodes are dynamically alloacted, and they usually are, this is a memory leak.
You need something like this:
void deleteNode(Node *node)
{
Node* old = node->next;
*node = *(node->next);
delete old;
}
It's a bit unconventional to modify a list by copying nodes, though, since it is very inefficent if the node's data is big.
Usually, you update the links in the list, but in order to do that you need to know what the previous node is.
To delete a node from a linked list when only the pointer to the node is given - that's possible only in doubly linked list or in indexed list. The nature of list itself says that you have to modify another node to remove one from existing chain.
In first case node contains pointer to previous node and cost is O(1), while with indexed list you have index (key) and access to mapping\indexing mechanism, cost of getting previous node depends on method used. For the last reason indexed lists are sometimes implemented as doubly-linked.
Related
I would appreciate some help relative to my code solution, which deals with linked list management in C. I'll already declare the only strange thing with my request: I am writing a C++ file, but I am actually mostly leveraging C resources (malloc(), free(), etc.); that said, given the basic code I provide, I am confident no one will have trouble with that.
I want to write a function to add elements to the end of the list and one to delete elements from it, that work in any edge case. Given my desire, the removal function was the one that I struggled the most with, but also the one that made me realize how little I am understanding pointers.
I will now share the code I produced, that should be working fine, but:
It can surely be greatly improved both in terms of clarity and performance
I think that showing it to the community will highlight many of the flaws present in my solution
// The plan is to create a linked list and to be able to add and delete its elements
#include <iostream>
using namespace std; // I can write output lines as cout << "Hi!", rather than std::cout < "Hi!"
#include <cstdlib> // needed for malloc() in C++
struct node {
int data;
node* nextPtr; //"struct node* nextPtr;" : This would be the syntax for plain old C: you always have to type the "struct" keyword
};
node* createElement(int data) {
node* newElemPtr = (node*)malloc(sizeof(node)); // the "(node*)" cast is required by C++, and is not used in C
newElemPtr->data = data;
newElemPtr->nextPtr = NULL;
return newElemPtr;
}
void appendElement(int data, node** head) { // Adds a new node at the end of the list
// I pass as argument a pointer to pointer (double pointer) to node, so that I can edit the head node
// if the list is empty, without having to return a new node pointer as head: my function indeed features
// "void" in its signature
node* elemPtr = NULL;
elemPtr = createElement(data); // elemPtr is a pointer to the new node
if (*head == NULL) {
*head = elemPtr;
}
else {
node* currPtr = *head; // currPtr is the temporary variable that visits each node of the linked list
while (currPtr->nextPtr != NULL)
currPtr = currPtr->nextPtr;
currPtr->nextPtr = elemPtr; // Set last element's nextPtr to "elem", i.e., a pointer to the new element
}
};
void removeElement(int data, node** head) { // Remove all the nodes whose data content matches the "data" argument
int presence_flag = 0; // Flag used to check whether the required data is present at all in the linked list
if (*head == NULL) {
return;
}
else {
node* currPtr = *head;
node* prevPtr = *head;
while (currPtr != NULL) {
// This is the case in which I find a node to delete (it matches the "data" query), and it is not the first of the list
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
// This is the case in which I find a node to delete and it is the first of the list
else if (data == currPtr->data && currPtr == *head) {
// This is the case in which I have to delete the first node, but the list features other nodes
if (currPtr->nextPtr != NULL){
*head = currPtr->nextPtr; // Move *head forward
currPtr = *head; // Do the same with currPtr, in order not to break the while() loop
free(prevPtr); // As *head has already been re-assigned, I leverage prevPtr to delete the old *head
presence_flag = 1;
}
// This is the case in which I have to delete the first and only node of the list
else {
*head = NULL;
currPtr = *head;
presence_flag = 1;
}
}
// This is the case in which the current node does not match the queried "data" value
else{
prevPtr = currPtr; // Update prevPtr
currPtr = currPtr->nextPtr; // Move currPtr forward
}
}
}
if (presence_flag == 0)
cout << "There is not any node with value " << data << " in the linked list.\n\n";
// Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
// Q2: Should I free() everythin before ending the main(), at least as a good practice?
// Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value?
// Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
};
void printLinkedList(node* head) { // Here I return nothing, so I can freely edit "head" (i.e., there is no need for a temporary pointer)
if (head == NULL) {
cout << "The linked list is empty.\n";
}
else {
int elemCounter = 0;
while (head != NULL) {
elemCounter += 1;
cout << "elem N. " << elemCounter << ": data value = " << head->data << "\n"; // head->data is equal to (*head).data
head = head->nextPtr;
}
}
};
int main(int argc, char* argv[])
{
//cout << "Size of a single node of the list = " << sizeof(node) << "\n";
// == 16. On a 64 bits machine, an int ("data") requires 4 bytes.
// The pointer requires 8 bytes; the remaining 4 bytes are padding
node* head = NULL;
appendElement(1, &head);
appendElement(2, &head);
appendElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 3...\n\n";
removeElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 4...\n\n";
removeElement(4, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
return 0;
}
As you can see from the comments embedded in the code, I have 3 doubts that captured my interest while coding the node removal function:
Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
Q2: Should I free() everything before ending the main(), at least as a good practice?
Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value? Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
I hope that featuring these "additional" questions is something reasonable to put here, as maybe someone in the future may have the same doubts I had.
I know there are plenty of ready-to-copy-and-paste solutions for my task, but I think I can really learn this stuff if I see why my precise design choices are not optimal/wrong.
I thank everyone for the time spent reading this.
There are many duplicated code. Also the function should not output any message. It is the caller of the function that decides whether to output a message. So the function should have the return type bool if you are considering the program as a C++ program or bool or int if you are considering the program as a C program.
The function removeElement invokes undefined behavior because in its paths of execution you are not always resetting correctly values of the pointers currPtr and prevPtr after deleting a node.
For example after this code snippet
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
prevPtr and currPtr will be equal each other.
I would define the function the following way
int removeElement( node **head, int data )
{
int deleted = 0;
while ( *head )
{
if ( ( *head )->data == data )
{
deleted = 1;
node *current = *head;
*head = ( *head )->next;
free( current );
}
else
{
head = &( *head )->next;
}
}
return deleted;
}
As for your question
Q3: Is there a way to make this function by not using a double pointer
as input and by also keeping "void" as return value? Of course, it
should still work in the tricky edge case of the last element in the
list that has to be deleted
then in C you can not achieve this. In C++ you can pass the pointer to the first node by reference. In C passing by reference means passing an object indirectly through a pointer to it. So in C you have to use a double pointer in such a case.
Of course just setting a pointer to NULL without freeing data pointed to by the pointer that was dynamically allocated produces a memory leak. And you should free all the allocated memory then it is not required any more.
I am a student who is making a tree structure in cpp for a project. The program is supposed to get a string from an input and enter it into a tree. The tree is organized by each node having the pointer to its next sibling (called sibling) and its first child (called child). However, when I try to make a function that recursively adds members to the tree, the function doesn't work. All of the neccisarry steps are completed, yet for some reason the nodes are not linked. Please take a look at my code, and thank you for reading.
#include <iostream>
#include <string>
struct node{
char data;
node *sibling = nullptr;
node *child = nullptr;
};
struct node* newNode(char data, unsigned int m)
{
if(m!=0) {
struct node *node = (struct node *) malloc(sizeof(struct node));
// std::cout << "node write" << std::endl;
node->data = data;
node->sibling = newNode(124,m-1);
node->child = newNode(124,m-1);
return (node);
}
}
char TreeOutput(node *n){
return *(char *)n;
}
void nodeAdd(node *currentNode, std::string str, int m ){
int n = str.length();
if(m<n){
if(TreeOutput(currentNode) == str[m]){
std::cout << m << "1..1" << std::endl;
nodeAdd(currentNode->child,str,m+1);
}
else if(TreeOutput(currentNode) == 124){
std::cout << m << "2..2" << std::endl;
currentNode = newNode(str[m],2);
nodeAdd(currentNode->child,str,m+1);
}
else{
std::cout << m << "3..3" << std::endl;
nodeAdd(currentNode->sibling,str,m+1);
}
}
}
int main() {
struct node *root = newNode('X',6);
std::cout << root->data << std::endl;
nodeAdd(root->child,"APE",0);
std::cout << root << std::endl;
return 0;
}
The reason they're not getting linked in this line:
currentNode = newNode(str[m],2);
Is because you're taking a node* to the function, then assigning the pointer inside the function a new value. So you change currentNode's value inside the function, but not in its parent. You need to take either a reference to the pointer or a double pointer for this to work correctly:
void nodeAdd(node*& currentNode, std::string str, int m )
It might make more sense if we remove the syntactic sugar for pointers. Imagine a pointer to node was written Ptr<node>, if we wrote:
void nodeAdd(Ptr<node> currentNode, std::string str, int m )
It's be obvious we're taking the pointer by value, so it now lives in a variable within the function. If we take it by reference, we can change its value outside the function:
void nodeAdd(Ptr<node>& currentNode, std::string str, int m )
Tangentially, you have char data in your node struct, I think you want a pointer there too (or an array).
In terms of general style, if you're trying to write C++, usually the contents of newNode would go in a constructor so you could just write new node(args...) to create a new instance. The TreeOutput function will work in this case because of the simple layout of node, but in general, casting to the first member of a struct doesn't have to work (in particular in the case of inheritance or virtual methods), so I'd at the very least access the member directly return node->data;
I'm trying to add elements to a list, but can't figure out why the push_back method is repeating the last added element. To illustrate:
Each node object consists of a data and head field. In the code below, I iterate through an array of ints, create a new node to store each int, and push_back the element to the list L. The repeated node is always the last one added to the list (in the picture above when iteratror i=1)
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
I included the complete code of the disjoint data structure below. I read on cplusplus.com that push_back increases the container size by 1. So I'm a little perplexed why an extra node is being added to the list.
#include <iostream>
#include <list>
struct node{
int data;
node* head;
};
void makeSet(std::list<node>& L,int arr[]){ //asterick is before the variable name
node *headNode = new node;
headNode->data = arr[0]; //representative node
headNode->head = headNode; //point to itself
L.push_back(*headNode);
}
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
int findSet(node* element){
return element->head->data;
}
int main(int argc, const char * argv[]) {
std::list<node>List;
std::list<node>::iterator Itor;
int dataArr[]={1,2,3,4,5};
int size = sizeof(dataArr)/sizeof(dataArr[0]);
Itor = List.begin();
makeSet(List,dataArr);
addElements(List,dataArr,Itor,size);
for (Itor = List.begin();Itor!=List.end();Itor++){
std::cout << Itor->data << std::endl;
}
}
Note that the size of the list in your example is 2. This means only nodes 0 and 1 are valid. This extra duplicate link is likely a Sentinel Value.
Often you'll find linked lists terminate with a null pointer, but it's just as easy to define the end of the list as a link that points to itself. This may have additional advantages, such as providing a one-past-the-end link to return as list::end.
Whatever its benefits, it is outside the bounds of the list so best that you not mess with it.
Here's the reference code:
#include <iostream>
using namespace std;
class linkedList {
struct listNode{ //a node of a list
int value;
struct listNode *next;
};
listNode *head;
public:
linkedList(){
cout << "hello1\n";
head = NULL;
};
linkedList(listNode* a){
cout << "hello2\n";
head = a;
};
~linkedList();
listNode* getHead() {return head;}
void appendNode(int);
//inline Search function due to unable to function outside of class definition
listNode* rangeSearch(int a, int b){
//listNode to search
listNode *search = head;
//listNode* toReturn = new listNode;
//listNode to return list of values that are found within range
linkedList *found = new linkedList;
while(search){
//if the current value is within range, then add to list
if(search->value >= a && search->value <= b){
//append searched value onto found
found->appendNode(search->value);
//after appending, go to next value
}
search = search->next;
}
return found->getHead();
}
void display();
};
int main()
{
cout << "Programmer : n\n";
cout << "Description : \n";
linkedList* list = new linkedList;
int x = 12;
//values to search
int s1 = 10, s2 = 14;
// adds 2 to each number on list for 5 times
for(int i = 0; i < 5; i++){
list->appendNode(x);
x += 2;
}
//create something to hold pointer of found to be deleted when done using
//print list
cout << "Original set of numbers in linked list: ";
list->display();
cout << "\nThe following are the values withing ranges: " << s1 << " and " << s2 << ":\n";
//EDITED:
//list->rangeSearch(s1,s2);
linkedList foundList(list->rangeSearch(s1,s2));
foundList.display();
//End of edit 6:40PM 7/18/13
cout << "\nHere are the original set of numbers in linked list (again): ";
list->display();
delete list;
return 0;
}
void linkedList::appendNode(int newValue)
{
listNode *newNode = new listNode(); // To point to a new node
listNode *nodePtr; // To move through the list
// Allocate a new node and store newValue there.
newNode->value = newValue;
newNode->next = 0;
// If there are no nodes in the list
// make newNode the first node.
if (!head)
head = newNode;
else // Otherwise, insert newNode at end.
{
// Initialize nodePtr to head of list.
nodePtr = head;
// Find the last node in the list.
while (nodePtr->next)
nodePtr = nodePtr->next;
// Insert newNode as the last node.
nodePtr->next = newNode;
}
}
void linkedList::display() {
for(listNode* p = head; p != NULL; p = p->next)
cout << p->value << ' ';
}
linkedList::~linkedList()
{
cout << "\ndestructor called";
listNode *nodePtr; // To traverse the list
listNode *nextNode; // To point to the next node
// Position nodePtr at the head of the list.
nodePtr = head;
// While nodePtr is not at the end of the list...
while (nodePtr != NULL)
{
// Save a pointer to the next node.
nextNode = nodePtr->next;
// Delete the current node.
delete nodePtr;
// Position nodePtr at the next node.
nodePtr = nextNode;
}
}
So a couple of questions here. First, why is it when I try to put the rangeSearch member function outside of the class definition, the compiler gives an error saying listNode* type is not recognized?
Second, this has to do with destructors. In this program, 2 instances (list & found list) were created but only 1 destructor was called. Can someone explain why? My intuition tells me that the dynamically allocated pointer to linkedList object did not get destructed. However, I don't know why. The reason I had to use dynamically allocated memory is primarily because I want to pass the pointer back to the main function. If I don't, when rangeSearch exits, the pointer will be passed back to main but whatever list the pointer had would be deconstructed after
return ptr; (assume ptr is a pointer to a linkedList declared in rangeSearch)
which will cause my program to crash because, now the address has nothing in it and I'm trying to call... nothing.
Well, as usual I would appreciate whoever the great Samaritan out there who would be more than willing to educate me more about this.
First, you are having an issue with scoping. In C++, the curly braces define a new scope, so you are defining listNode inside the class linkedlist. If you want to access it, you'd have to use the scoping operator as such linkedlist::listNode
I don't entirely understand your second question. I only see one call to delete, so why do you think two destructors will be called? The destructors are only called when you call delete, so unless you specify that you want to destroy it, it's still going to be there.
Although I don't entirely understand your question, I see that you returned a pointer to the head in rangeSearch, but you don't assign it to anything. What this means is that you will have a memory leak; you allocated memory for the found, but then don't do anything with it. Actually since you only return the head, you still wouldn't be able to delete it if you did assign something to it, because you wouldn't have access to linked list itself.
linkNode is nested inside of linkedList. Move listNode outside of the linkedList class, and you won't get the first error. Or you can use it's full declaration, linkedList::listNode. Also, if you leave linkNode nested, you will have to make it public.
In main, you can just say
linkedList list;
instead of
linkedList* list = new linkedList;
rangeSearch() is returning a value, but that value is never being assigned to anything in main(). rangeSearch() is allocating a linkedList, but it never gets deleted.
I am kind of new to c++ and got headache with this pointer and stuff!
I need to iterate through list of struct which is linked list, read the data of struct and pop that entry!
this my struct :
struct node {
map<string,double> candidates;
double pathCost;
string source;
node *next; // the reference to the next node
};
by reading this post I create my list like :
list<node*> nodeKeeper;
and then initialized the first value:
node *head;
head= new node;
head->pathCost = 0.0;
head->source="head";
head->next = NULL;
thin fill the list and struct :
for(unsigned int i = 0; i < sourceSentence.size(); i++){
node *newNode= new node; //create a temporary node
//DO STUFF HERE
//push currunt node to stack
nodeKeeper.push_back(newNode);
head = newNode;
}
now I have list of struct and I want to iterate through it and pop the elements:
for (list<node*>::const_iterator it=nodeKeeper.begin();it!=nodeKeeper.end();it++){
it->pop_front();
}
which gives me this error:
error: request for member 'pop_front' in '*
it.std::_List_const_iterator<_Tp>::operator->()', which is of
pointer type 'node* const' (maybe you meant to use '->' ?) make: ***
[main3.o] Error 1
It looks like that my iterator points inside the list , not the list itself!
Can you tell me what is wrong here?!
If your goal is to have a single list of your node struct, there is no need to manage next pointers your self. Inserting would stay the same (minus the head = line)
To pop all element of the list you would do something like
int sizeOfList = nodeKeeper.size();
for( int i =0; i < sizeOfList; i++) {
//if you want to do something with the last element
node * temp = nodeKeeper.back();
//do stuff with that node
//done with the node free the memory
delete temp;
nodeKeeper.pop_back();
}
Compiling/running example here: http://ideone.com/p6UlyN
If all you need to do is remove the elements, use std::list::clear:
nodeKeeper.clear();
To read the contents of the element, then remove, try this:
for (std::list<node*>::const_iterator it = nodeKeeper.begin(); it != nodeKeeper.end(); ++it) {
std::cout << (*it)->source;
// do more reading
nodeKeeper.pop_front();
}
or with C++11:
for (const auto& a : nodeKeeper) {
std::cout << a->source;
nodeKeeper.pop_front();
}