So I have an assignment where I\'m giving a random list of number and I need to sort them using insertion sort. I must use a singly linked list. I looked around at other posts b
void linked_list::insertion_sort() {
node * p = head;
node * currentNode = head->next; // The node that is being compared at the moment.
node * previousNode = head; // The node previous to the node being compared at the moment.
//We can return from the sorting if the length of the linked list is less than 2.
if (p == nullptr || p->next == nullptr) {
return;
}
while (currentNode != nullptr) {
//If the current node is larger than or equal to the largest element of the sorted linked list on the left, we can move to the next element.
//Helpful for an already sorted array.
if(previousNode->value<=currentNode->value){
currentNode = currentNode->next;
previousNode = previousNode->next;
}
else{
//If the element is the smaller than the head element we need to take care of the head element.
if (head->value > currentNode->value) {
previousNode->next = currentNode->next;
currentNode->next = head;
head = currentNode;
}else {
p = head;
while (p->next != NULL && p->next->value < currentNode->value) {
p = p->next;
}
previousNode->next = currentNode->next;
currentNode->next = p->next;
p->next = currentNode;
}
}
currentNode = previousNode->next;
}
}
Let's think about how Insertion Sort works: It "splits" (in theory) the list into three groups: the sorted subset (which may be empty), the current item and the unsorted subset (which may be empty). Everything before the current item is sorted. Everything after the current item may or may not be sorted. The algorithm checks the current item, comparing it with the next item. Remember that the first item after the current item belongs to the unsorted subset.
Let's assume that you are sorting integers in increasing order (so given "3,1,5,2,4" you want to get "1,2,3,4,5"). You set your current item to the first item in the list. Now you begin sorting:
If the next item is greater than the current item, you don't need to sort that item. Just make it "current item" and continue.
If the next item is less than the current item then you have some work to do. First, save the next item somewhere - let's say in a pointer called temp - and then "remove" the next item from the list, by making current->next = current->next->next. Now, you need to find right place for the removed item. You can do this in two ways:
You continue this process until you reach the end of the list. Once you reach it, you know that you have completed your insertion sort and the list is in the correct sorted order.
I hope this helps.
Wow, I'm sure late to the party huh? Regardless, I would like to throw in my two cents in answering this question. Based on the way you provided your sample code, I am going to assume the following:
To begin, the answer I'm about to give you uses what I like to call the double pointer technique! Where you use a double pointer to help you reference two variables at the same time such that you avoid a complicated test case when reaching nullptr.
Okay, okay... I am playing fast in lose by calling pointer-to-pointer double pointer, and I may be tugging your leg by calling it a technique! If you have mastery over the concepts of pointers, then what I am about to show you should be quite trivial. I call pointer-to-pointer a technique, because rarely anybody talks about it or uses it in their example source code! The following link will take you to a blog created by Semmy Purewal that discusses this concept in more detail!
forward_list *insertion_sort( forward_list *head )
{
/// Ensure provided linked list is not empty and has more than one element...
if( head == nullptr || head -> next == nullptr )
{
std::cout << "Error: empty or single element linked list provided!\n";
return;
}
/// Initialize separate variable the houses a growing sorted output...
forward_list *sorted = nullptr;
/// Traverse provided singly linked list...
while( head != nullptr )
{
/// Remember current head before popping it off...
forward_list *current_head = head;
/// Double pointer for effective splicing of unsorted singly linked list...
forward_list **trail = &sorted;
/// Now we pop off the current head...
head = head -> next;
/// Iterate through our growing sorted output to figure out where we need to the head...
while( ( *trail ) != nullptr && ( *trail ) -> data > current_head -> data )
{
/// Head does not belong in this current position, move on!
trail = &( *trail ) -> next;
}
/// Insert the head and update our growing sorted output to point to the head...
current_head -> next = ( *trail );
( *trail ) = current_head;
}
/// Return our sorted output...
return sorted;
}
There we go, you now have an example implementation of insertion sort that operates wonderfully on a singly linked list! This implementation does not have a messy test case for nullptr, because we used a double pointer named trail that keeps track of itself and the pointer pointing to our growing sorted output. Thus, as the algorithm iterates through the sorted output, the variable trail gets dereferenced at nullptr, which holds the last node's next pointer!
All in all, I hope you find this answer to be both helpful and a little bit more readable! I know this question was asked seven years ago and was only active one year ago, but I hope someone finds this somewhat useful. Whelp, I'll be on my way then!
I have coded it using classes instead of struct. Changes could be done but the algorithm would be same. Code for creating class of node and single link list..
#include<iostream>
using namespace std;
class node{
public:
int data;
node* next;
};
class list{
node* head;
public:
list() {
head=NULL;
}
void add(int el) {
node* newNode=new node();
newNode->data=el;
newNode->next=NULL;
if(head==NULL) {
head=newNode;
} else {
node* temp=head;
while(temp->next!=NULL) {
temp=temp->next;
}
temp->next=newNode;
}
}
//Insertion sort code
void insertionSort() {
node* i=head->next;
while (i!=NULL)
{
node* key=i;
node* j=head;
while (j!=i)
{
if (key->data<j->data)
{
int temp=key->data;
key->data=j->data;
j->data=temp;
}
j=j->next;
}
i=i->next;
}
}
void display() {
node* temp=head;
while (temp!=NULL) {
cout<<temp->data<<" ";
temp=temp->next;
}
}
};
For creating main:
int main()
{
list l;
l.add(2);
l.add(6);
l.add(0);
l.add(3);
l.add(7);
l.add(4);
l.insertionSort();
l.display();
}
Do correct me if not working or the criteria for insertion sort in not implemented correctly.
Think about this - if the list is empty, temp
will initially be NULL
, so you get undefined behavior when you do temp->next = head;
.
Try some debugging, it will surely help. You'll probably either want to keep the previous node as well, so you can insert afterwards, or look 2 nodes forward.
struct node {
int data;
struct node *next;
};
void insertion(struct node **head) {
if((*head)== NULL || (*head)->next == NULL) {
return;
}
struct node *t1 = (*head)->next;
while(t1 != NULL) {
int sec_data = t1->data;
int found = 0;
struct node *t2 = *head;
while(t2 != t1) {
if(t2->data > t1->data && found == 0) {
sec_data = t2->data;
t2->data = t1->data;
found = 1;
t2 = t2->next;
} else {
if(found == 1) {
int temp = sec_data;
sec_data = t2->data;
t2->data = temp;
}
t2 = t2->next;
}
}
t2->data = sec_data;
t1 = t1->next;
}
}