Alright so I am attempting to implement a LinkedList data structure but when I try to loop through my list (printNodes and insert functions) I run into an error that says: "Unhandled exception thrown: read access violation. tmpNode was 0xCDCDCDCD." I feel like it has something to do with my pointers not behaving in the manner I think they should but I am not sure. Some assistance would be very much appreciated.
#include<iostream>;
using namespace std;
struct Node {
int data;
Node* next;
Node(int el) {data = el; } //constructor
Node(int el, Node* ptr) { data = el; next = ptr; } //constructor
};
class LinkedList {
public:
Node* head = NULL, * tail = NULL;
void addToHead(int el) {
head = new Node(el, head);
}
void insert(int el) {
Node* newNode = new Node(el);
if (head == nullptr) {
head = newNode;
}
else {
Node* tmpNode = head;
while (tmpNode->next != nullptr) {
tmpNode = tmpNode->next;
}tmpNode->next = newNode;
}
}
void printNodes() {
Node* tmpNode = head;
cout << tmpNode->data;
while (tmpNode->next != nullptr) {
std::cout << tmpNode->data;
tmpNode = tmpNode->next;
}
}
};
int main() {
LinkedList myList = LinkedList();
myList.insert(10);
myList.addToHead(20);
myList.insert(10);
myList.printNodes();
}
Your iteration is correct, but there is a problem with your printNodes function. It dereference tmpNode without checking for null:
void printNodes() {
Node* tmpNode = head;
cout << tmpNode->data; // <-- here
while (tmpNode->next != nullptr) {
std::cout << tmpNode->data;
tmpNode = tmpNode->next;
}
}
I would change it to the following:
void printNodes() {
Node* tmpNode = head;
while (tmpNode != nullptr) {
std::cout << tmpNode->data << ", ";
tmpNode = tmpNode->next;
}
}
Apart from that, as said in comments, if you set next member to null in Node constructor it should work fine.
To search, it is the same thing but checking for the data:
Node* findNode(int el) {
Node* tmpNode = head;
Node* ret = nullptr;
while (tmpNode != nullptr) {
if (tmpNode->data == el) {
ret = tmpNode;
break;
}
tmpNode = tmpNode->next;
}
return ret;
}
And in main:
Node* n = myList.findNode(10);
if (n)
std::cout << "N 10: " << n->data << "\n";
n = myList.findNode(30);
if (n)
std::cout << "N 30: " << n->data << "\n";
else
std::cout << "There is no N 30\n";
There are memory leak problems also, as specified by #RikusHoney in the comments.
Related
I created a doubly-linked list in C++. Everything works great if I insert a node at the beginning of the list or if I just insert a node at the end of the list; but, when I insert a node at the beginning and then try to insert a node at the end, I get a null pointer error!
Here is the code and the problem is in the InserAtEnd function
#include <iostream>
using namespace std;
struct Node {
int data;
Node* prev;
Node* next;
};
struct MyList {
Node* head;
Node* tail;
};
bool IsEmpty(MyList list) {
if (list.head == nullptr) return true;
else return false;
}
void Insert(MyList& list, int data) {
Node* node = new Node();
node->data = data;
node->prev = nullptr;
node->next = list.head; //node->next points to NULL
if (list.head == nullptr) {
list.head = node;
node->prev = nullptr;
}
else {
//insert the new node at the beginning of the list
list.head->prev = node;
list.head = node;
node->prev = nullptr;
}
}
// Insert node at end of list
void InsertAtEnd(MyList& list, int data) {
Node* node = new Node();
node->data = data;
node->next = nullptr;
node->prev = nullptr;
if (list.head == nullptr) { // Empty list
list.head = node;
list.tail = node;
}
else {
list.tail->next = node;
node->prev = list.tail;
list.tail = node;
}
}
//Traverse the list from the head
void PrintAll(const MyList& list) {
Node* temp = list.head;
if (temp == nullptr) {
cout << "list is empty" << endl;
}
else {
while (temp != nullptr)
{
cout << temp->data << endl;
temp = temp->next;
}
cout << "*************************************" << endl;
}
}
Node* Search(const MyList& list, int key) {
Node* temp = list.head;
while (temp != nullptr && temp->data != key)
{
temp = temp->next;
}
return temp;
}
void Delete(MyList& list, int key) {
Node* temp = Search(list, key); //call search()
if (temp != nullptr)
{
if (temp->prev != nullptr)
{
temp->prev->next = temp->next;
}
else
{
list.head = temp->next;
}
if (temp->next != nullptr)
{
temp->next->prev = temp->prev;
}
}
}
int main() {
MyList list;
list.head = nullptr; //initialize the linked-list
list.tail = nullptr;
if (IsEmpty(list))
cout << "List is empty" << endl;
Insert(list, 10);
PrintAll(list);
/*
Insert(list, 20);
Insert(list, 30);
Insert(list, 40);
*/
// Insert at end
cout << "Now insert at end" << endl;
InsertAtEnd(list, 70);
InsertAtEnd(list, 45);
InsertAtEnd(list, 59);
InsertAtEnd(list, 12);
InsertAtEnd(list, 33);
PrintAll(list);
/*
int x = 24;
Node* result = Search(list, x);
if (result == nullptr) cout << "Cannot find " << x << endl;
else cout << "Found " << result->data << endl;
Delete(list, 200);
PrintAll(list);
Delete(list, 10);
PrintAll(list);
Delete(list, 40);
PrintAll(list);
Delete(list, 20);
PrintAll(list);
Delete(list, 30);
PrintAll(list);
*/
return 0;
}
the problem is in the InserAtEnd function
How do you know?
In fact the problem isn't in InserAtEnd but in Insert:
You never set list.tail.
Tip: use Node **tail = &head; for a more efficient MyList and add member initializers and a Constructor.
This is C++ with classes. Use member functions.
I am implementing doubly linked list in C++, and I have been trying to make my insert method work without success.
The class should contain two node pointers: one to the head of the list, and one to the tail of the list. If the list is empty, they should both point to nullptr.
The insert method should take a value at given index and add it to the list, increasing its size with one element. my code is:
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int value;
Node *next;
Node *prev; //previous node pointer
Node(int v) : value(v), next(nullptr), prev(nullptr) {}
};
class LinkedList
{
private:
Node *head;
Node *tail;
Node *prev;
Node *get_node(int index)
{
if (index < 0 or index >= size)
{
throw range_error("IndexError: Index out of range");
}
Node *current = head;
for (int i = 0; i < index; i++)
{
current = current->next;
}
return current;
}
public:
int size;
LinkedList()
{
head = nullptr;
tail = nullptr;
}
int length()
{
Node *current = head;
int count = 0;
while (current != nullptr)
{
count++;
current = current->next;
}
cout << "Length of list is " << count << endl;
return count;
}
void append(int value)
{
Node *new_node = new Node(value);
if (head == nullptr)
{
head = new_node;
head->prev = nullptr;
new_node->next = tail;
}
else if (tail == nullptr)
{
tail = new_node;
new_node->next = nullptr;
}
}
void print()
{
Node *current = head;
Node *prev;
cout << "[";
if (current->next == NULL)
{
cout << current->value;
cout << "]";
}
else
{
while (current->next != nullptr)
{
cout << current->value;
cout << ", ";
prev = current;
current = current->next;
}
cout << current->value << "]" << endl;
}
}
~LinkedList()
{
Node *current;
Node *next;
current = head;
while (current != nullptr)
{
next = current->next;
delete current;
current = next;
}
}
int &operator[](int index)
{
return get_node(index)->value;
}
void insert(int val, int index)
{
Node *current = new Node(val);
Node *prev = get_node(index - 1);
Node *next = current->next;
prev->next = current;
}
};
int main()
{
LinkedList a;
a.append(1); // Appending elements to list
a.append(2);
a.append(3);
a.append(4);
a.append(5);
a.print(); // [1, 2, 3, 4, 5]
a.insert(3, 1);
a.print();
};
This gives me the error
libc++abi.dylib: terminating with uncaught exception of type std::range_error: IndexError: Index out of range
Abort trap: 6
I tried to fix all of your methods, probably succeded, at least current test example is printing correct answer:
Try it online!
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int value;
Node *next;
Node *prev; //previous node pointer
Node(int v) : value(v), next(nullptr), prev(nullptr) {}
};
class LinkedList
{
private:
Node *head;
Node *tail;
Node *get_node(int index)
{
if (index < 0)
throw range_error("IndexError: Index out of range");
Node *current = head;
for (int i = 0; i < index; i++) {
if (!current)
break;
current = current->next;
}
if (!current)
throw range_error("IndexError: Index out of range");
return current;
}
public:
LinkedList()
{
head = nullptr;
tail = nullptr;
}
int length()
{
Node *current = head;
int count = 0;
while (current != nullptr)
{
count++;
current = current->next;
}
cout << "Length of list is " << count << endl;
return count;
}
void append(int value)
{
Node *new_node = new Node(value);
if (head == nullptr)
{
head = new_node;
tail = head;
}
else
{
tail->next = new_node;
new_node->prev = tail;
tail = new_node;
}
}
void print()
{
Node *current = head;
cout << "[";
if (current->next == NULL)
{
cout << current->value;
cout << "]";
}
else
{
while (current->next != nullptr)
{
cout << current->value;
cout << ", ";
current = current->next;
}
cout << current->value << "]" << endl;
}
}
~LinkedList()
{
Node *current;
Node *next;
current = head;
while (current != nullptr)
{
next = current->next;
delete current;
current = next;
}
}
int &operator[](int index)
{
return get_node(index)->value;
}
void insert(int val, int index)
{
Node *node = new Node(val);
if (index == 0) {
if (!head) {
head = node;
tail = head;
} else {
node->next = head;
head->prev = node;
head = node;
}
} else {
Node *prev = get_node(index - 1);
Node *next = prev->next;
prev->next = node;
node->prev = prev;
node->next = next;
if (next)
next->prev = node;
if (prev == tail)
tail = node;
}
}
};
int main()
{
LinkedList a;
a.append(1); // Appending elements to list
a.append(2);
a.append(3);
a.append(4);
a.append(5);
a.print(); // [1, 2, 3, 4, 5]
a.insert(3, 1);
a.print();
};
Output:
[1, 2, 3, 4, 5]
[1, 3, 2, 3, 4, 5]
Well the obvious problem in insert is that it calls get_node which tests the size member but nothing updates size anywhere.
However, fundamentally, your append function is wrong. It should be a class invariant that a linked list is either empty and has both its head and tail be nullptrs, or it should have a valid head and a valid tail.
Your append function does not enforce this invariant. It tries to work on two cases, one where the head is null and another where the tail is null. Ask yourself if those two cases are meaningful.
Rewrite append such that a list either is empty or has a valid head and tail.
I have to do XOR linked list. Now im at point that i want to proper way clear memory. I did something like this but it seems doesnt work.
Minimal code i could add to work
void deleteAll(Data* head)
{
if (head == NULL)
cout << "Empty list." << endl;
else
{
if (XOR(head, NULL) == NULL)
{
Data* tmp = NULL;
Data* next;
while (head)
{
next = XOR(head->npx, tmp);
tmp = head;
delete head;
//cout << head->liczba << endl; EDIT <<< this line is not problem
head = next;
}
}
}
}
This is the moment when i alocate data
Data* tmp = new Data;
tmp->liczba = num;
tmp->npx = XOR(*head, NULL);
if (*head != NULL)
{
(*head)->npx = XOR(XOR((*head)->npx,NULL),tmp);
}
*head = tmp;
tmp = NULL;
delete tmp;
In main function after deleting function i run printAll function, then i can see that data has not been cleared.
Edit:
#include <iostream>
using namespace std;
struct Data {
int liczba;
Data* npx;
};
struct Data* XOR(struct Data* prev, struct Data* next)
{
return (Data*)((uintptr_t)(prev) ^ (uintptr_t)(next));
}
void pushEnd(Data** head, int num)
{
Data* tmp = new Data;
tmp->liczba = num;
tmp->npx = XOR(*head, NULL);
if (*head != NULL)
{
(*head)->npx = XOR(XOR((*head)->npx,NULL),tmp);
}
*head = tmp;
tmp = NULL;
delete tmp;
}
void printBackward(Data* head)
{
if (head == NULL)
cout << "Pusta lista." << endl;
else
{
Data* next;
Data* prev = NULL;
while (head)
{
cout << head->liczba << endl;
next = XOR(head->npx, prev);
prev = head;
head = next;
}
}
}
void deleteAll(Data* head)
{
if (head == NULL)
cout << "Empty list." << endl;
else
{
if (XOR(head, NULL) == NULL)
{
Data* tmp = NULL;
Data* next;
while (head)
{
next = XOR(head->npx, tmp);
tmp = head;
delete head;
head = next;
}
}
}
}
int main()
{
Data* head = NULL;
pushEnd(&head, 5);
pushEnd(&head, 10);
pushEnd(&head, 7);
pushEnd(&head, 3);
printBackward(head);
cout << head->liczba;
cout <<endl<< "DEL" << endl;
deleteAll(head);
printBackward(head);
}
In deleteAll you have a line preventing all deletions:
if(XOR(head, NULL) == NULL) { // remove this line
Your deleteAll functions also takes a Data* and all changes you make to head will be local to the function only. A minimal change needed that should make it work is to take head as a Data*& - that is, a reference to a pointer, so that all changes to do to head in your function are actually made to the head you defined in main.
Example:
void deleteAll(Data*& head) {
if(head == nullptr)
cout << "Empty list." << endl;
else {
Data* tmp = nullptr;
Data* next;
while(head) {
next = XOR(head->npx, tmp);
tmp = head;
delete head;
head = next;
}
}
}
You still call it the same way: deleteAll(head);.
If you prefer calling it with deleteAll(&head); you could define the function like this:
void deleteAll(Data** head) {
if(*head == nullptr)
cout << "Empty list." << endl;
else {
Data* tmp = nullptr;
Data* next;
while(*head) {
next = XOR((*head)->npx, tmp);
tmp = *head;
delete *head;
*head = next;
}
}
}
I have compiled my code and it seemed to work correctly. But out of no-where I get the error (this->tail was nullptr). I have tried changing the creation of the new node. But nothing seems to work. I cannot tell where tail is being set to nullptr and messing up the code.
How would I go about fixing this problem? Is there any way to set tail to non-nullptr without ruining every other function? I am not too familiar with exception throwing, so if you could explain the situation it would help a lot.
#ifndef MYDLL_H
#define MYDLL_H
#include <iostream>
#include <new>
using namespace std;
class MyDLL
{
struct Node
{
int i;
Node* next;
Node* prev;
};
Node* head;
Node* tail;
public:
MyDLL();
~MyDLL();
void append(int);
void remove(int);
bool find(int) const;
void clear();
void print() const;
void reverse() const;
};
MyDLL::MyDLL()
{
head = nullptr;
tail = nullptr;
}
MyDLL::~MyDLL()
{
clear();
}
void MyDLL::append(int i)
{
Node *n = new Node{ i, nullptr, nullptr };
if (head = nullptr)
{
head = n;
tail = n;
}
else
{
n->prev = tail;
tail->next = n; **<--- This is where the exception thrown error is showing up**
tail = n;
}
}
void MyDLL::remove(int i)
{
Node* p = head;
Node* q = tail;
while (p != nullptr && p->i != i)
{
q = p;
p = p->next;
}
if (p = nullptr)
{
return;
}
if (q = nullptr)
{
head = p->next;
}
else
{
q->next = p->next;
}
if (p->next = 0)
{
tail = q;
}
else
{
p->next->prev = q;
}
delete(p);
}
bool MyDLL::find(int i) const
{
Node* p = tail;
while (p != nullptr)
{
if (p->i = i)
{
return (true);
}
p = p->prev;
}
return (false);
}
void MyDLL::clear()
{
while (tail != nullptr)
{
Node* p = tail;
tail = p->prev;
delete (p);
}
head = nullptr;
}
void MyDLL::print() const
{
Node* p = head;
while (p)
{
cout << p->i << "\t";
p = p->next;
}
cout << "\n";
}
void MyDLL::reverse() const
{
Node* p = tail;
while (p)
{
cout << p->i << "\t";
p = p->prev;
}
cout << "\n";
}
#endif
int main()
{
MyDLL list;
list.append(5);
list.append(6);
list.append(7);
list.append(8);
list.print();
list.reverse();
cout << system("pause");
}
This code is exactly why you want to use nullptr = tail instead of tail = nullptr. In particular, every time you "check" for tail to be a null pointer, you are assigning nullptr to tail, and then assign operator returns a value which gets then implicitly casted to a boolean value, giving you no errors. But the error is actually there. Replace the "=" operator with "==" when performing a comparison, unless you actually have a reason for assigning and checking the return value.
Please fix = with == in your code.
void MyDLL::append(int i)
{
Node *n = new Node{ i, nullptr, nullptr };
if (head == nullptr)
It is always recommended to do like the reverse comparison (nullptr == head)
I'm having problems with this code. I'm pretty sure it's in the swapping.
The line: curr->Data() = nextEl.Data() gives me the following error:
"expression must be a modifiable lvalue"
Any help is appreciated. Thank you in advance.
Here is the code for my bubble-sort algorithm:
class Node
{
private:
int data;
Node* next;
public:
Node() {};
void Set(int d) { data = d;};
void NextNum(Node* n) { next = n;};
int Data() {return data;};
Node* Next() {return next;};
};
class LinkedList
{
Node *head;
public:
LinkedList() {head = NULL;};
virtual ~LinkedList() {};
void Print();
void AddToTail(int data);
void SortNodes();
};
void LinkedList::SortNodes()
{
Node *curr = head;
Node *nextEl = curr ->Next();
Node *temp = NULL;
if(curr == NULL)
cout <<"There is nothing to sort..."<< endl;
else if(curr -> Next() == NULL)
cout << curr -> Data() << " - " << "NULL" << endl;
else
{
for(bool swap = true; swap;)
{
swap = false;
for(curr; curr != NULL; curr = curr ->Next())
{
if(curr ->Data() > nextEl ->Data())
{
temp = curr ->Data();
curr ->Data() = nextEl ->Data();
nextEl ->Data() = temp;
swap = true;
}
nextEl = nextEl ->Next();
}
}
}
curr = head;
do
{
cout << curr -> Data() << " - ";
curr = curr -> Next();
}
while ( curr != NULL);
cout <<"NULL"<< endl;
}
You are doing it wrong. You cannot change the value of temp variable returned by a function.
But you can make it work this way..
int& Data() {return data;};
though this is not good practise. Instead just use the setter you have..
curr->Set(nextEl->Data());
The statement
curr->Data() = nextEl.Data();
will never work, you are trying to assign something to the return value of a function. I don't know how you defined Node, but you probably meant something like
curr->Data = nextEl.Data();
i.e., assign something to a member of Node.
change
curr ->Data() = nextEl ->Data();
nextEl ->Data() = temp;
to
curr->Set(nextEl ->Data());
nextEl->Set(temp);