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.
Related
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;
}
I was tasked with creating functions to add and delete nodes in a linked list given input data as an int and the char for with function to call. I'm not sure what I'm doing wrong. The only error I was given was: Exited with return code -11 (SIGSEGV). And a compiler method: main.cpp: In function ‘void listInsertValue(ListNode*&, ListNode*&, int)’:
main.cpp:111:23: warning: ‘toGoAfter’ may be used uninitialized in this function [-Wmaybe-uninitialized]
111 | toGoAfter->next = head;
Any help is appreciated. Thanks!
#include <iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
};
void listRemoveAfter(ListNode*&, ListNode*&, ListNode*);
void listPrepend(ListNode*&, ListNode*&, ListNode*&);
void listDeleteValue(ListNode*&, ListNode*&, int);
void listInsertValue(ListNode*&, ListNode*&, int);
void listInsertAfter(ListNode*&, ListNode*&, ListNode*, ListNode*);
int main()
{
ListNode *head = nullptr, *tail = nullptr;
ListNode *temp;
char choice;
int val;
//Write a main like you did in the previous lab
char command;
int number;
cin >> command;
while(command != 'Q')
{
if(command == 'I')
{
cin >> number;
listInsertValue(head,tail,number);
}
else
{
cin >> number;
listDeleteValue(head,tail,number);
}
cin >> command;
}
ListNode* current;
current = head;
while (current != nullptr)
{
cout << current->data << " ";
current = current->next;
}
cout << endl;
return 0;
}
//From previous lab - already complete
void listPrepend(ListNode*& h, ListNode*& t, ListNode*& n)
{
if (h == nullptr)
{
h = n;
t = n;
}
else
{
n->next = h;
h = n;
}
}
//From book, write yourself using the book code in 17.6 as a starting point
void listInsertAfter(ListNode*&head, ListNode*&tail, ListNode* curNode, ListNode* newNode)
{
if (head->next == nullptr)
{
head= newNode;
tail = newNode;
}
else if (curNode->next == tail)
{
tail->next = newNode;
tail = newNode;
}
else
{
newNode->next = curNode;
curNode->next = newNode;
}
}
//This function is mostly written, but you will need to add some code near the TODOs to complete the algorithm from the slides
void listInsertValue(ListNode*& head, ListNode*& tail, int val)
{
ListNode* toGoAfter, *newNode;
//TODO - create a new ListNode (newNode) with a data value of val (3 lines of code)
newNode = new ListNode;
newNode->data = val;
newNode->next = nullptr;
//TODO - check whether the list is empty in the if condition
if (head == nullptr)
{
listInsertAfter(head, tail, nullptr, newNode);
}
//TODO - use the else if to check whether the the value passed in is smaller than the value in the head
else if (head->data > val) //need to add to beginning of the list
{
listPrepend(head, tail, newNode);
}
else //need to add somewhere else in the list
{
//TODO - set toGoAfter to point to the head
toGoAfter->next = head;
//loop to find the location to insert the value
while (toGoAfter->next != nullptr && toGoAfter->next->data < val)
{
//TODO - set toGoAfter to point to the node after toGoAfter, like is done in traversals
toGoAfter = toGoAfter->next;
}
//We have found the location, so we can insert
listInsertAfter(head, tail, toGoAfter, newNode);
}
}
//modify
void listDeleteValue(ListNode* &head, ListNode*& tail, int val)
{
ListNode *temp;
//TODO - check if list is not empty in if condition
if (head->next == nullptr)
{
// TODO - check if value of head matches val passed in
if (head->data == val)
listRemoveAfter(head, tail, nullptr);
}
else
{
//loop searches for value to delete in node following temp
//TODO - set temp to point to the head
temp->next = head;
while (temp->next != nullptr && temp->next->data != val)
{
//TODO - set temp to point to the node after temp, like is done in traversals
temp = temp->next;
}
//TODO - make sure a node exists after temp, meaning the value to delete was found
if (temp->next != nullptr)
listRemoveAfter(head, tail, temp);
}
}
//From book, write yourself using the book code in 17.7 as a starting point
//Also add to the book's code, the code to delete nodes from memory
void listRemoveAfter(ListNode* & head, ListNode*& tail, ListNode* curNode)
{
ListNode *sucNode, *toDelete;
if (curNode->next == nullptr && head->next != nullptr)
{
sucNode = head->next;
head->next = sucNode;
if (sucNode->next == nullptr)
{ // Removed last item
tail->next = nullptr;
toDelete = head;
}
}
else if (curNode->next != nullptr)
{
sucNode = curNode->next->next;
curNode->next = sucNode;
if (sucNode-> next == nullptr)
{ // Removed tail
tail->next = curNode;
toDelete = curNode->next;
}
}
delete toDelete; //needed after the if/else if to remove the deleted node from memory
}
For most part you are not handling the case when there ia no element in the list. While inserting handle 4 use cases
Head==nullptr => head =newNode;
head->data > val
Tail->data < val
else case : insert in middle
Generic mistake: accessing ptr-> next, when ptr is nullptr
In general you want to use a debugger and any access to a memory 0x0 (nullptr) will start resolving your issues. ie head is 0x0 and you are doing operationa like head->data ==val
I have written two functions to insert nodes in a Linked List. While one function (insertNth) updates the head pointer, the second one (sortedInsert) does not update the head pointer across function calls. The push function is taking a reference to the head pointer.
struct node
{
int data;
node *next;
};
void printList(node *head)
{
node *current = head;
while(current!=NULL)
{
cout<<current->data<<" ";
current = current->next;
}
}
void push(node* &head, int data)
{
node *newNode = new node();
newNode->data = data;
newNode->next = head;
head = newNode;
}
void insertNth(node *&head, int index, int val)
{
node *current = head;
int cnt = 0;
while(current!=NULL)
{
if(cnt == index)
{
if(cnt==0)
{
push(head, val);
}
else
{
push(current->next, val);
}
}
current=current->next;
cnt++;
}
}
void sortedInsert(node *head, int val)
{
node *current = head;
if(head != NULL && val < head->data)
{
node *newNode = new node();
push(head,val);
return;
}
while(current!=NULL)
{
if(current->data < val && current->next->data > val)
{
push(current->next, val);
return;
}
current = current->next;
}
}
int main()
{
node *head;
push(head, 3);
cout<<"\n";
printList(head);
cout<<"\nInsertNth: ";
insertNth(head,0, 2);
printList(head);
cout<<"\nsortedInsert: ";
sortedInsert(head, 1);
printList(head);
return 0;
}
I'm getting following as output:
3
InsertNth: 2 3
sortedInsert: 2 3
Why is the third line not printing 1 2 3?
//
Update
//
The correct SortedInsert is as follows:
void sortedInsert(node *&head, node *newNode)
{
node *current = head;
if(head == NULL || newNode->data < head->data)
{
newNode->next = head;
head = newNode;
return;
}
while(current!=NULL && current->next != NULL)
{
if(current->data < newNode->data && current->next->data > newNode->data)
{
newNode->next = current->next;
current->next = newNode;
return;
}
current = current->next;
}
if(current->next == NULL)
{
current->next = newNode;
newNode->next = NULL;
}
}
A sample was requested. Note that I did it as a template, but you could skip the template business and instead of a T* you can use struct node *. It's not general purpose, but might be easier to understand.
template <class T>
class MyLinkedList {
class Entry {
public:
Entry * previous;
Entry * next;
T * node;
}
Entry * head;
Entry * tail;
void push(T * nodeToPush) { pushBefore(head, nodeToPush); }
void insertNth(int whereToInsert, T * nodeToInsert) {
... find the nth Entry pointer
pushBefore(head, nodeToPush);
}
private:
void pushBefore(Entry *entry, T * nodeToPush) {
Entry *newEntry = new Entry();
newEntry->node = nodeToPush;
if (entry != NULL) {
newEntry->previous = entry->previous;
}
newEntry->next = entry;
entry->previous = newEntry;
if (head == entry) {
head = newEntry;
}
if (tail == NULL) {
tail = newEntry;
}
}
// Other methods as necessary, such as append, etc.
}
Other than passing in a pointer to the objects you're inserting into your linked list, at no point do you have to pass pointers around in a fashion where your methods are also performing side effects on those pointer. The class should know how to manage a class, and no weird passing of variables all over.
Performing side effects on your arguments should be done with GREAT caution. If you're passing an object to a method, then it's fair to manipulate the object. But I really don't like passing pointers and having methods modify the pointers themselves.
That IS going to lead to (at best) confusion.
Note: I did NOT test this code. It might not quite be perfect.
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);
}
I've been trying to delete a node if the data matches a specific value.
Here's my delete value method:
void del_value(int data)
{
Node *temp = head;
int i = 0;
while(temp!=NULL)
{
if(temp->data == data)
{
del_index(i);
i--; // Since the nodes count will be reduced after deleting, reducing the index by one.
}
i++;
temp = temp->next;
}
}
And here is my del_index method(Which is working correctly):
int getCount()
{
int i = -1;
Node *temp = head;
while(temp!=NULL)
{
temp = temp->next;
i++;
}
return i;
}
void del_index(int pos)
{
int count = getCount();
if(pos == 0)
{
del_start();
}
else if(pos == count)
{
del_last();
}
else if(pos<0 || pos>count)
{
cout<<"Out of range"<<endl;
return;
}
else
{
int i = 1;
Node *temp = head;
while(i<pos)
{
temp = temp->next;
i++;
}
Node *toDel = temp->next;
Node *forward = toDel->next;
temp->next = forward;
delete toDel;
}
}
And here is my main method:
int main()
{
Mylist l;
l.add_start(4);
l.add_start(4);
l.add_start(4);
l.del_value(4);
l.show();
}
But it stucks when it reaches del_value method inside loop. Any idea where am I missing?
Update: (Added del_first and del_last methods
void del_start()
{
if(head == NULL)
{
cout<<"List is empty"<<endl;
return;
}
else
{
Node *temp = head;
head = head->next;
delete temp;
}
}
void del_last()
{
if(head == NULL)
{
cout<<"List is empty"<<endl;
return;
}
else
{
Node *temp = head;
while(temp->next != NULL)
{
tail = temp;
temp = temp->next;
}
tail->next = NULL;
delete temp;
}
}
Your del_value method will not work because you delete the object being pointed to by 'temp' then you dereference it after (with "temp = temp->next").
For your example code, I would cache the 'next' value before your conditional, for example:
Node *next = temp->next;
if(temp->data == data)
{
del_index(i);
i--;
}
i++;
temp = next;
I am assuming you're doing this for practice purposes but I would add the following suggestions:
I wouldn't call del_index here but remove the node inline, within the del_value method. As you have the necessary pointers to be able to remove it. del_index has to traverse your list a second time.
I would also recommend using the containers within the stl instead of rolling your own to avoid encountering issues like this.