I'm trying to implement my own version of a linked list for learning. I have the following code. The reverseList function works correctly and if I print it inside that function it is good.
However, when I leave the function and then call the print method I get the the first value and then nothing (null). I'm guessing when I get out of the function it brings me back to the original first ([99]) element which is now actually the last element. So my print method outputs the element sees null is the next and ends.
Or I was thinking the changes I was making in the function were somehow only in that function's scope even though I passed a pointer, but that doesn't make sense because if that's the case then I should have all the original data still.
struct ListNode
{
int value;
ListNode* next = NULL;
};
void insertRecList(ListNode* list, int value)
{
if(list->next == NULL)
{
ListNode* end = new ListNode;
end->value = value;
list->next = end;
}
else
insertRecList(list->next, value);
}
void printList(ListNode* list)
{
std::cout << list->value << std::endl;
while(list->next != NULL)
{
list = list->next;
std::cout << list->value << std::endl;
}
}
void reverseList(ListNode* list)
{
ListNode* next;
ListNode* prev = NULL;
ListNode* cur = list;
while(cur != NULL)
{
if(cur->next == NULL)
{
cur->next = prev;
break;
}
else
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
}
list = cur;
std::cout << cur->value << " list:" << list->value << std::endl;
}
void testLinkedList()
{
srand(time(NULL));
ListNode nodes;
nodes.value = 99;
int val;
for(int i = 0; i < 5; i++)
{
val = rand() % 30 + 1;
insertRecList(&nodes, i);
//insertList(&nodes, val);
}
printList(&nodes);
reverseList(&nodes);
printList(&nodes);
}
int main()
{
testLinkedList();
return 0;
}
Appreciative of any help you guys can give me,
Thanks!
Update:
By passing the ListNode *list to reverseList, you create a copy of your pointer which point to the same address with nodes. Inside the function, you assign list to the updated cur pointer but the copy will be destroyed at the end. list still points to the same address as before passing to reverseList but its next has changed.
I have modified your code a little bit:
#include <cstdlib>
#include <iostream>
struct ListNode
{
int value;
ListNode* next = nullptr;
};
void insertRecList(ListNode* list, int value)
{
if(list->next == nullptr)
{
ListNode* end = new ListNode;
end->value = value;
list->next = end;
}
else
insertRecList(list->next, value);
}
void printList(ListNode* list)
{
std::cout << list->value << std::endl;
while(list->next != nullptr)
{
list = list->next;
std::cout << list->value << std::endl;
}
}
void reverseList(ListNode** list)
{
ListNode* cur = *list;
ListNode* next = cur->next;
ListNode* prev = nullptr;
while(cur != nullptr)
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
*list = prev;
}
void cleanNodes(ListNode *list) {
// clean goes here
}
void testLinkedList()
{
srand(time(nullptr));
ListNode *nodes = new ListNode();
nodes->value = 99;
int val;
for(int i = 0; i < 5; i++)
{
val = rand() % 30 + 1;
insertRecList(nodes, i);
//insertList(&nodes, val);
}
printList(nodes);
reverseList(&nodes);
printList(nodes);
cleanNodes(nodes);
}
int main()
{
testLinkedList();
return 0;
}
Try to compile with: -std=gnu++11
You don't change nodes in reverseList you're just changing list you're just changing a pointer on your struct which is a temporary object so physically nodes steel the same and pointed on the same first element which now has next attribute pointing on Null so the result of printList is correct. You need to work with pointers e.g.
#include <iostream>
#include <cstdlib>
struct ListNode
{
int value;
ListNode* next = NULL;
~ListNode(){
if(this->next)
delete this->next;
}
};
void insertRecList(ListNode* list, int value)
{
if(list->next == NULL)
{
ListNode* end = new ListNode;
end->value = value;
list->next = end;
}
else
insertRecList(list->next, value);
}
void printList(ListNode* list)
{
std::cout << list->value << std::endl;
while(list->next != NULL)
{
list = list->next;
std::cout << list->value << std::endl;
}
}
ListNode * reverseList(ListNode* list)
{
ListNode* next;
ListNode* prev = NULL;
ListNode* cur = list;
while(cur != NULL)
{
if(cur->next == NULL)
{
cur->next = prev;
break;
}
else
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
}
std::cout << cur->value << " list:" << list->value << std::endl;
return cur;
}
void testLinkedList()
{
srand(time(NULL));
ListNode * nodes = new ListNode;
nodes->value = 99;
int val;
for(int i = 0; i < 5; i++)
{
val = rand() % 30 + 1;
insertRecList(nodes, i);
//insertList(&nodes, val);
}
printList(nodes);
nodes = reverseList(nodes);
printList(nodes);
delete nodes;
}
int main()
{
testLinkedList();
return 0;
}
Also, don't forget to delete object created dynamically
Reversing a linked list is not a fundamental operation. It does not belong among the basis operations of your class. It is easier (and safer) to implement it in terms of your other operations. Roughly:
Create an empty list.
While the first list is not empty, remove a node from the front of the first list and insert it into the front of the second list.
The second list is now the reverse of the original.
Related
I have a little problem which occurs after trying to execute function delete_all(). Any idea why Visual Studio is throwing me an error:
Invalid address specified to RtlValidateHeap, instruction __debugbreak() or something similar
Everything works perfect until I want to execute this function.
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = NULL;
node* next = NULL;
};
node* add(node* first, string name) {
if (first == NULL) {
return NULL;
}
node* nowy = new node;
if (first->next == NULL) {
nowy->prev = first;
first->next = nowy;
}
else {
while (first->next != NULL) {
first = first->next;
}
nowy->prev = first;
first->next = nowy;
}
nowy->name = name;
return nowy;
}
void writeout(node* first) {
if (first == NULL) cout << "first = NULL";
while (first->next != NULL) {
cout << first->name;
cout << "\n";
first = first->next;
}
if (first->next == NULL) {
cout << first->name;
cout << "\n";
}
}
void delete_all(node* first) {
node* temp;
while (first != NULL) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node n1;
add(&n1, "n2");
add(&n1, "n3");
writeout(&n1);
delete_all(&n1);
}
You declared an object in main() with automatic storage duration as the first node of the list:
node n1;
You may not destroy it using the delete operator.
Using your approach of the list implementation, you could define the function delete_all() the following way:
void delete_all(node* first)
{
if ( first != nullptr )
{
while ( first->next != nullptr )
{
node *temp = first->next;
first->next = temp->next;
delete temp;
}
}
}
But, it will be much better if initially in main(), you declared a pointer to a node. In this case, you will need to update the functions.
Your implementation of delete_all() is fine, but you are passing it a pointer to a node instance that was not created with new, so delete'ing that node is undefined behavior. ALL of your node instances should be created dynamically, including the 1st node.
As such, your add() function should be updated to not blindly return without creating a new node instance if first is initially NULL. You should instead update the caller's node* pointer to point at the new node that was created.
Also, writout() has undefined behavior if first is NULL, because you are unconditionally accessing first->next whether first is NULL or not.
With that said, try something more like this instead:
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = nullptr;
node* next = nullptr;
};
node* add(node* &first, string name) {
if (!first) {
first = new node{name};
return first;
}
else {
node *prev = first;
while (prev->next) {
prev = prev->next;
}
prev->next = new node{name, prev};
return prev->next;
}
}
/* alternatively:
node* add(node* &first, string name) {
node **nowy = &first, *prev = nullptr;
while (*nowy) {
prev = *nowy;
nowy = &(prev->next);
}
*nowy = new node{name, prev};
return *nowy;
}
*/
void writeout(node* first) {
if (!first) {
cout << "first = NULL";
}
else {
do {
cout << first->name;
first = first->next;
if (first) cout << '\n';
}
while (first);
}
}
void delete_all(node* first) {
node* temp;
while (first) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node* n1 = nullptr;
add(n1, "n2");
add(n1, "n3");
writeout(n1);
delete_all(n1);
}
Alternatively:
...
node* add(node* first, string name) {
if (!first) {
return new node{name};
}
else {
while (first->next) {
first = first->next;
}
first->next = new node{name, first};
return first->next;
}
}
/* alternatively
node* add(node* first, string name) {
// same as node** further above ...
}
*/
...
int main()
{
node* n1 = add(nullptr, "n2");
add(n1, "n3");
...
delete_all(n1);
}
We are iterating through the linked list with the help of head, that is, we are updating our head as we move forward towards i th position. Please have a look at the fuction insertIthnode. I am inserting my Node at i th position are returning head - and it's still able to print the linked list. I don't know how? head is no longer pointing towards the first node then how is it still able to return a full linked list?
here's the code:
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *next;
Node(int data) {
this->data = data;
next = NULL;
}
};
int length(Node *head) {
int x = 0;
Node *temp = head;
while (temp != NULL) {
x += 1;
temp = temp->next;
}
return x;
}
void printIthnode(Node *head, int i) {
int n = length(head);
if (i < 0 || i > n - 1) {
cout << -1 << endl;
return;
}
int count = 1;
while (count <= i) {
head = head->next;
count++;
}
if (head) {
cout << head->data << endl;
} else {
cout << "-1" << endl;
}
}
Node *takeinput() {
int data;
cin >> data;
Node *head = NULL;
Node *tail = NULL;
while (data != -1) {
Node *n = new Node(data);
if (head == NULL) {
head = n;
tail = n;
} else {
tail->next = n;
tail = n;
}
cin >> data;
}
return head;
}
void PrintLL(Node *head) {
Node *temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
}
Node *insertIthnode(Node *head, int i, int data) {
if (i < 0) {
return head;
} else if (i == 0) {
Node *n = new Node(data);
n->next = head;
head = n;
return head;
}
int count = 1;
while (count <= i - 1 && head != NULL) {
head = head->next;
count++;
if (count == i - 1) {
Node *n = new Node(data);
n->next = head->next;
head->next = n;
return head;
}
return head;
}
}
int main() {
/*Node n1(1);
Node *head=&n1;
Node n2(2);
Node n3(3);
Node n4(4);
Node n5(5);
Node n6(6);
n1.next=&n2;
n2.next=&n3;
n3.next=&n4;
n4.next=&n5;
n5.next=&n6;
*/
Node *head = takeinput();
insertIthnode(head, 3, 7);
PrintLL(head);
}
In the main() function you are creating a head when you are taking input from the user with the help of the "takeInput()" function.
After that, you are calling the function "insertIthnode(head,3,7)" which is returning the head (since the return type is Node) but you are not receiving it in any variable so the head returned from the "insetIthnode" is lost.
Your original head remains the same as per of "takeInput()" function.
If you try to insert ith Node at Index 0 it won't print according to the inserted node.
The problem is that you consider the Node as the linked list. While this is valid, the whole point of the linked list is that you don't lose track of the head. You could use two approaches:
Don't iterate over the head. Instead, use a temporary reference to the head.
Implement a Linked List wrapper. You can keep a constant reference to the head while performing operations over the node.
You pass head by value. Any changes you do to the variable receiving the value of head inside the functions are made to the local variable inside the function only and will not be visible from the call site.
Take your PrintLL function as an example:
void PrintLL(Node *head) { // head is here a local variable
Node *temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
}
This could be rewritten without the extra variable temp. The name head doesn't make it the same head you used to call the function with:
void PrintLL(Node* head) {
while (head != nullptr) {
cout << head->data << ' ';
head = head->next;
}
}
and it would not affect the head you passed in as a parameter.
Similarly:
void foo(int x) {
++x;
//
}
int main() {
int x = 10;
foo(x);
std::cout << x << '\n'; // prints 10
}
I'm trying to make single linked list's fucntions.
but it reports an error. like this..
i am trying to a lot of thing about that.
like using rvlaue reference, double pointer
but nothings work..
what is the problem?
and can i return p pointer in getNode(int k) fucntion?
#include<iostream>
using namespace std;
template<typename T>
class SingleLList {
private:
template<typename T>
struct Node {
T data;
Node<T>* next;
};
Node<T>* head;
int size; // for List size
public:
SingleLList() :head(nullptr) {};
~SingleLList() {
Node<T>* delNode;
while (head->next != nullptr) {
delNode = head;
head = head->next;
delete delNode;
}
};
// add Node at index th
void addNode(int index, T data) {
if (index < 0)return;
Node<T>* newNode = new Node<T>;
newNode->data = data;
newNode->next = nullptr;
if (index == 0) { // add at 0
// empty
if (head == nullptr) head = newNode;
// not empty
else {
newNode->next = head->next;
head = newNode;
}
size++;
}
else {
Node<T>* prev = head;
for (int i = 1; i < index && prev != nullptr; i++) {
prev = prev->next;
}
newNode->next = prev->next;
prev->next = newNode;
size++;
}
}
// traversa
void showList()const {
Node<T>* p = head;
cout << "Single Linked List : [ ";
while (p != nullptr) {
cout << p->data << " ";
p = p->next;
}
cout << " ]" << "total elements are : "
<< size << endl;
}
// return k th Node by reference.
Node<T>*& getNode(int k)const {
if (head == nullptr || k > size) {
Node<T>* temp = nullptr;
return temp;
}
// Node<T>* p; < -- is it okay?
Node<T>* p = new Node<T>;
p= head;
for (int i = 1; i < k && p->next != nullptr; i++) {
p = p->next;
}
cout << " address of p : " << &p << endl;
cout << "value of p : " << p << endl;
return p;
}
// delete n Node in list
void deleteNode(Node<T>*& n) {
cout << "address of n : " << &n << endl;
cout << n->data << endl;
if (n->next == nullptr) { // if last node
delete n->next;
n = nullptr; //
size--;
}
else {
Node<T>* del_node = n->next;
n->data = n->next->data;
n->next = n->next->next;
delete del_node;
size--;
}
}
};
int main() {
SingleLList<int> sll;
sll.addNode(0, 4);
sll.addNode(1, 5);
sll.addNode(2, 6);
sll.addNode(3, 8);
sll.addNode(4, 9);
sll.showList();
sll.deleteNode(sll.getNode(5));
sll.showList();
return 0;
}
and in main i make Linked List like this.
Node<T>*& getNode(int k)const {
if (head == nullptr || k > size) {
Node<T>* temp = nullptr;
return temp;
This same basic bug occurs several times in the shown code. All instances of this bug will need to be fixed.
temp is a local variable. Once this function returns, it goes out of scope and gets destroyed.
However: this function is declared as returning a reference to a pointer, and by returning temp this ends up returning a reference to an object that's already destroyed, when the function returns. All subsequent use of this reference automatically becomes undefined behavior, and the likely reason for your crash. For example:
sll.deleteNode(sll.getNode(5));
For example, getNode() returns a reference here. To add insult to injury this reference isn't even used immediately, but it gets passed to deleteNode(). By that time temp, or a reference to whatever was originally returned from getNode, is a distant memory and was already destroyed a long, long time ago, and attempting to reference it will not end well.
There are likely other issues, but this is fundamental, and fixing it will require fundamental changes to the shown logic, as such the first order of business will be to redesign the shown code, and it will likely involve other major changes to the rest of the code, as well.
I need to define a class of linked list,List, in a way such that object of class can be defined in two ways,
List obj1 = L1();//head=0
List obj2 = L2(given_arr[], size of array) // I would be given an array, whose elements are elements of list
so, I need to form a construter for both,
for obj1, Its easy.
List(){head=0};
But I am not abe to do so for second type of object.
I tried to form a program for this.
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head;
int arr[];
List() { head = 0; }
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
int i;
head->val = arr[0];
for (i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[4] = {9, 89, 0, 43};
List* M = new List();
List* L = new List(barr[4], 4);
L->display();
return 0;
}
This program doesn't work. Please suggest a way to do so.
Make these changes to your main().
int main() {
int barr[] = {9, 89, 0, 43}; // No need to specify size if you're initializing
// List* M = new List(); // unused
// Your array is barr, barr[4] makes no sense. You also don't allocate the List,
// the list allocates
List L = List(barr, sizeof(barr) / sizeof(barr[0]);
L.display(); // -> to .
return 0;
}
This now compiles, but immediately segfaults. Simply running the program in the debugger shows a simple error. The line head->val = arr[0]; attempts to dereference a null pointer. Which takes us to the next thing. Use nullptr, not NULL or 0.
Your array constructor was over-complicated, you just need this:
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
Your addnode() function already handled an empty list. Fixing that, your code should run. I made a couple other small changes, mostly trimming cruft out. Here's your complete code:
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head = nullptr;
List() = default;
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[] = {9, 89, 0, 43};
List L = List(barr, sizeof(barr) / sizeof(barr[0]));
L.display();
return 0;
}
How can I can remove max value from a Simply-Connected list?
Two of the solutions I tried produce wrong results. Please explain to me what am I doing wrong. With code, if not difficult.
Stack:
struct Stack
{
int info;
Stack *next;
} *top;
Wrong solution 1:
void delMaxValue(Stack **stck, int maxValue){
Stack *tmp = NULL;
do {
if ((*stck)->info != maxValue)
tmp = *stck;
cout << tmp->info << endl;
tmp = tmp->next;
*stck = (*stck)->next;
} while ((*stck)->next != NULL);
while (tmp != NULL)
{
*stck = tmp;
*stck = (*stck)->next;
tmp = tmp->next;
}
Wrong solution 2:
Stack* deleteMaxValue(Stack *begin) {
Stack *t = begin, *p = begin->next;
for (; p; p = p->next)
if (p->info > t->info) t = p;
p = begin;
if (p != t) {
while (p->next != t) p = p->next;
p->next = t->next;
}
else
begin = t->next;
delete t;
return begin;}
#include <cstdio>
#include <iostream>
struct Stack
{
int info;
Stack *next;
// added just to easy initialization
Stack(int _info, Stack *_next) : info(_info), next(_next) {}
} *top;
void delMaxValue(Stack *&head)
{
// first - find MaxValue in the list
// as you can see, i save pointer to the previous element in the list
Stack* max_prev = nullptr;
Stack* max = head;
for(Stack *i_prev = nullptr, *i = head; i; i_prev = i, i = i->next) {
if (max->info < i->info) {
max_prev = i_prev;
max = i;
}
}
// max has the maximum value and max_prev is the element before max in the list
// now we remove max
if (max_prev == nullptr) {
// max has no prev, so max is the head of the list. We assign the new head
head = max->next;
} else {
max_prev->next = max->next;
max->next = NULL;
}
}
void printStack(Stack *head) {
std::cout << "Priting " << head << std::endl;
for(Stack *i = head; i; i = i->next) {
std::cout << i << " " << i->info << std::endl;
}
}
int main()
{
Stack *head = new Stack(1, new Stack(15, new Stack(10, nullptr)));
printStack(head);
delMaxValue(head);
printStack(head);
return 0;
}
You may interest yourself in list helping macros from bsd, now available in glibc, newlib, openbsd etc., see here.
Your first solution takes maximum value as a parameter, while the second one doesn't. I am assuming we don't have the maximum value and will calculate it while processing the stack.
The basic approach should be to think of a logic first.
Step 1.) We need to pop all the elements to find the maximum element in the stack. Also, we need to store all the values we popped in another stack(say, auxiliary). Now, we are aware of the maximum value(say MAX).
Step 2.) Note we would have the stack in reverse now. Pop all elements from the auxiliary stack and if the value is not max, push them in the original stack.
Data Initially,
Original Stack: 1->2->3->4->100->5->7->NULL
Auxiliary Stack: NULL
Data after first Step,
Original Stack: NULL
Auxiliary Stack: 7->5->100->4->3->2->1->NULL
MAX: 100
Finally,
Original Stack: 1->2->3->4->5->7->NULL
Auxiliary Stack: NULL
Try to code for this. Your both solutions are doing things way differently than expected.
I hope It will be helpful.
#include <iostream>
struct LList
{
int info;
LList *next;
//constructer
LList(int info_) :info(info_) {
next = nullptr;
}
};
void removeMaxValue(LList *&root) {
int max = 0;
LList *temp = root;
//Searching for max value
while (temp!=nullptr)
{
if (temp->info > max)
max = temp->info;
temp = temp->next;
}
temp = root;
//Find max value and remove
while (temp->next->info != max)
temp = temp->next;
LList *maxNode = temp->next;
temp->next = temp->next->next;
delete maxNode;
}
void print(const LList *root)
{
while (root!=nullptr)
{
std::cout << root->info << " ";
root = root->next;
}
std::cout << std::endl;
}
int main() {
LList *root = new LList(15);
root->next= new LList(10);
root->next->next= new LList(45);
root->next->next->next = new LList(85);
root->next->next->next->next = new LList(5);
//before removing
print(root);
removeMaxValue(root);
//After removing
print(root);
std::cin.get();
}
Your two functions take two different approaches. I chose the one where the function doesn't know what actual max value is so it has to find it first.
First, the function just iterates through the elements and chooses the max value.
Then it searches for the first node that contains this value and removes the node.
void stackRemoveMaxValue(Stack*& top) {
if(top == nullptr) {
return;
}
// Find max value.
int maxValue = top->info;
Stack* node = top->next;
for(; node != nullptr; node = node->next) {
if(maxValue < node->info) {
maxValue = node->info;
}
}
// Remove first node that contains maxValue.
Stack* previous = nullptr;
Stack* current = top;
do {
if(current->info != maxValue) {
previous = current;
current = current->next;
} else {
if(previous != nullptr) {
previous->next = current->next;
} else {
top = current->next;
}
delete current;
return;
}
} while(current != nullptr);
}