C++ linked lists using pointers - beginner question - c++

I have been learning C++ for the last couple of months, and after going through an online course I have started doing some challenges with using raw pointers. I have successfully created class that can initiate and iterate through linked list, with lots of struggle I managed to create method that deletes its element(s), but I am struggling to write a method that would remove all the duplicates.
I have a method such as
void linked_list::remove_dups(){
Node *p = first;
Node *g = first;
while(p!=NULL){
int x = 0;
g = new Node;
g = first;
Node *remove = first;
while (g!=NULL){
if(p->data == g->data){
x++;
}
if(x>1){
remove = new Node;
remove = p;
p = p->next;
remove->next = p->next;
delete remove;
x--;
}
g = g->next;
}
p = p->next;
}
}
where Node is standard
struct Node{
int data;
struct Node *next;
};
first is private member
Node *first;
Can anyone point out what is wrong in this function and explain please? I initiated list with pointers that is
int a[] = {3,5,5,7,65,5,65,65,4,4,15};
and it removed most of the duplicates, but not all. If I add more though, I have EXC_BAD_ACCESS error.
Really appreciate any help!

The main issue is:
p = p->next;
remove->next = p->next;
delete remove;
You try to set remove->next to point to the new next element. But remove is going to be deleted. So the element before remove will still point to something deleted. So, after the delete, you'll have a broken list that contains pointer to deleted elements. Next loop iteration, it will break.
Below is the code I edited as I went. Please note that
remove = new Node;
remove = p;
is not only useless, it leaks memory. You can directly do remove = p;
Just draft code as I went. Not fixed. Proper would be keeping a prev pointer or something.
void linked_list::remove_dups()
{
Node *p = first;
Node *g = first;
while(p!=NULL)
{
// int x = 0; remove this
// g = new Node; remove this
g = first;
Node *remove = first;
while (g != NULL)
{
if(p->data == g->data) // test directly, no x
{
// remove = new Node; remove this
remove = p;
p = p->next;
// remove->next = p->next; You are going to delete this, no point modifying it
delete remove;
}
g = g->next;
}
p = p->next;
}
}

Something I wrote for my custom doubly-linked list that will remove duplicates. Not necessarily the most efficient but it gets the job done.
void unique()
{
std::map<int, int> hash;
Node<T>* temp = this->head;
while(temp)
{
hash[temp->data]++;
if(hash[temp->data] > 1)
{
Node<T>* next = temp->next;
Node<T>* prev = temp->prev;
delete temp;
temp = nullptr;
if(!next)
{
temp = prev;
temp->next = nullptr;
hash[temp->data]--;
break;
}
next->prev = prev;
prev->next = next;
temp = next;
hash[temp->data]--;
}
else
{
temp = temp->next;
}
}
}

Related

Dynamic allocated lists - create a function that deletes all the elements which contain an even value

As I homework, I have to create a program which deletes all the nodes which contain an even value.
Here is how I've done it:
#include <iostream>
using namespace std;
struct node {
int info;
node* next;
};
void sterge(node*& p)
{
node* t;
t = new node;
if (p->info % 2 == 0)
{
p = p->next;
}
t = p;
while (t != NULL)
{
if (t->next != NULL)
{
if (t->next->info % 2 == 0)
{
node* aux;
aux = t->next;
t->next = t->next->next;
delete aux;
}
}
t = t->next;
}
}
int main()
{
node* head = new node;
head->info = 5;
node* p = new node;
node* t = new node;
t->info = 2;
head->next = t;
p = head;
node* x = new node;
x->info = 4;
node* w = new node;
w->info = 6;
t->next = x;
x->next = w;
w->next = nullptr;
sterge(head);
//Loop through the list and print each value
while (p != NULL) {
cout << p->info << endl;
p = p->next;
}
return 0;
}
But the output for the nodes created in main is 5 and 4.
I know the reason why but I don't know how to fix it.
Basically, I verify the next node if it has an even value, and then go to the next node. So it would look like this:
5 -> next is even so 2 is deleted
-> go to the next node which is 4
^now the problem is that this node is not being checked because I always check the next one. So it is considered by the program valid.
So how can I fix my program?
Put a continue after your delete.
That way, the next iteration will begin immediately, without the rest of the current iteration being executed, so the unwanted t = t->next will be skipped.

My program stops working from a while loop when using dynamic allocated lists

I've been studying about dynamic allocated lists (the stuff we are discussing right now in class is pretty outdated tbh) and I can't seem to access the next node in a list. (I've just began learning this topic)
The problem is that the while loop that I'm using for going through the list never stops. I'm definitely missing something and I don't understand what.
struct node {
int info;
node* next;
};
int main()
{
node *p, *prim=NULL;
p = prim;
node* t;
t = new node;
p->next = t;
while (p != NULL)
{
cout << "test";
p = p -> next;
}
return 0;
}
Here is the code.
Why does my program not output anything and also tells me "it exited with code -1073741819" instead of 0?
Thanks.
////edit: I forgot to tell you that I've tried this way too
struct node {
int info;
node* next;
};
int main()
{
node *p, *prim=NULL;
p = prim;
node* t;
t = new node;
prim->next = t;
while (p != NULL)
{
cout << "test";
p = p -> next;
}
return 0;
}
Let's analyze your code:
node *p, *prim=NULL; // prim is NULL, p not yet initnialized
p = prim; // p now equal to NULL as well
node* t;
t = new node; // t is allocated
p->next = t; // NULL->next = t
So you're crashing on a null pointer when you try to dereference p->next for assignment.
It looks like you're trying to setup a basic linked list and loop through it. Your loop looks good, but you forgot the part where you actually setup the list!
That could look like:
struct node {
int info;
node* next;
//Add a quick constructor to make creating new nodes easy
node(int i) : info(i), next(nullptr) { }
};
int main()
{
//Start out with 3 itmes
// This list will look like:
// head -> 5 -> 3 -> 1
node *head = new node(5);
head->next = new node(3);
head->next->next = new node(1);
//Loop through the list and print each value
for(node *p = head; p; p = p->next) {
std::cout << p->info << std::endl;
}
//Don't forget to delete the memory you allocated to prevent a leak!
for(node *p = head; p;) {
node *temp = p->next;
delete p;
p = temp;
}
return 0;
}
See it run: https://ideone.com/WngD3b

fixing logic in Removing duplicates from linked list

I'm trying to remove duplicates from linked list, but I have a bug in the code, I can't figure it out... So it seems there is a logical bug when for example found a duplicated node, the deletion is not correct?
ListNode *deleteDuplicates(ListNode *head) {
if (head == nullptr)
return head;
bool visited[255];
memset(visited, false, sizeof(visited));
ListNode * t = head;
ListNode *p = head;
while (t)
{
if (!visited[t->val])
{
visited[t->val] = true;
}
else{
ListNode *temp = t;
p->next = temp->next;
delete temp;
}
p = t;
t = t->next;
}
return head;
}
The problem is that when you find a duplicate you delete temp which actually equals to t. Then later, when you call t = t->next you're referring to a deleted pointer which is of course illegal.
A simple solution would be to change the while loop to look like:
while (t)
{
ListNode *temp = NULL; // added
if (!visited[t->val])
{
visited[t->val] = true;
}
else{
temp = t; // changed
p->next = temp->next;
// delete temp; // commented out (moved below)
}
p = t;
t = t->next;
if (temp) { // Added - delete temp folder in case it was set
delete temp;
}
}
Your code invokes undefined behavior. When you delete the object pointed by temp, it disqualifies the internal fields of the object, including the next field. Since t points to the same object as temp, t's fields also become invalid. Therefore, the assignment t = t->next will produce non-deterministic result.

Reversing a linked list (by recursion) not working

I was trying to write a code to reverse the linked list but getting wrong output.
Is there something I am missing.
Here is the function
void reverselinklist( struct node **headreverse)
{
struct node *p = *headreverse;
if(p->next == NULL)
{
*headreverse = p;
return;
}
reverselinklist(&(p->next));
p->next->next = p;
p->next = NULL;
}
After display function
Input 409765
Output 4
*headreverse = p is meaningless. You should set *headreverse = p->next each time to move forward, until the last node is reached.
Anyway, I changed your code to make it work:
void reverselinklist(struct node **headreverse)
{
struct node *p = *headreverse;
if(p->next == NULL){
return;
}
*headreverse = p->next;
reverselinklist(headreverse);
p->next->next = p;
p->next = NULL;
}
For single list use two two pointers, to update list as you can not go back.
Here is my code. Hope it will help you to understand concept.
void reverselinklist(struct node** head_ref)
{
struct node* first;
struct node* rest;
first = *head_ref;
rest = first->next;
if (rest == NULL)
return;
reverselinklist(&rest);
first->next->next = first;
first->next = NULL;
*head_ref = rest;
}
If it could me more precise please provide suggestions.
Your headreverse is not being assigned to the new head of the list. Be sure to use 2 arguments for your function, 1) head of the initial list 2) current node(same as your headreverse)
if(p->next == NULL)
{
*head = p; //instead of headreverse use head
return;
}

linked list C++ , question selflearning

#include <iostream>
using namespace std;
struct Node
{
int item; // storage for the node's item
Node* next; // pointer to the next node
};
Node* addNode(Node*& head, int data , int& count)
{
Node * q; // new node
q = new Node; // allocate memory for the new mode
q->item = data; // inserting data for the new node
q->next = head; // point to previous node ?? how would i do that? ( am i doing it correctly?)
count++; // keep track of number of node
head = q;
return q;
}
int main()
{
int a, count=0;
int data;
bool repeat;
Node *head= NULL;
//^^ assuming thats creating the first node ^^
do
{
cout << "please enter the data for the next node" <<endl;
cin >> data;
addNode(head, data, count);
cout << "do you wish to enter another node? (enter true or false)" << endl;
cin >>repeat;
}
while (repeat == true);
// assuming this is the print function
while(head != NULL)
{
cout << "output" << temp->item << endl;
cout << temp->next << endl;
}
system("pause");
return 0;
}
okey i tried adding a new element in the list how would i move the head around like a LIFO memory (stack) so the last element is on the very top..
any help would be appreciated ! The pointers and the nodes are messing with my brain lately ....
temp is an uninitialized pointer. So -
temp-> item = a; // temp is not initialized or pointing to a memory location
// that has Node object to use operator ->
First, temp needs to be allocated memory location using new.
temp = new Node;
temp -> item = a;
And now assign it head. Similarly allocate memory for the child nodes too in the while loop. And return all the resources acquired from child to head using delete before program termination.
You seem to have some misunderstandings here:
Your "head" is the start of the list. It's always the start.
You add append elements to a linked list by assigning them to the last node's next pointer.
Third, you're not allocating anything.
Node *head= new Node();
Node *temp = new Node();
cout<<"enter something into data"<<endl;
cin >> a ;
temp->item = a;
head->next = temp;
Now ... to add the next thing, you either need to keep track of the last node (tail), or traverse the list to find the last node.
Node *nextNode = new Node();
nextNode->item = 0.0;
Node *i;
for (i = head; i->next != null; i = i->next);
i->next = nextNode;
This is O(n) execution time. By keeping track of the tail you make it O(1):
Node *head= new Node();
Node *tail = head;
Node *temp = new Node();
cout<<"enter something into data"<<endl;
cin >> a ;
temp->item = a;
tail->next = temp;
tail = temp;
Node *nextNode = new Node();
nextNode->item = 0.0;
tail->next = nextNode;
tail = nextNode;
EDIT: As pointed out, if you want to prepend to the list, you would:
temp->next = head;
head = temp;
Since I'm not sure every answer completely answers it, here's a linked list implementation (written without testig:
// your (correct) structure
struct Node
{
float item; // storage for the node's item
Node* next; // pointer to the next node
};
Now we need two pointers somewhere to look after the list:
/* some pointers */
struct List
{
Node* head;
Node* tail;
};
Now we need to create some elements. As others have said, you can do that with new:
/* create some elements we want to link in */
Node* elem1 = new Node();
Node* elem2 = new Node();
Node* elem3 = new Node();
/* maybe even set their properties! */
elem1->item = 3.14;
elem2->item = 3.14;
elem3->item = 3.14;
Notice how I didn't try to add these elements to a list yet? That's because I've got a function in mind which looks like this:
void addtolist(List &list, Node* node)
{
/* if no head, initialise the list */
if ( list->head == NULL )
{
list->head = node;
list->tail = node;
}
else if ( list->head != NULL && list->tail != NULL )
{
/* access the tail element and set its
next to this ptr.
Move tail to this node */
list->tail->next = node;
list->tail = node;
}
else
{
/* probably raise an exception! */
}
}
You can call this by doing this:
List l;
addtolist(l, elem1); /* etc */
Deleting elements is somewhat more tricky, since you have to go to that element, remember its previous element, grab it's next element, join them up and delete the Node* you're on.
Now for traversing lists... your terminology HEAD|TAIL reminds me of Erlang and tail recursion, where the current element is referred to as the head and the remainder the tail. If I write:
Node* cur = l.head;
while ( cur != NULL )
{
// do something with cur.item ?
cur = cur->next;
}
You can see this happening. Replacing cur with head here would be harmless thanks to the List struct.
Finally, I've used a very C-like approach here, but there's scope for templates:
template<typename T>
struct node
{
T item; // storage for the node's item
Node<T>* next; // pointer to the next node
};
and encapsulating the List struct as a class:
template<typename T>
class List
{
protected:
Node<T>* head;
Node<T>* tail;
public:
void addtolist(Node<T>* node);
Node<T>* gethead();
Node<T>* gettail();
}
Which brings you a little bit closer to std::list.
Additionally note that you are doing an implicit cast from int to float on
temp-> item = a;
as a is an int, while temp->item is a double.
To solve your problem: You want to allocate a new structure before accessing temp, thus
temp = new Node();