Deleting duplicate elements in a list in c++ [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have a task to delete any duplicate elements from a list. I am using a struct and pointers for my functions. Here is the struct and the function:
struct node
{
int key;
node *next;
}*start = NULL;
int SIZE = 0;
Where size increments when an item is added. There is the function for deleting duplicates:
void del_dup()
{
if (!start) {
return;
}
if (SIZE == 1) {
return;
}
node * pointer = start->next;
node * prev = start;
node * mPointer = nullptr;
node * mPrev = nullptr;
for (int i = 0; i < SIZE - 1; i++)
{
if (pointer->next)
{
mPointer = pointer->next;
mPrev = pointer;
}
for (int j = i + 1; j <= SIZE; j++)
{
if (pointer->key == mPointer->key)
{
mPrev->next = mPointer->next;
delete mPointer;
}
else
{
mPrev = mPointer;
mPointer = mPointer->next;
}
}
prev = pointer;
pointer = pointer->next;
}
}
The thing is I get a crash at the if statement to compare if the two elements match:
if (pointer->key == mPointer->key)
The error is access violation type and nullptr for mPointer.
The list is filled from the user every time he runs the program with the values he wants. Here is the push function:
void push_start(int n) {
elem *p = start;
start = new elem;
start->key = n;
start->next = p;
SIZE++;
}
Any help to fix this would be appreciated. Thanks in forward!

For starters it is a bad idea to declare the variable SIZE outside the structure definition. In this case all functions that deal with the list will suffer from accessing to the global variable. You can not have more than one list in the program.
You could "wrap" the structure node in one more structure as for example
struct node
{
int key;
node *next;
};
struct list
{
node *head;
size_t /*int*/ size;
};
In this case each list would have its one data member size.
The function del_dup looks very confusing and you are using confusing names as for example pointer and mPointer. You should not rely on the variable SIZE that shall be decremented when a node is deleted.
I can suggest the following function implementation.
#include <iostream>
#include <cstdlib>
#include <ctime>
struct node
{
int key;
node *next;
} *head = nullptr;
size_t size;
void push_front( node * &head, int key )
{
head = new node { key, head };
++size;
}
std::ostream & display_list( node * head, std::ostream &os = std::cout )
{
os << size << ": ";
for ( const node *current = head; current; current = current->next )
{
os << current->key << ' ';
}
return os;
}
void del_dup( node * head )
{
for ( node *first = head; first; first = first->next )
{
for ( node *current = first; current->next; )
{
if ( current->next->key == first->key )
{
node *tmp = current->next;
current->next = current->next->next;
delete tmp;
--size;
}
else
{
current = current->next;
}
}
}
}
int main()
{
const size_t N = 10;
std::srand( ( unsigned int )std::time( nullptr ) );
for ( size_t i = 0; i < N; i++ )
{
push_front( head, std::rand() % ( int )N );
}
display_list( head ) << std::endl;
del_dup( head );
display_list( head ) << std::endl;
return 0;
}
The program output might look like
10: 2 2 3 3 8 5 6 2 6 1
6: 2 3 8 5 6 1

At a guess, you're at some point comparing keys with an already deleted node. For example, you're assigning mPointer = pointer->next, then possibly deleting mpointer, then at the end of the inner loop assigning pointer = pointer->next. So wouldn't it be possible for pointer->next to have already been deleted there?
Edit
Acutally it's much more likely that your inner loop condition is the problem. Try just:
for (int j = i + 1; j < SIZE; j++)
instead.

Related

Freeing memory space when deleting a node in a circular LinkedList without declaring a new pointer

I've come across a problem in dynamic programming in which we are asked to delete nodes of a circular LinkedList, in the following manner.
Delete the first node then skip one and delete the next, then skip two and delete the next, then skip three and delete the next and it continues until we are left with only one node, and that one node is our answer.
For example, if we have 5 nodes, then the nodes will be deleted in the following order – 1 3
2 5 4, and the last node would be 4.
Similarly, if we have 4 nodes, then the nodes will be deleted in the following order – 1 3 4
2, and the last node would be 2.
This is a screenshot of the part of the code that requires improvement
using this code in c++, I've been successful in solving the problem but I want to free the memory using delete command as I delink a node. Can anyone please help me to solve this problem by improving this code (while using minimal memory)?
The node can be deleted by declaring another pointer, but that would only increase the memory usage, which I don't want at the moment.
The entire code is given below
#include<iostream>
using namespace std;
class linked {
public:
int x;
linked* next;
//methods
linked(int p); //constructor
static void insert(linked*& head, int p);//method to insert new node
static int print(linked* head);//method to print the result
static void del(linked*head, int size) {//method to delete all the undesired nodes
linked* temp = head;
while (temp->next != head) {//traversing until we find the node just behind the node we want to del
temp = temp->next;
}
for(int i=1;i < size;i++) {
for (int k = 1; k < i; k++) {//del nodes with increment
temp = temp->next;
}
temp->next = temp->next->next; //delinking the
}
}
};
int main() {
int no_of_nodes;
cout << "enter the number of nodes you want to have" << endl;
cin >> no_of_nodes;
linked* head = new linked(1);
for (int i = 1; i <= no_of_nodes; i++) {
linked::insert(head, i);//for inserting nodes, as desired by the user
}
linked::del(head, no_of_nodes);
cout<< linked::print(head);
}
linked::linked(int p) {
x = p;
next = NULL;
}
void linked::insert(linked*& head, int p) {
linked* temp = head;
linked* n = new linked(p);//for the new node
if (p == 1) {
head->next = head;
return;
}
while (temp->next != head) {
temp = temp->next;
}
temp->next = n;
n->next = head;
}
int linked::print(linked* head) {
linked* temp = head;
for (int i = 0; i < 25; i++) {//this can go longer(or shorter), i limited it to 25 only, just to ensure that it is a circular linked list
temp = temp->next;
if (temp == temp->next) {
return temp->x;
}
}
cout << endl;
}
P.S. The problem was taken from ICPC Asia Topi 2022, link: (https://giki.edu.pk/wp-content/uploads/2022/03/ICPC_Day_2.pdf)
It seems neither professional programmer are going to help you.:)
So we, beginners, should help each other.:)
You should declare a class of the circular singly-linked list with non-static member functions.
As for the task to remove all elements from the circular singly-linked list except one using the described algorithm then I can suggest the following approach.
At first within the function remove the cycling. This will make easy to remove elements from the circular singly-linked list.
After all elements except one will be removed then restore the cycling.
Here is a demonstration program.
#include <iostream>
#include <utility>
#include <stdexcept>
class CircularList
{
private:
struct Node
{
int data;
Node *next;
} *head = nullptr;
public:
CircularList() = default;
CircularList( const CircularList & ) = delete;
CircularList &operator =( const CircularList & ) = delete;
~CircularList()
{
clear();
}
void clear()
{
if (head)
{
Node *current = head;
do
{
delete std::exchange( current, current->next );
} while (current != head);
head = nullptr;
}
}
void insert( int data )
{
Node *new_node = new Node{ data };
if (not head)
{
new_node->next = new_node;
head = new_node;
}
else
{
Node *current = head;
while (current->next != head) current = current->next;
new_node->next = head;
current->next = new_node;
}
}
const int & top() const
{
if (not head)
{
throw std::out_of_range( "Error. The list is empty." );
}
return head->data;
}
void remove_except_one()
{
if (head)
{
Node *last = head;
while (last->next != head) last = last->next;
last->next = nullptr;
Node **current = &head;
for (size_t n = 0; head->next != nullptr; ++n)
{
for (size_t i = 0; i != n; i++)
{
current = &( *current )->next;
if (*current == NULL) current = &head;
}
Node *tmp = *current;
// The statement below is uncommented for the debug pyrpose.
std::cout << ( *current )->data << '\n';
*current = ( *current )->next;
if (*current == nullptr) current = &head;
delete tmp;
}
head->next = head;
}
}
friend std::ostream &operator <<( std::ostream &os, const CircularList &list )
{
if (list.head)
{
const Node *current = list.head;
do
{
os << current->data << " -> ";
current = current->next;
} while (current != list.head);
}
return os << "null";
}
};
int main()
{
CircularList list;
for (int i = 0; i < 5; i++)
{
list.insert( i + 1 );
}
std::cout << "The list: ";
std::cout << list << '\n';
list.remove_except_one();
std::cout << "The list: ";
std::cout << list << '\n';
list.clear();
std::cout << '\n';
for (int i = 0; i < 4; i++)
{
list.insert( i + 1 );
}
std::cout << "The list: ";
std::cout << list << '\n';
list.remove_except_one();
std::cout << "The list: ";
std::cout << list << '\n';
}
The program output is
The list: 1 -> 2 -> 3 -> 4 -> 5 -> null
1
3
2
5
The list: 4 -> null
The list: 1 -> 2 -> 3 -> 4 -> null
1
3
4
The list: 2 -> null
Within the function remove_except_one this statement
std::cout << ( *current )->data << '\n';
is present for the debug purpose only. You may remove or comment it if you want.
There are some problems with your code:
1) empty list should be nullptr
In main:
linked* head = new linked(1);
should be
linked* head = nullptr;
You start with an empty list. You do not know what data you will insert first and you assume the first value inserted will be 1. With this change you also have to change your insert:
if (p == 1) {
has to check
if (head == nullptr) {
2) replace head with tail
In a circular single linked list you always need the previous node to delete a node or to insert at the head. That means you have to traverse the whole list when given the head to find the previous. This is rather slow, so store the tail of the list instead. Then the head is tail->next and you can delete the head or insert at the head directly.
3) del breaks head
static void del(linked*head, int size) {
If this deletes the first node in the list then the head the caller passed in becomes a dangling pointer. There is no way to update the pointer the caller holds for the list. Just like with insert you need to pass in a reference:
static void del(linked*&head, int size) {
Now for your problem of how to delete the node without extra memory:
You can't. You always need extra memory to temporarily store the node to be deleted while you fix up the links in the list and then delete it. You already needed that extra memory to find the tail of the list and you called it temp.
static void del(linked*&tail) {
if (tail == nullptr) return; // no list, nothing to delete
for (std::size_t skip = 0; tail->next != tail; ++skip) { // keep going till only one node is left
for(std::size_t i = 0; i < skip; ++i) tail = tail->next; // skip nodes
// delete node
linked* temp = tail->next;
tail->next = tail->next->next;
delete temp;
}
}

insertion in linked list start mid and end

I'm practicing linked list today, trying my best to understand it, so I tried making one singly linked list where I can add at the beginning,middle,and end, it also initializes to add one if the list is empty then printing the result.
I already use functions for this insertion and display of inputs or outputs but still the outputs result to nothing, event the printing the list, i tried to change the position of
node* head = NULL;
and still nothing happens
void insert(node* head, int numb, int size, int pos)
{
node* temp = new node();
int counter;
temp->number = numb;
if (head == NULL) {
head = temp;
}
else {
int counter = 0;
node* current = head;
node* trail = NULL;
while (counter++) {
if (counter == pos) {
temp->next = current;
trail->next = temp;
break;
}
else {
trail = current;
current = current->next;
continue;
}
}
}
size++;
}
void printlist(node* head)
{
while (head != NULL) {
cout << " " << head->number;
head = head->next;
}
}
int main()
{
node* head = NULL;
int numb, size = 0, pos;
numb = 5;
pos = 0;
insert(head, numb, size, pos);
printlist(head);
numb = 6;
pos = 2;
insert(head, numb, size, pos);
printlist(head);
}
I expect the output for the first is 5 then the second is 5 6.
The pointer you pass in insert(node* head is just a copy of the pointer in main. Any modifications to this pointer (e.g. head = temp) will not be reflected in main.
You need to pass either a pointer to the pointer or a reference to the pointer, for example:
void insert(node*& head, int numb, int size, int pos)
The function is invalid and in general has undefined behavior. For example this statement in the function
size++;
does not make sense because the parameter size does not have a referenced type. That is the function deals with a copy of its argument. The object size passed as an argument to the function will stay unchanged. And as a result the variable size within main will be always equal to 0.
Or within the loop
node* trail = NULL;
while (counter++) {
if (counter == pos) {
temp->next = current;
trail->next = temp;
//...
for the position equal to 1 the node trail is equal to NULL so this statement
trail->next = temp;
has undefined behavior.
Also the head node in main is not changed by the function because it is passed to the function by value. That is again the function deals with a copy of the head node.
And it is a bad idea to define the variables size and pos as having a signed integer type. In this case you have to check within the function whether the value of the parameter pos is greater than or equal to 0.
The function can be defined as it is shown in the demonstrative program below.
#include <iostream>
struct node
{
int number;
node *next;
};
void insert( node * &head, int number, size_t &size, size_t pos )
{
node **current = &head;
while ( pos != 0 && *current != nullptr )
{
--pos;
current = &( *current )->next;
}
*current = new node { number, *current };
++size;
}
std::ostream & printlist( const node* head, std::ostream &os = std::cout )
{
for ( const node *current = head; current != nullptr; current = current->next )
{
os << current->number << ' ';
}
return os;
}
int main()
{
node *head = nullptr;
size_t size = 0;
size_t pos;
int numb;
numb = 5;
pos = 0;
insert( head, numb, size, pos );
printlist(head) << '\n';
numb = 6;
pos = 2;
insert( head, numb, size, pos );
printlist(head) << '\n';
numb = 4;
pos = 0;
insert( head, numb, size, pos );
printlist(head) << '\n';
numb = 10;
pos = 2;
insert( head, numb, size, pos );
printlist(head) << '\n';
std::cout << "There are " << size << " nodes in the list.\n";
return 0;
}
The program output is
5
5 6
4 5 6
4 5 10 6
There are 4 nodes in the list.
Pay attention to that you need to write also a function that will free all allocated memory for the list.

Double pointers

I'm struggling with the following code. I want to create a linked list and keep track of its head. However, when I assign a pointer to the first node created, I am able to access only the first node's data value, and not its next nodes.
ie) the code below produces
0
Why won't it print out all values in the linked list ( 0 - 4 ) ?
#include <iostream>
using namespace std;
struct node
{
int val;
node * next = nullptr;
node(int a)
{
val = a;
}
};
node * t = nullptr;
node * temp;
int main(int argc, const char * argv[])
{
for (int i = 0; i < 5; i++)
{
t = new node (i);
if (i ==0)
{
temp = t;
}
t = t->next;
}
while (temp!=nullptr)
{
cout << (temp)->val;
temp = (temp)->next;
}
return 0;
}
During the creation of the list you need to keep track of the node created previously and set the next pointer of that node to the node you just created.
You probably want this:
int main(int argc, const char * argv[])
{
node *head;
node *previous = NULL;
for (int i = 0; i < 5; i++)
{
node *t = new node(i);
if (i == 0)
{
head = t;
}
if (previous != nullptr) // if not first node
{
previous->next = t; // set next of previous node to current node
}
previous = t;
}
node *temp = head;
while (temp != nullptr)
{
cout << temp->val << endl;
temp = temp->next;
}
return 0;
}
The overall design of this code is still poor but it sticks as closely as possible to the original code.
Output:
0
1
2
3
4

Why I get an EXC_BAD_ACCESS error in my linked list? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm just learning C++ right now, so I wanted to create a simple linked list program to learn how to write C++. (I come from Java and Python). Sometimes (not every time) I get an EXC_BAD_ACCESS error.
Here is my code:
#include <iostream>
#include <string>
using namespace std;
class LinkedList
{
struct Node
{
int value;
Node *next;
};
private:
Node *head;
public:
LinkedList()
{
head = NULL;
}
void addNode(int value, int index)
{
Node *node = new Node;
node->value = value;
Node *n = head;
if (index == 0)
{
node->next = n;
head = node;
return;
}
int size = getSize();
for (int i = 0; i < size - 1; i++)
{
if (i == index - 1)
{
node->next = n->next;
n->next = node;
}
n = n->next;
}
}
void addNode(int value)
{
Node *node = new Node;
node->value = value;
if (!head)
{
node->next = NULL;
head = node;
return;
}
Node *n = head;
int size = getSize();
for (int i = 0; i < size - 1; i++)
{
n = n->next;
}
n->next = node;
}
int getSize()
{
Node *_node = new Node;
_node->value = head->value;
_node->next = head->next;
int size = 1;
while (_node != NULL)
{
_node = _node->next;
size++;
}
return size - 1;
}
string printList()
{
Node *n = head;
string output = to_string(n->value);
int size = getSize();
for (int i = 0; i < size - 1; i++)
{
n = n->next;
output.append(" -> " + to_string(n->value));
}
return output;
}
};
I get this error in the method "getSize()" on the line "_node = _node->next;" I have no idea what's wrong.
Inside addNode you are not initializing the next pointer of Node to NULL when there is a head node.
You must initialize it to NULL.

Linked list implementation in classes c++, showing Segmentation fault [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I know the segmentation fault is occurring in this while loop: (while(temp != NULL){temp = temp->next;}), but I have no idea why.
#include<iostream>
using namespace std;
class zDepthList {
typedef struct node {
int data;
node* next;
node* prev;
} Node;
public:
zDepthList() {
head = NULL;
}
zDepthList(int array[], int length) {
Node *temp, *ptr;
int i = 0;
while(i != length - 1) {
temp = head;
ptr = new Node;
ptr->data = array[i];
i++;
ptr->next = NULL;
if(head == NULL) {
head = ptr;
ptr->prev = NULL;
}
else {
while(temp != NULL) {
temp = temp->next;
}
}
temp->next = ptr;
ptr->prev = temp;
}
}
void out(const char order) {
cout << head->data << endl;
return;
}
private:
Node *head;
};
For starters you have to initialize the head to NULL.
And after this while loop
else {
while(temp != NULL) {
temp = temp->next;
}
}
temp->next = ptr;
ptr->prev = temp;
the pointer temp is equal to NULL because it is the condition to interrupt the loop. Thus this statement
temp->next = ptr;
results in undefined behavior.
If you have a double-linked list it is natural to introduce also data member tail that it could be easy to append new nodes.
So you should include
class zDepthList {
//...
private:
Node *head, *tail;
};
In this case the constructors can look the following way
zDepthList() : head( nullptr ), tail( nullptr )
{
}
zDepthList( const int a[], size_t n ) : head( nullptr ), tail( nullptr )
{
for ( size_t i = 0; i < n; i++ )
{
Node *tmp = new Node { a[i], nullptr, tail };
tail == nullptr ? head = tmp : tail->next = tmp;
tail = tmp;
}
}
Here is a demonstrative program
#include <iostream>
class zDepthList {
typedef struct node {
int data;
node* next;
node* prev;
} Node;
public:
zDepthList() : head(nullptr), tail(nullptr)
{
}
zDepthList(const int a[], size_t n) : head(nullptr), tail(nullptr)
{
for (size_t i = 0; i < n; i++)
{
Node *tmp = new Node{ a[i], nullptr, tail };
tail == nullptr ? head = tmp : tail->next = tmp;
tail = tmp;
}
}
std::ostream & out( std::ostream &os = std::cout ) const
{
for (Node *current = head; current; current = current->next)
{
os << current->data << ' ';
}
return os;
}
private:
Node *head, *tail;
};
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
zDepthList l(a, sizeof(a) / sizeof(*a));
l.out() << std::endl;
}
The program output is
0 1 2 3 4 5 6 7 8 9
You never set head but you access it. This means it is uninitialized and this is an UB.
You have 2 ctors and you initialize head only then, when it is called without any parameter.