Sorting the linked list during insert - c++

So I'm trying to insert nodes into linked list in descending order, but I struggle when I'm getting duplicate numbers and cant find a good solution for the problem. I either encounter missing numbers / program crash or program lists only 1 number infinite times.
Here is my code that I think works up to the "else" statement, it's the part that I cant figure out and im just leaving my last version, which doesnt work obviously
void Link::insert(int number) {
Node *news = new Node;
news->number = number;
if(first == NULL) {
first = news;
}
if(news->number > first->number) {
Node *temp = first;
first = news;
news->next = temp;
} else {
Node *temp = first;
while (temp->next || news->number < temp->number) {
temp=temp->next;
}
temp->next = news;
news->next = temp->next;
}
}
If the other functions are needed or my main.cpp please let me know.

Maybe
void Link::insert(int number){
Node *news = new Node;
news->number = number;
if(first == NULL){
first = news;
return;
}
for(Node *i=first, *pred=NULL;!i;i=i->next){
if(i->number<number){
if(i==first) {
news->next=first;
first=news;
} else {
pred->next=news;
news->next=i;
}
break;
}
pred=i;
}
}

When you are first inserting, it goes into your first if condition and then sets first=news, but after that its again checking news->number > first->number which will be false, so going into the else condition unnecessarily. So either add return; in first if block or put others in else block.
keep track of previous element
else{
Node *temp=first,*prev=null;
while (temp && (temp->next || news->number < temp->number)){
prev=temp;
temp=temp->next;
}
if(prev==null){
news->next=first;first=news;
}
else{
prev->next=news;news->next=temp;
}
}

You should swap your 2 last lines, else you have news->next = news, creating a cycle.
Anyway, I suggest to split the function in 2 (private) parts: One which found the Node* where to insert after (or nullptr for first position), and the method for the insertion (and it is so easier to debug).
Node* Link::upper_bound(int value) const
{
if (first == nullptr || first->number <= value) {
return nullptr;
}
Node* node = first;
Node* next = first->next;
while (next && value < next->number) {
node = next;
next = node->next;
}
return node; // we have: node->number < value && (next == nullptr || value <= next->number)
}
void Link::insert_after(Node* node, int value)
{
Node* new_node = new Node(value);
if (node == nullptr) {
new_node->next = first;
first = new_node;
} else {
new_node->next = node->next;
node->next = new_node;
}
}
and finally:
void Link::insert(int number) {
insert_after(upper_bound(number), number);
}

Related

Delete Nodes With The Value 0 In Singly Linked List In C++

I can't for the life of me figure this out I've spent days on this exercise but to no avail.
I'm trying to delete nodes with the value 0 from a singly liked list.
Let's say i have |1|3|0|4|0|5|0|0|. The outcome should be |1|3|4|5|
Here is all the code for reference
#include <iostream>
#include <fstream>
using namespace std;
struct node {
int data;
node* next;
};
node* head, *last;
int n;
void creating_list()
{
node* aux;
ifstream f("in.txt");
f >> n;
for(int i=0;i<n;i++)
{
if (head == NULL)
{
head = new node;
f >> head->data;
head->next = NULL;
last = head;
}
else
{
aux = new node;
f >> aux->data;
last->next = aux;
aux->next = NULL;
last = aux;
}
}
}
void displaying_list()
{
node* a;
a = head;
if (a == NULL)
cout << "List is empty! ";
else
{
cout << "Elements of list are: | ";
while (a)
{
cout << a->data<<" | ";
a = a->next;
}
}
}
void delete_first_node()
{
if (head == NULL)
cout << "List is empty";
else
{
cout << "Deleting first node\n";
node* aux;
aux = head;
head = head->next;
delete aux;
}
}
void delete_last_node()
{
if (head == NULL)
cout << "List is empty";
else
{
if (head == last)
{
delete head;
head = last = NULL;
}
else
{
node* current;
current = head;
while (current->next != last)
current = current->next;
delete current->next;
current->next = NULL;
last = current;
}
}
}
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
int main()
{
creating_list();
displaying_list(); cout <<endl;
delete_value_0();
return 0;
}
Here is the problem that gives me metal problems
I've tried to move one node short of the node that has the 0 value, store the value in another node, aux in this case and delete aux;
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
If I put break at the end it only shows me the first few numbers until the 0 and then stops short, doesn't move through the full list.
if I don't put break the the program is doesn't stop, it's in an infinite loop, it doesn't exit with code 0
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
Honestly I'm at a loss I've spent so much time trying to figure this out, and this should be a very simple exercise. I feel like the answear Is really simple but i don't know what to do anymore, Maybe this is not for me.
This is much simpler than it appears on the first glance. The trick to this task is instead of using a pointer to the current node, a pointer to the pointer to the current node gets used instead. The entire task becomes laughably trivial: only one loop, and one if statement that takes care of all possibilities: the list is empty; the node to delete is the first node in the list; ot the last node in the list; or anywhere in the middle of it.
void delete_value_0()
{
node **p= &head;
while (*p)
{
if ((*p)->data == 0)
{
node *nextptr=*p;
*p=(*p)->next;
delete nextptr;
}
else
{
p= &(*p)->next;
}
}
}
The naive solution is something like this:
void delete_value_0()
{
while (head && head->data == 0)
delete_first_node();
if (head == nullptr)
return;
node *cur = head->next;
node *pre = head;
while (cur)
{
if (cur->data == 0)
{
pre->next = cur->next;
delete cur;
cur = pre->next;
}
else
{
pre = cur;
cur = cur->next;
}
}
}
The key point is that you need to have a pointer to both the element you are inspecting and to the previous element in the list. This allows you to pull the current element out if it has data == 0.
The issue with this is that you have to treat the first element special (since it has no previous element).
My suggestion is to study this solution until you understand how it works, then move on to the (much better) solution by #Sam Varshavchik and study that - it does basically the same, but uses a pointer to pointer in a clever way to make the special cases here irrelevant.
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
OK why there the sketchy iteration is in else for if (last->data == 0)? Your input seems to have 0 as last item so in this case it would never be triggered. Also, if you want to have first/last items as special case, instead of
if (head->data == 0)
delete_first_node();
you would want something like
while (head && head->data == 0)
delete_first_node();
That being said, the real WTF is treating first/last item specially instead of using just single iteration. Also, you don't really check whether the pointers are non-null before trying to access the contents. With C (or C++ in the case you try it at some point) you need to take care with memory access when dealing with pointers.
Some random pieces of help:
You need to break from last item when it's 0 to exit loop simply because you don't assign a to the next item in this case.
If this is your schoolwork this might not be your fault, reading amount of items from the input file (assuming it was given part of the assignment) before actual items is huge WTF as you're reading into a linked list. There is no need to loop for any n items when you can be simply reading a line of input at the time until the file runs out.
Arguments and return values. You should learn those.
#include <iostream>
struct Node {
int data;
Node* next;
};
// Function to delete nodes with the value 0 in a singly linked list
void deleteNodes(Node** head) {
// Edge case: empty list
if (*head == nullptr) {
return;
}
// Delete all nodes with the value 0 at the beginning of the list
while (*head != nullptr && (*head)->data == 0) {
Node* temp = *head;
*head = (*head)->next;
delete temp;
}
// Edge case: list with only one node
if (*head == nullptr) {
return;
}
// Delete nodes with the value 0 in the rest of the list
Node* current = *head;
while (current->next != nullptr) {
if (current->next->data == 0) {
Node* temp = current->next;
current->next = temp->next;
delete temp;
} else {
current = current->next;
}
}
}
int main() {
// Create a singly linked list: 1 -> 0 -> 2 -> 0 -> 3 -> 0 -> 4
Node* head = new Node{1, new Node{0, new Node{2, new Node{0, new Node{3, new Node{0, new Node{4, nullptr}}}}}};
// Delete nodes with the value 0
deleteNodes(&head);
// Print the resulting list: 1 -> 2 -> 3 -> 4
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
return 0;
}
hope it help

C++ Need help on Remove Node function

I have stressed my head out the last few days to figure out how to get this remove() function to work. I'm still a student and data structure is no joke.
I really need help on how to get this function to remove a specific number on the list from user input. Doesn't matter what I try, it still could not work right.
For example, the list is: [1, 2, 3]
I want to delete number 2 on the list. I want the remove() function to traverse thur the list, if it found number 2, then delete number 2.
class SortedNumberList {
public:
Node* head;
Node* tail;
SortedNumberList() {
head = nullptr;
tail = nullptr;
}
void Insert(double number) {
Node* newNode = new Node(number);
if (head == nullptr) {
head = newNode;
tail = newNode;
}
else {
tail->SetNext(newNode);
tail = newNode;
}
}
// Removes the node with the specified number value from the list. Returns
// true if the node is found and removed, false otherwise.
bool Remove(double number) {
Node* temp = head;
if (temp == nullptr) {
return false;
}
if (head->GetData() == number) {
head = head->GetNext();
return true;
}
else{
while (temp != nullptr) {
Node* curNode = temp;
Node* preNode = nullptr;
preNode = curNode->GetPrevious();
temp = temp->GetNext();
if (curNode->GetData() == number) {
preNode = curNode->GetNext();
return true;
}
delete curNode;
}
}
delete temp;
}
};
class Node {
protected:
double data;
Node* next;
Node* previous;
public:
Node(double initialData) {
data = initialData;
next = nullptr;
previous = nullptr;
}
Node(double initialData, Node* nextNode, Node* previousNode) {
data = initialData;
next = nextNode;
previous = previousNode;
}
Edit: I'm able to solve my own issue, thank you everyone.
bool Remove(double number) {
// Your code here (remove placeholder line below)
Node* temp = head; //Make a temporary node point to head.
if (temp == nullptr || head == nullptr) { //if user don't provide input, return false.
return false;
}
if (head->GetData() == number) { //If number need to delete is at head.
head = head->GetNext();
return true;
}
else {
while (temp != nullptr) { //Travese temp node throught out a list.
Node* curNode = temp->GetNext(); //Make a current node point at temp next.
Node* preNode = temp;
Node* sucNode = curNode->GetNext();
if(curNode->GetData() == number) { //Delete a node if number is found on the list
if (curNode->GetNext() == nullptr) { //Delete at tail.
preNode->SetNext(nullptr);
tail = preNode;
delete curNode;
return true;
}
if (curNode->GetNext() != nullptr) {
preNode->SetNext(sucNode);
sucNode->SetPrevious(preNode);
delete curNode;
return true;
}
}
temp = temp->GetNext();
}
}
return false;
}
};
You should make Node a friend class of SortedNumberList or define former inside the later class which simplifies the code somewhat. It's personal preference but it leads to less unnecessary boilerplate code (getters and setters).
In a double linked list you do not need to keep track of the last as you do need on single linked lists because you have both pointers available.
The quest is just a matter of iterating to find the value, taking care to cut it early when we pass the mark since it is a sorted list.
Then delete the object and update the link pointers.
bool Remove(double number) {
// Loop through the entire list
Node* temp = head;
while ( temp != nullptr) {
// There is no point looking forward if the list is sorted
if (temp->data > number ) return false;
// Compare to find
if (temp->data == number) {
// Get the pointers so we can delete the object
Node* prev = temp->previous;
Node* next = temp->next;
// Delete object
delete temp;
// Update previous pointers
if ( prev==nullptr ) {
head = next;
} else {
prev->next = next;
}
// Update next pointers
if ( next==nullptr ) {
tail = prev;
} else {
next->previous = prev;
}
// Indicate success
return true;
}
}
// We iterated to the end and did not find it
return false;
}

c++ replace values in linked list by changing pointers

Having a problem with linked list. Need to create a method, which will replace data in list, by not creating a new element but by changing pointers. For now I have such method:
void replaceValues(Node* head, int indexOne, int indexTwo)
{
Node* temporaryOne = NULL;
Node* temporaryTwo = NULL;
Node* temp = NULL;
Node* current = head;
int count = 0;
while (current != NULL) {
if (count == indexOne)
{
temporaryOne = current;
}
else if (count == indexTwo)
{
temporaryTwo = current;
}
count++;
current = current->next;
}
current = head;
count = 0;
while (current != NULL) {
if (count == indexOne)
{
head = temporaryTwo;
}
else if (count == indexTwo)
{
head = temporaryOne;
}
count++;
current = current->next;
}
}
I am sure, that exists a more simpler way, how to do it, but I don't fully understand, how it works...
Thanks in advance for help.
I assume that with "replace" you actually mean "swap"/"exchange".
Some issues:
The argument head should be passed by reference, as one of the nodes to swap may actually be that head node, and then head should refer to the other node after the function has done its job.
The node before temporaryOne will need its next pointer to change, so you should stop your loops one step earlier in order to have access to that node and do that.
In some cases head may need to change, but this is certainly not always the case, so doing head = temporaryOne or head = temporaryTwo is certainly not right. In most cases you'll need to link to the swapped node from the preceding node (see previous point).
The next pointer of the node that is swapped will also need to change, as the node that follows it will be a different one than before.
As mentioned already in comments, it is advised to split the task into removals and insertions, as the fiddling with next pointers can get confusing when you try to cover all possible cases, notably making the distinction between the case where the two nodes are adjacent and when they are not.
Here are some functions that split the work into removal, insertion and finally exchanging nodes:
Node* removeNode(Node* &head, int index) {
// If index is out of range, no node is removed, and function returns nullptr
// Otherwise the extracted node is returned.
if (head == nullptr || index < 0) return nullptr;
Node* current = head;
if (index == 0) {
head = head->next;
current->next = nullptr;
return current;
}
while (--index > 0) {
current = current->next;
if (current == nullptr) return nullptr;
}
Node* temp = current->next;
if (temp != nullptr) {
current->next = temp->next;
temp->next = nullptr;
}
return temp;
}
void insertNode(Node* &head, Node* node, int index) {
// If index is too large, node is inserted at the end of the list
// If index is negative, node is inserted at the head of the list
if (index <= 0 || head == nullptr) {
node->next = head;
head = node;
return;
}
Node* current = head;
while (--index > 0 && current->next != nullptr) {
current = current->next;
}
node->next = current->next;
current->next = node;
}
bool exchangeNodes(Node* &head, int indexOne, int indexTwo)
{
// Returns true when successful, false when at least one index
// was out of range, or the two indexes were the same
if (head == NULL || head->next == NULL || indexOne == indexTwo || indexOne < 0) return false;
// To ensure the right order of operations, require the first index is the lesser:
if (indexOne > indexTwo) return exchangeNodes(head, indexTwo, indexOne);
Node* two = removeNode(head, indexTwo);
if (two == nullptr) return false; // out of range
Node* one = removeNode(head, indexOne);
insertNode(head, two, indexOne);
insertNode(head, one, indexTwo);
return true;
}

C++ linked lists deleting nodes

I am trying to go through a singly linked list and delete all nodes that contain a certain char. I have been trying to fix a pointer error (it said glibc detected: double free or corruption) by looking up online and trying those suggestions but now I seem to be stuck in a loop after rewriting my original code. I think the I am at least stuck in the 3rd while loop, I have tried using and if/else statement but the same thing happens. I also get a segmentation fault sometimes.
Code:
int MonsterList::removeMonsterType(char monster){
if(!isalpha(monster)) return 0;
if(first == 0) return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev = first; //first is the ptr in the list this function is called on
if(prev->next == 0){
while(prev->id == key || prev->id == key+32){
first = 0;
delete prev; prev = 0;
count++;
return count;
}
return count;
}
MonsterNode *temp = prev->next;
while(temp != NULL){
while(prev->id == key || prev->id == key+32){
first = temp;
delete prev;
prev = temp;
temp = temp->next;
}
while(temp->id == key || temp->id == key+32){
prev->next = temp->next;
delete temp;
temp = prev->next;
count++;
}
prev = temp;
temp = temp->next;
}
return count;
}
Thanks in advance for your help.
No wonder you're having such trouble. You only need a single for loop. Allow me to simplify your code [please pardon some gratuitous style edits]. Note this is untested and may not be perfect:
int
MonsterList::removeMonsterType(char monster)
{
if (!isalpha(monster))
return 0;
// first is the ptr in the list this function is called on
if (first == 0)
return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev;
MonsterNode *cur;
MonsterNode *next;
prev = NULL;
for (cur = first; cur != NULL; cur = next) {
// grab this _first_ so we have it before cur may be deleted (e.g. if
// cur gets deleted cur->next is immediately invalid, but this will
// remain)
next = cur->next;
if ((cur->id == key) || (cur->id == (key + 32))) {
// link previous item to next item
if (prev != NULL)
prev->next = next;
// replace first item in list
else
first = next;
// delete the node and advance the count
delete cur
count++;
continue;
}
// remember previous item
prev = cur;
}
return count;
}

Double Linked List Insertion Sorting Bug

I have implemented an insertion sort in a double link list (highest to lowest) from a file of 10,000 ints, and output to file in reverse order.
To my knowledge I have implemented such a program, however I noticed in the ouput file, a single number is out of place. Every other number is in correct order.
The number out of place is a repeated number, but the other repeats of this number are in correct order. Its just strange how this number is incorrectly placed. Also the unsorted number is only 6 places out of sync.
I have looked through my program for days now with no idea where the problem lies, so I turn to you for help.
Below is the code in question,
(side note: can my question be deleted by myself? rather my colleges dont thieve my code, if not how can it be deleted?)
void DLLIntStorage::insertBefore(int inValue, node *nodeB)
{
node *newNode;
newNode = new node();
newNode->prev = nodeB->prev;
newNode->next = nodeB;
newNode->value = inValue;
if(nodeB->prev==NULL)
{
this->front = newNode;
}
else
{
nodeB->prev->next = newNode;
}
nodeB->prev = newNode;
}
void DLLIntStorage::insertAfter(int inValue, node *nodeB)
{
node *newNode;
newNode = new node();
newNode->next = nodeB->next;
newNode->prev = nodeB;
newNode->value = inValue;
if(nodeB->next == NULL)
{
this->back = newNode;
}
else
{
nodeB->next->prev = newNode;
}
nodeB->next = newNode;
}
void DLLIntStorage::insertFront(int inValue)
{
node *newNode;
if(this->front == NULL)
{
newNode = new node();
this->front = newNode;
this->back = newNode;
newNode->prev = NULL;
newNode->next = NULL;
newNode->value = inValue;
}
else
{
insertBefore(inValue, this->front);
}
}
void DLLIntStorage::insertBack(int inValue)
{
if(this->back == NULL)
{
insertFront(inValue);
}
else
{
insertAfter(inValue, this->back);
}
}
ifstream& operator>> (ifstream &in, DLLIntStorage &obj)
{
int readInt, counter = 0;
while(!in.eof())
{
if(counter==dataLength) //stops at 10,000
{
break;
}
in >> readInt;
if(obj.front != NULL )
{
obj.insertion(readInt);
}
else
{
obj.insertBack(readInt);
}
counter++;
}
return in;
}
void DLLIntStorage::insertion(int inValue)
{
node* temp;
temp = this->front;
if(temp->value >= inValue)
{
insertFront(inValue);
return;
}
else
{
while(temp->next!=NULL && temp!=this->back)
{
if(temp->value >= inValue)
{
insertBefore(inValue, temp);
return;
}
temp = temp->next;
}
}
if(temp == this->back)
{
insertBack(inValue);
}
}
Thankyou for your time.
I don't like this part
else
{
while(temp->next!=NULL && temp!=this->back)
{
if(temp->value >= inValue)
{
insertBefore(inValue, temp);
return;
}
temp = temp->next;
}
}
if(temp == this->back)
{
insertBack(inValue);
}
Imagine what happens if inValue is greater than all values except this->back->value. It gets inserted at the end instead before this->back. By the way, You are inserting equal integers in the reversed order, they are read. For integers it doesn't matter that much, but it could if You inserted other objects. I would change the code of the insertion method to this:
node* temp;
temp = this->front;
while(temp!=NULL)
{
if(temp->value > inValue)
{
insertBefore(inValue, temp);
return;
}
temp = temp->next;
}
insertBack(inValue);
Just some remarks.
while(!in.eof())
This will not stop the inside of the loop from seeing an EOF error. You want
while ( in >> readInt )
Also,
if(this->front == NULL)
and
void DLLIntStorage::insertion(int inValue)
{
node* temp;
temp = this->front;
if(temp->value >= inValue)
do not mix. Either the front can be NULL, or it cannot. Likewise, you need to decide whether to use temp->next!=NULL or temp!=this->back, but not both, as a loop termination condition.
My guess would be that some inconsistency between multiple linking conventions is causing the errant value to get pushed into the middle of the list.