I sketched up this small single linked list example. But for some reason, new node do not get appended to the list correctly.
Can someone help me by detecting the error please?
struct Node {
Node(int x, Node *next = nullptr) : x{x}, next{next} {}
int x;
std::shared_ptr<Node> next;
};
class LinkedList {
public:
LinkedList(std::vector<int> const &v) {
for (auto i = 0; i < std::size(v); ++i) {
auto temp = std::make_shared<Node>(v[i], nullptr);
if (head == nullptr) {
head = temp;
} else {
auto ptr = head;
while (ptr != nullptr) {
ptr = ptr->next;
}
ptr = temp;
}
}
}
std::shared_ptr<Node> head = nullptr;
};
int main() {
auto v = std::vector<int>{1, 2, 3};
auto l = LinkedList{v};
}
Think about what ptr is when you assign it to temp.
It is a local variable that you initialized with the link list's head member before the while loop. When you assign temp to it, you know its value is the nullptr, okay. So you have assigned a pointer to a new node to a local variable that currently holds a nullptr. How is that going to add an item to your linked list?
To insert an item into the list you need a pointer to a node in the list and assign a pointer to its next member e.g.
...
auto ptr = head;
while (ptr->next != nullptr) {
ptr = ptr->next;
}
ptr->next = temp;
...
But as mentioned in comments of this answer, the way you are inserting each item has O(n) running time as you need to iterate through the entire list to find the end. The correct way to do this would be for each insert to be O(1).
Related
I don't know where I am wrong, when I debugged the code I found out that the 'new node' address is 'new node' address, basically the new node is referring to itself
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct node new_node;
new_node.a = item;
parent->addr = &new_node;
parent->addr->addr = NULL;
}
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct node new_node;
new_node.a = item;
parent->addr = &new_node;
parent->addr->addr = NULL;
}
The lifetime of new_node is limited to the function. Once that function returns, it is no longer valid.
In order to circumvent this, it is necessary to dynamically allocate memory for new_node. Of course, as already pointed out, this means explicitly deallocating the memory eventually.
Note: as this is C++ rather than C, we do not need to add struct to the front of the type in use, and NULL is better spelled nullptr.
void insertend(node *parent, int item)
{
while (parent->addr != nullptr)
parent = parent->addr;
node *new_node = new node;
new_node.a = item;
parent->addr = new_node;
parent->addr->addr = nullptr;
}
As C++ structs are just classes with default public access, it's also worth noting we could implement this as a member function. Something like:
template <typename T>
struct Node {
T value;
Node<T> *next;
void append(T val) {
Node<T> * temp = this;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new Node<T>;
temp->next->value = val;
temp->next->next = nullptr;
}
};
int main() {
auto n = Node<int>();
n.value = 27;
n.append(42);
n.append(34);
for (Node<int> *t = &n; t != nullptr; t = t->next) {
std::cout << t->value << std::endl;
}
return 0;
}
The next step would be implementing a constructor and destructor.
One more thing to keep in mind is that getting to the end of a list this way is O(n) time complexity. Doing it over and over again is costly. If you have Node::append return a pointer to the new Node, then you can call append on that.
template <typename T>
struct Node {
T value;
Node<T> *next;
Node<T> *append(T val) {
Node<T> * temp = this;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new Node<T>;
temp->next->value = val;
temp->next->next = nullptr;
return temp->next;
}
};
int main() {
auto n = Node<int>();
n.value = 27;
auto n2 = n.append(42);
n2 = n2->append(34);
n2 = n2->append(15);
for (Node<int> *t = &n; t != nullptr; t = t->next) {
std::cout << t->value << std::endl;
}
return 0;
}
I’m not sure what the addr refers to, but I would assume it points to the next node in the linked list. In your code, there needs to be another node to use as a temporary node, because the parent node keeps being reassigned, and the previous items are lost. We also need to check that the parent node is not NULL.
void insertend(struct node **parent, int item)
{
node *new_node = new node;
new_node->a = item;
new_node->addr = NULL;
if(*parent == NULL)
{
*parent = new_node;
}
else
{
node *temp = *parent;
while (temp->addr != NULL)
temp = temp->addr;
temp->addr = new_node;
}
}
The if statement checks whether the parent node is NULL. If true, then we assign parent node to new_node. If false, then we go to the end of the list and assign the next node in the list to new_node.
As Igor correctly pointed out, your new node gets destroyed when the function finishes. So, in this context you could just allocate memory. You can use the new operator for this. However, you would need to explicitly free the memory, eventually.
void insertend(struct node *parent, int item)
{
while (parent->addr != NULL)
parent = parent->addr;
struct * new_node = new node;
new_node->a = item;
parent->addr = new_node;
parent->addr->addr = NULL;
}
I need help in understanding why my Linked List approach doesn't work as expected.
#include <iostream>
using namespace std;
class Node {
public:
int Data;
Node* Next;
Node(int data) {
Data = data;
Next = NULL;
}
};
void insertNodeAtEnd(Node* HEAD, int data) {
Node* it = HEAD;
if (HEAD == NULL) { HEAD = new Node(data); }
else {
while (it->Next != NULL) { it = it -> Next; }
it -> Next = new Node(data);
}
}
void printLinkedList(Node* HEAD) {
Node* it = HEAD;
while (it != NULL) {
cout << it->Data << endl;
it = it -> Next;
}
}
int main() {
Node* HEAD = NULL;
// Node* HEAD = new Node(0);
insertNodeAtEnd(HEAD, 5);
insertNodeAtEnd(HEAD, 2);
insertNodeAtEnd(HEAD, 10);
printLinkedList(HEAD);
return 0;
}
The above main() function does NOT work (ie: no output, and the HEAD keeps resetting to NULL as soon as the control leaves insertNodeAtEnd()), and I've found similar questions here on SO which explain that this is because the pointer is being passed by value, and that makes partial sense to me.
Why does it work as expected when I replace Node* HEAD = NULL; with Node* HEAD = new Node(0); in the main() function, if the pointer is being passed as value?
How are nodes getting added if I initialise HEAD like Node* HEAD = new Node(0);, but not in the case where HEAD = NULL initially? I was able to get it to work properly by using pointer to pointer but I can't understand why this approach doesn't work. I am sorry if I haven't explained my question properly, please let me know if any clarification is required.
The underlying issue can be reduced to this code:
void insertNodeAtEnd(Node* HEAD, int data) {
//...
if (HEAD == NULL) { HEAD = new Node(data); }
//...
}
int main() {
Node* HEAD = NULL;
insertNodeAtEnd(HEAD, 5);
//...
You seem to assume that assigning to HEAD inside insertNodeAtEnd would change the HEAD variable inside of main. This is not true. Your pointer is passed by value, so the address is copied for the function. Changing this copied variable will not change the value of HEAD inside of main.
To fix this you could pass a pointer to a pointer instead, like this:
void insertNodeAtEnd(Node** HEAD, int data) {
//...
if (*HEAD == NULL) { *HEAD = new Node(data); }
//...
}
int main() {
Node* HEAD = NULL;
insertNodeAtEnd(&HEAD, 5);
//...
This pointer to a pointer is still passed by value, however the pointer that it points to will be the same as the on from main.
The problem come from your first insertion. You change the value of head which is reset when you quit the function. You can only change the value behind the pointer, not the pointer itself.
A solution for this would be to pass a pointer of pointer. Something like: (not tested)
void insertNodeAtEnd(Node** HEAD, int data) {
if (*HEAD == NULL) { *HEAD = new Node(data); }
else {
Node* it = *HEAD;
while (it->Next != NULL) { it = it -> Next; }
it -> Next = new Node(data);
}
}
int main() {
Node* HEAD = NULL;
// Node* HEAD = new Node(0);
insertNodeAtEnd(&HEAD, 5);
return 0;
}
As you don't change the pointer of pointer but only the value behind it (the actuual pointer to head) the change will be keep once you exit the function.
The answer has already been given by #Brotcrunsher. I am posting to help you implement a better solution, that separates the concept of a list and an element of a list, that incapsulates the methods used and that frees the resources it uses, when it goes out of scope:
#include <iostream>
using namespace std;
class Node {
public:
int Data;
Node* Next;
Node(int data = 0) {
Data = data;
Next = nullptr;
}
};
class List {
public:
Node* Head = nullptr;
void Insert(int data) {
if (Head == nullptr)
Head = new Node(data);
else {
Node* ptr;
for (ptr = Head; ptr->Next != nullptr; ptr = ptr->Next)
;
ptr->Next = new Node(data);
}
}
void Print() {
for (Node* ptr = Head; ptr != nullptr; ptr = ptr->Next)
cout << ptr->Data << endl;
}
~List() {
Node* ptr = Head;
while (ptr != nullptr) {
Node* tmp = ptr;
ptr = ptr->Next;
delete tmp;
}
}
};
int main() {
List list;
list.Insert(5);
list.Insert(2);
list.Insert(10);
list.Print();
return 0;
}
I am writing a simple app that gets a list and saves the objects as nodes in a singly linked list and we can add(), remove(), copy(), etc. each node depending on the given data set. each node has a char value which is our data and an int count which counts the occurrence of the related char.
e.g. for a list like
a, a, b, b, c, a
there would be three nodes (since there are three different characters) which are:
[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr
bool isAvailable() checks if the data is already in the list or not.
Q: When inserting a data there are two options:
The data has not been entered: so we have to create a newNodewith the given data, count=1and *next=NULL.
The data is already entered: so we have to count++ the node that has the same data.
I know if the given data is available or not, but how can I point to the node with same data?
Here's the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Snode
{
public:
char data;
int count;
Snode *next;
Snode(char d, int c)
{
data = d;
count = c;
next = NULL;
}
};
class set
{
private:
Snode *head;
public:
set()
{
head = NULL;
tail = NULL;
}
~set();
void insert(char value);
bool isAvailable(char value);
};
set::~set()
{
Snode *t = head;
while (t != NULL)
{
head = head->next;
delete t;
}
}
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
void set::insert(char value)
{
Snode *newNode = new Snode(char d, int c);
data = value;
if (head == NULL)
{
newNode->next = NULL;
head = newNode;
newNode->count++;
}
else
{
if(isAvailable)
{
//IDK what should i do here +_+
}
else
{
tail->next= newNode;
newNode->next = NULL;
tail = newNode;
}
}
}
I know if the given data is available or not, but how can I point to the node with same data?
You'll need to start at the head of the list and iterate along the list by following the next pointers until you find the node with the same data value. Once you've done that, you have your pointer to the node with the same data.
Some other notes for you:
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
Why is this function allocating a new Snode? There's no reason for it to do that, just initialize the floatingNode pointer to point to head instead.
This function always returns after looking at only the first node in the linked list -- which is not the behavior you want. Instead, it should return true only if (value == floatingNode); otherwise it should stay inside the while-loop so that it can go on to look at the subsequent nodes as well. Only after it drops out of the while-loop (because floatingNode finally becomes NULL) should it return false.
If you were to modify isAvailable() slightly so that instead of returning true or false, it returned either floatingPointer or NULL, you'd have your mechanism for finding a pointer to the node with the matching data.
e.g.:
// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
[...]
}
void set::insert(char value)
{
Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
if (theNode != NULL)
{
theNode->count++;
}
else
{
[create a new Snode and insert it]
}
}
You had a lot of problems in your code, lets see what are they:
First of all, Snode doesn't need to be a class, rather you can go with a simple strcut; since we need everything public.(not a mistake, but good practice)
You could simple initialize count = 1 and next = nullptr, so that no need of initializing them throw constructor. The only element that need to be initialized through constructor is Snod's data.
Since c++11 you can use keyword nullptr instead of NULL, which denotes the pointer literal.
Member function bool set::isAvailable(char value) will not work as you think. Here you have unnecessarily created a new Snode and cheacking whether it points to nullptr which doesn't allow you to even enter the loop. BTW what you have written in the loop also wrong. What do you mean by return (value == floatingNode); ? floatingNode is a Snode by type; not a char.
Hear is the correct implementation. Since we don't wanna overwrite the head, will create a Node* pointer and assign head to it. Then iterate through list until you find a match. If not found, we will reach the end of the isAvailable() and return false.
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
In void set::insert(char value), your logic is correct, but implementation is wrong. Following is the correct implementation.(Hope the comments will help you to understand.
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value); // create a node and assign there
}
}
Your destructor will not delete all what you created. It will be UB, since your are deleting newly created Snode t ( i.e, Snode *t = head;). The correct implementation is as bellow.(un-comment the debugging msg to understand.)
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
Last but not least, the naming (set) what you have here and what the code exactly doing are both different. This looks more like a simple linked list with no duplicates. This is however okay, in order to play around with pointers and list.
To make the code or iteration more efficient, you could do something like follows. In the isAvailable(), in case of value match/ if you found a node, you could simply increment its count as well. Then in insert(), you can think of, if node is not available part.
Hope this was helpful. See a DEMO
#include <iostream>
// since you wanna have all of Node in public, declare as struct
struct Node
{
char data;
int count = 1;
Node* next_node = nullptr;
Node(const char& a) // create a constrcor which will initilize data
: data(a) {} // at the time of Node creation
};
class set
{
private:
Node *head; // need only head, if it's a simple list
public:
set() :head(nullptr) {} // constructor set it to nullptr
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value);
}
}
void print() const // just to print
{
Node *temp = head;
while(temp != nullptr)
{
std::cout << temp->data << " " << temp->count << "\n";
temp = temp->next_node;
}
}
};
int main()
{
::set mySet;
mySet.insert('a');
mySet.insert('a');
mySet.insert('b');
mySet.insert('b');
mySet.insert('c');
mySet.insert('a');
mySet.print();
return 0;
}
I wonder why passing the second parameter Node** fhead causes a segfault? Node has an int value and a next pointer pointing to the next Node.
Here is my code:
void reverse(Node* head, Node** fhead) {
if (!head->next)
{
fhead = &head;
return;
}
reverse(head->next, fhead);
head->next->next = head;
head->next = 0;
}
int main()
{
Node a = {1, 0};
Node b = {2, &a};
Node c = {3, &b};
Node** fhead;
reverse(&c, fhead);
}
You have a little mistake in the recurssion termination. You should set *fhead to head and not assigning it with &head (Which will just change fhead locally in the funciton):
if (!head->next)
{
*fhead = head;
return;
}
There are two very small but serious problems.
First,
fhead = &head;
assigns a value to the parameter, so that change will not be visible outside of the function.
This works exactly like
void f(int x)
{
x = 0;
}
Just like you would do when you pass e.g. a pointer to an int,
void f(int* x)
{
*x = 0;
}
you need to assign to the object that the pointer points to:
*fhead = head;
Second, you need to pass a valid pointer to a variable:
Node* fhead = 0;
reverse(&c, &fhead);
(The initialisation isn't strictly necessary, but it's a good idea to initialise variables.)
With those two changes, your code works as expected.
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
One can assume ListNode definition
class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
this.next = null;
}
}
So I want to copy a whole linked list classes, I have trouble figuring it out how to do so,
class list{
public:
list(const list &t);
private:
struct Node{
int x;
Node *next;
}*p;
I started with something like this:
list::list(const list &t){
Node* q;
q=new Node;
while (p!=NULL){
q->x= p->x;}
}
but I'm not sure if I am on the right track or what. I also have trouble how should I test such a copy constructor? For example I have list l1, then i insert couple integers into a list and then how I can copy it?
In your example it never will work if you initialized p or will work forever if p != NULL. You must allocate new nodes while traversing through t list:
p = NULL;
Node* copy = l.p;
Node* insert = p;
Node* inserted_el = NULL;
while (copy){
insert = new Node();
insert->x = copy->x;
insert->next = NULL;
if (inserted_el) {
inserted_el->next = insert; //copy memory pointer to next element
} else {
p = insert; //copy memory pointer to list head
}
copy = copy->next;
inserted_el = insert;
}
This is basic idea. Also don't forget to implement assign operator and destructor.
Usage:
list t1;
//insert nodes
list t2(t1);
The biggest trouble in your code is that you do not duplicate each node of the list while you need to do so.
Here is the code of the ctor:
list::list(const list &t)
{
p = NULL; // Init the head of the list this is vital important.
// Loop over the elements of the passed list if any.
Node *pt = t.p;
Node *last_local_element = NULL;
while (pt != NULL)
{
// Allocate a new node and set the fields there.
Node *q = new Node;
q->x= pt->x;
q->next = NULL;
// Add new node to the local list.
if (last_local_element != NULL) {
last_local_element->next = q;
} else {
p = q;
}
last_local_element = q;
// Shift the loop variable along the passed list.
pt = pt->next;
}
}
There are 2 most often cases when the copy ctor is called:
list my_list1;
list my_list2(my_listl); // Explicit call.
list my_list3 = my_listl; // Assignment in the definition statement.
With your design of class, you need to be careful with memory management. This is the code:
list::list(const list& t) {
Node* n = t.p;
Node* m = p;
while (n) {
if (!m) {
m = new Node(); // Allocate memory.
if (!p) p = m;
}
m->x = n->x;
m = m->next;
n = n->next;
}
if (m) { // Original list is longer, delete the rest of the list.
Node * tmp = m;
m = m->next;
delete tmp;
}
}