Sorting a Singly Linked List With Pointers - c++

I am trying to sort a singly linked list using bubble sort by manipulating ONLY the pointers, no keys.
The following gets stuck in the for loop and loops infinitely. I don't understand why this is. Can anybody explain to me why the end of the list is not being found?
Node* sort_list(Node* head)
{
Node * temp;
Node * curr;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
temp = curr;
curr = curr->next;
curr->next = temp;
didSwap = true;
}
cout << curr->next->key << endl;
}
}
return head;
}
If I change the code so that the keys (data) are swapped, then the function works properly but for some reason I am not able make it work by manipulating only pointers.

Logical Error, you are creating an infinite loop with following code -
temp = curr;
curr = curr->next;
curr->next = temp;
I,e next_of_current is pointing to current, so curr->next will always be curr and never will be NULL;
Next you should use previous pointer to fix your list because your list can be traversed in a single direction. So, Think -
If A->B->C->NULL; and you make C and B swap then the new list will still point to A->B and next iteration will be wrong ... because you are not modifying your previous next.
So, another implementation may be -
Node* sort_list(Node* head) {
Node * curr;
Node * prev;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
prev = head;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
if (head == curr) {
head = curr->next;
curr->next = head->next;
head->next = curr;
prev = head;
} else {
prev->next = curr->next;
curr->next = prev->next->next;
prev->next->next = curr
}
didSwap = true;
} else if (head != curr) {
prev = prev->next;
}
//cout << curr->next->key << endl; // <- this may cause crash if curr->next now points to NULL; (i,e last element)
}
}
return head;
}
Hope this helps, regards.

You have following problem:
Let you have list with three members: ptr1->ptr2->ptr3. Before swap you have following pointer set: curr=ptr1; curr->next=ptr2; curr->next->next=ptr3. When you perform swap you receive curr=ptr2; curr->next=ptr1; curr->next->next=ptr2.
E.g. you lost ptr3. You need to change code of inner loop with following:
temp = curr;
temp->next = curr->next->next; // Save ptr3
curr = curr->next;
curr->next = temp;
didSwap = true;

The field you want to swap is the value. However, if you swap the node, the next field will change, the question becomes a little more complex, you need keep the next field right. In a word, change value is a simple and good method.

node *sorted_list(node *head) {
node *index1,*index2;
for(index1=head;index1->next!=NULL;index1=index1->next) {
for(index2=index1->next;index2!=NULL;index2=index2->next) {
if(index1->data>index2->data) {
int temp=index1->data;
index1->data=index2->data;
index2->data=temp;
}
}
}
return head;
}

Related

How to delete "end" node from a circular linked list using only tail in c++?

I need to write three separate functions for node deletion in a circular singly linked list (deleteFront(), deleteMiddle() and deleteEnd()). I have to use only tail (last). For some reason, my deleteEnd() function deletes second to the last node. Can anyone please help?
struct node
{
int data;
struct node* next;
};
// some other functions
// 6 -> 5 -> 4 -> 3 -> deleteEnd() does 6 -> 5 -> 3 ->
void deleteEnd(struct node* last)
{
if (last != NULL)
{
if (last->next == last)
last = NULL;
else
{
node* temp = NULL;
node* temp1 = last;
while (temp1->next != last)
{
temp = temp1;
temp1 = temp1->next;
}
temp->next = temp1->next;
delete temp1;
}
}
}
There are several issues with your deleteEnd function:
There is no way that the caller can get the new tail reference, because the tail argument is passed by value. The tail parameter should be a pass-by-reference parameter.
The statement after the loop (in the else block) does not remove the correct node. After the loop, temp1->next will be equal to last, and it should be that node that is removed, yet your code removes temp1. You can fix this by changing the loop condition and initialise the temp and temp1 variables to point to one node further in the list.
The else block does not update tail, yet it is clear that it should, since the original tail node is deleted.
Less of an issue, but in C++ you should not use NULL, but nullptr.
Here is a correction:
void deleteEnd(struct node* &last) // corrected
{
if (last != nullptr)
{
if (last->next == last)
last = nullptr;
else
{
node* temp = last; // corrected
node* temp1 = last->next; // corrected
while (temp1 != last) // corrected
{
temp = temp1;
temp1 = temp1->next;
}
last = temp; // added
temp->next = temp1->next;
delete temp1;
}
}
}
Try This
Explanation : So we are receiving head of the Circular Linked List and taking a curr pointer and pointing it to the head of the CLL.
Then we are taking another pointer and keeping it one step before the curr pointer so that we can point that pointer's next(prev->next) to curr's next(curr->next) and free the curr node.
void deleteTail(Node* &head)
{
Node* curr = head;
Node* prev = NULL;
while(curr->next != head)
{
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
curr->next = NULL;
delete curr;

linked list insertion, pointer confusion

I've looked around the forums but cant seem to find an answer to this very general question. The class below is a basic singly linked list with pushBack written the standard way.
class linkedList {
private:
typedef struct node {
int data;
struct node *next;
node(int d):data(d), next(NULL){}
}*nodePtr;
nodePtr head, temp, curr;
public:
linkedList():head(NULL), temp(NULL), curr(NULL){}
void pushBack(int d) {
temp = new node(d);
curr = head;
if (curr != NULL) {
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = temp;
} else head = temp;
}
void printAll() {
curr = head;
cout << "list:" << endl;
while (curr) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
};
but why cant my pushBack function be written like this?
void pushBack(int d) {
temp = new node(d);
curr = head;
while (curr != NULL) {
curr = curr->next;
}
curr = temp;
}
It should iterate through the list until curr == NULL and then set curr = temp. If the list is empty then it doesnt enter the loop and head will be set to the new node by setting temp to curr (which its self is set to head).
The logic makes perfect sense to me so it must be something else I'm missing.
Thank you for the help!
your function would fail for the first insertion or pushback, i.e, when the head pointer is null to begin with. when you assign head to curr like this:
curr = head;
curr now points to head and not vice versa .When curr is then assigned temp( i.e. when the first node isnserted into this linked list) , you have only reassigned the pointer curr with the location held by temp. Now all you have is a pointer curr pointing to the same location as temp, both of which pointers are not connected to head pointer at all!
a modified version of your code that would work is:
void pushBack(int d)
{
temp = new node(d);
curr = head;
if(curr!=NULL)
{
while (curr != NULL)
{
curr = curr->next;
}
curr = temp;
}
else head=temp;
}

how to insert into circular list (stuck in loop)

I have this insert function that is suppose to insert into a linked list in ascending order. I think I have the function right. The problem is that I am stuck in a loop and I don't know why because everything compiles.
void list::insertElement(int element)
{
//ascending order
node *temp, *curr;
temp = new node;
temp->item = element;
numberofelements++;
if(head ==NULL)
{
head = temp;
head->next = head;
}
else {
curr = head;
do
{
if (((curr->item <= element)&& (curr->next->item >=element)) ||curr->next==head)
{
temp->next = curr->next;
curr->next = temp;
if (element < head -> item)
{
head = temp;
}
}
curr = curr->next;
}while(curr!= head);
}
}//end of function
tl;dr : add a retrun just after you have inserted
the problem is, when you insert, you don't stop the loop, as the loop stops only when current==head
when you insert, current isn't modified, so it's on the element before the one inserted, so then the curr = curr->next; put it on the inserted element, so next element is head and the element and the inserting condition is met again of course, so it's inserted again, and when it's inserted again, executing
temp->next = curr->next;
curr->next = temp;
make them looping, because temp->next = current->next = temp
PS : even if it is here obvious, when you use a struct or class you should really give us how it is defined exactly (functionnal code always make more people able to help you fast)

add element after specifiec element in linked list and delete first element

I tried hard to solve this problem but only managed to partially solve it.
My problem in this method is that I need to add an element after another element:
Example: add 5 1
5 is an element in the linked list but I want to add 1 after 5.
Example: let linked list contains these elements : 2 3 7
I call method to add 1 after 3, add 3 1, so the result assume to be 2 3 1 7, but with my method the result is 2 1 3 7, which is my problem.
Second problem is that I can't deal with the first element:
Example: add 2 1
It acts as if the first element does not exist:
void addNodeAtPos(link *head, int pos,int addelement)
{
link prev=NULL;
link curr =*head;
link newNode = (link)malloc(sizeof(node));
newNode->data = addelement;
while(curr->next != NULL )
{
prev = curr;
curr = curr->next;
if(curr->data == pos)
{
newNode->next = curr;
prev->next = newNode;
break;
}
}
}
My problem here is that I can't remove the first element:
void deletenode(link *head,int s){
bool found = false;
node *curr = *head, *prev=NULL;
while(curr != NULL){
// match found, delete
if(curr->data == s){
found = true;
// found at top
if(prev == NULL){
link temp = *head;
curr->next= prev;
delete(temp);
// found in list - not top
}else{
prev->next = curr->next;
delete(curr);
} }
// not found, advance pointers
if(!found){
prev = curr;
curr = curr->next; }
// found, exit loop
else curr = NULL; }
}
Here's the solution to the first problem
if(curr->data == pos)
{
// tempNode = curr->next;
// improvement as suggested by #Rerito
newNode->next = curr->next;
curr->next = newNode;
break;
}
It appears you are using non-circular doubly linked lists. Thus, both ends of the list are marked with NULL. Now, it seems to me that you use C++ in a very C-esque fashion ... (NULL would'nt be used in C++, there is the nullptr keyword).
I will deal with your issues assuming you are using C instead of C++.
// Note that I pass a link **ptr, NOT a link *ptr ...
void addNodeAtPos(link **head, int pos, int addelement) {
// I am assuming head will be a valid pointer, if not, please add the appropriate checks.
link *newNode = NULL, *cur = *head;
if (NULL == (newNode = malloc(sizeof(link)))
return;
newNode->data = addelement;
while (cur != NULL) {
if (cur->data == pos || NULL == cur->next) {
newNode->next = cur->next;
newNode->prev = cur; // remove this line if there is no prev pointer.
cur->next = newNode;
if (NULL != newNode->next) { // remove this if clause if there is no prev pointer
newNode->next->prev = newNode;
}
break;
}
cur = cur->next;
}
}
You did not specify what you should do if the "position" is not found, I assumed that you just add the element at the end of the list in that case.
Now, considering your issue removing the first element :
void deleteNode(link **head, int el)
{
// I assume you wont pass a `NULL` ptr as #head
link *cur = *head, *prev = NULL;
while (cur != NULL) {
if (cur->data == el) {
next = cur->next;
prev = cur->prev;
free(cur);
if (NULL != next)
next->prev = prev;
if (NULL != prev)
prev->next = next;
else
*head = next;
break;
}
cur = cur->next;
}
}
Why do you need to pass a link **head instead of a link *head ? Because when you are removing the head of the list, you must make sure it won't be accessed anymore and thus you need to update the head pointer you use elsewhere. This is what is made in the *head = next; statement in the above function.
If you are using singly linked list (only a pointer to the next element, not the previous), the solution becomes the following :
void deleteNode(link **head, int el)
{
// I assume you wont pass a `NULL` ptr as #head
link *cur = *head, *prev = NULL, *next = NULL;
while (cur != NULL) {
if (cur->data == el) {
if (NULL != prev)
prev->next = cur->next;
else
*head = cur->next;
free(cur);
break;
}
prev = cur;
cur = cur->next;
}
}

Removing a node from a doubly linked list

I have looked at other threads here on the topic, but have no been able to use them to solve my problem.
this is the main class definition of a node in the linked list:
class node {
public:
// default constructor
node() {name = ""; prev = NULL; next = NULL;};
// default overloaded
node(string s) {name = s; prev = NULL; next = NULL;};
// item in the list
string name;
// links to prev and next node in the list
node * next, * prev;
};
the above is the node class definition, which is used in another class that generates a linked list. the linkedlist code was given to us, which we had to modify, so I know it works. I have gone through and tested the addition of new nodes in the doubly linked list to be working, and I am now working on removing nodes from this same doubly linked list.
The function to remove a node: http://pastebin.com/HAbNRM5W
^ this is the code I need help with, there is too much to retype
I was told by my instructor that the code that is the problem is the line 56, which reads:
tmp->prev = prev;
I am trying to set the link to the previous node to be the correct one. the case I am trying to work from with the similar if/else loops is whether or not the current node is the last item in the list. if it is the last item (aka curr->next = NULL), then don't set a link using curr->next and stop the loop iteration.
any help / ideas / suggestons / feedback will be greatly appreciated!
void linkedList::remove(string s)
{
bool found = false;
node * curr = getTop(), * prev = NULL;
node * tmp = new node();
while(curr != NULL)
{
// match found, delete
if(curr->name == s)
{
found = true;
// found at top
if(prev == NULL)
{
node * temp = getTop();
setTop(curr->next);
getTop()->prev = NULL;
delete(temp);
} // end if
else
{
// determine if last item in the list
if (curr->next = NULL)
{
// prev node points to next node
prev->next = curr->next;
// delete the current node
delete(curr);
} // end if
// if not last item in list, proceed as normal
else
{
// prev node points to next node
prev->next = curr->next;
// set the next node to its own name
tmp = prev->next;
// set prev-link of next node to the previous node (aka node before deleted)
tmp->prev = prev;
// delete the current node
delete(curr);
} // end else
} // end else
} // end if
// not found, advance pointers
if(!found)
{
prev = curr;
curr = curr->next;
} // end if
// found, exit loop
else curr = NULL;
} // end while
if(found)
cout << "Deleted " << s << endl;
else
cout << s << " Not Found "<< endl;
} // end remove
NULL should be replaced with nullptr
if (curr->next = NULL) { ...
That is an assignment, you want:
if (curr->next == nullptr) { ...
On line 47 I think you say: if prev == nullptr and next is not nullptr , but you use
prev->next = curr->next;
Which doesn't work since prev is nullptr.
For your code, I suggest several things. Isolate the code to find the node with the name you are looking for. The remove method SHOULD only remove a doubly linked node, provided that it is given one.
I know that your remove method takes in a string parameter, but pass that to another function and have that function return the node you are looking for.
It should look something like this:
Node *cur = find("abcd");
Node *prev = cur->prev;
prev->next = cur->next;
Node *n = cur->next;
n->next = cur->prev;
cur->next = NULL; //or nullptr
cur->prev = NULL; //or nullptr
delete cur;
Should look like:
prev->next = curr->next;
prev->next->prev = prev;
delete (curr);
I got lost in all your different conditionals. All you need to do is this:
void linkedList::remove(const std::string& s)
{
node* current = getTop(); // get head node
while (current != nullptr) // find the item you are trying to remove
{
if (current->name == s)
{
break; // when you find it, break out of the loop
}
}
if (current != nullptr) // if found, this will be non-null
{
if (current->prev) // if this is not the head node
{
current->prev->next = current->next;
}
else
{
// update head node
}
if (current->next) // if this is not the tail node
{
current->next->prev = current->prev;
}
else
{
// update tail node
}
// at this point, current is completely disconnected from the list
delete current;
}
}