I am trying to sort a singly linked list using bubble sort. If there is a simple mistake then please pardon. Please tell me where I am going wrong. Program stops unexpectedly when I try to do this.
void sortBubble()
{
Node *i=start,*j=start;Node *temp;Node* prev=start;Node* agla;
while(i->next!=NULL)
{
cout<<"\nhello 1";
j=i;
agla=j->next;
while(agla!=NULL)
{
temp=NULL;temp->next=NULL;
cout<<"\nhello2";
if(*(j) > *(agla))
{
temp=agla->next;
agla->next=j;
prev->next=agla;
prev=agla;
agla=j->next;
j->next=temp;
}
else{
prev=j;
j=agla;
agla=j->next;}
}
prev=i;
i=i->next;
}
}
}
Your first obvious mistake that absolutely leads to program crash is:
while(agla!=NULL)
{
temp=NULL;temp->next=NULL;
You are setting a variable to NULL, then setting its fields. A null pointer points to nowhere, so you cannot edit its contents.
Remove temp->next=NULL;
Edit:
Your program logic is not correct. You ruin the list after a few iterations of the loop and the program sticks in an infinite loop with mixed up pointers.
In bubble sort, we iterate through the items several times. In each iteration, the largest item is bubbled up to the end of the list. After first iteration, we are sure that the largest element is at the end of the list. After second iteration, we are sure that the second largest element is before the last element of the list, and so on.
You repeat this process until all the items are on their places:
int getListSize(Node* start)
{
int count = 0;
while(start != NULL)
{
count++;
start = start->next;
}
return count;
}
void bubbleSort(Node *&start) // <-- Pass a reference to pointer, because we may need to modify the start pointer.
{
int size = getListSize(start);
int i = 0;
while(size--)
{
Node
*current = start,
*prev = NULL; // We are at the beginnig, so there is no previous node.
while(current->next != NULL) // We have at least one node (size > 0) so `current` itself is not NULL.
{
Node *after = current->next;
if((*current) > (*after))
{
//swap the items
current->next = after->next;
after->next = current;
if (prev == NULL) // we are at the beginning
start = after;
else
prev->next = after;
prev = after;
}
else
{
prev = current;
current = current->next;
}
}
}
}
We repeat the "bubbling up" process size times. This is not the most efficient way, since we even compare the items that are already sorted. A more efficient way is to sort until no new swapping occurs:
void bubbleSort(Node *&start) // <-- Pass a reference to pointer, because we may need to modify the start pointer.
{
int size = getListSize(start);
int i = 0;
Node *lastSwapped = NULL;
while(size--)
{
Node
*current = start,
*prev = NULL, // We are at the beginnig, so there is no previous node.
*currentSwapped = NULL;
while(current->next != lastSwapped) // We have at least one node (size > 0) so `current` itself is not NULL.
{
Node *after = current->next;
if((*current) > (*after))
{
//swap the items
current->next = after->next;
after->next = current;
if (prev == NULL) // we are at the beginning
start = after;
else
prev->next = after;
prev = after;
currentSwapped = current;
}
else
{
prev = current;
current = current->next;
}
}
if (currentSwapped == NULL)
break; // No swapping occured. The items are sorted.
else
lastSwapped = currentSwapped;
}
}
This is the complete working program
You are comparing the elements by simply doing *(j) > *(agla), I'm not sure how that builds since both j and agla are pointers to structures. Structures cannot be compared directly.
Related
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;
}
A really basic question about lists in C++ that I'm struggling with. I have a structure Metadata that have prev, next and value. I have a block metadataBlock which is already sorted by value and I want to add a new block metadataBlockResult in that list. What I did:
bool addedFlag = false;
Metadata* iterator = metadataBlock;
while (iterator != nullptr) {
if (metadataBlockResult->getValue() < iterator->getValue()) {
// What should be here?
addedFlag = true;
break;
}
iterator = iterator->getNext();
}
if (!addedFlag) {
metadataBlockResult->setPrev(iterator);
metadataBlockResult->setNext(nullptr);
iterator->setNext(metadataBlockResult);
}
I can't seem to understand how to add the item between two items and handle all cases (start and end). How should I add the item?
Don't be afraid to use pen and paper to visualize the logic to be implemented:
Here's some pseudocode with a possible implementation:
// 1. Find the position to insert newNode
Node *before = nullptr, *after = startOfList;
while (after != nullptr && after->value < newNode->value) {
before = after;
after = after->next;
}
// 2. Splice newNode in between before and after
newNode->prev = before;
newNode->next = after;
if (before != nullptr) {
before->next = newNode;
} else {
startOfList = newNode;
}
if (after != nullptr) {
after->prev = newNode;
}
Not sure if there is a simple and better way to implement this function?
void insert(Node* &head, int element, int position) {
Node* current = new Node;
current->data = element;
current->next = NULL;
if (position == 1) {
current->next = head;
head = current;
return;
}
else {
Node * current2 = head;
for (int i = 0; i < position - 2; i++) {
current2 = current2->next;
}
current2->next = current2->next;
current2->next = current;
}
}
A better way would be to make this function without null pointer access. You are missing all the necessary error checking.
But if you have to use this function you are already doing something wrong. The operation takes O(n) time. And if you build your list using only this function then you already have O(n^2) time. Using a balanced tree or heap would give you O(n * log n) time which makes a huge difference even for relatively small n. So think again why you need to insert at a given position and think about more suitable data structures.
A simpler implementation, and actually used in real code a lot, is to implement insert_before(before, data) or insert_after(after, data) with a doubly linked list. Both of which would get an item in the list and a new item to insert and place the new item before or after the old one on O(1) time.
Some boundary check is needed (please find the comments inline):
int listLen(Node *head)
{
int len = 0;
while (head != nullptr)
{
len++;
head = head->next;
}
return len;
}
void insert(Node* &head, int element, int position)
{
if (head == nullptr) // do nothing if head is nullptr
return;
if (position < 0) // insert to the begin if position is negative
position = 0;
else
{
int len = listLen(head);
if (len < position) // position is out of range, insert to the end
{
position = len;
}
}
if (position == 0)
{
Node *next = head;
head = new Node(element);
head->next = next;
}
else
{
int curPos = 0;
Node *curNode = head;
while (curPos < position - 1) // move to position
{
curNode = curNode->next;
curPos++;
}
Node *next = curNode->next; // do insertion
curNode->next = new Node(element);
curNode->next->next = next;
}
}
So I've recently updated my Bubblesort (sorts alphabetically) to work with a linked list.
Although now my previously working reverse method breaks the list. (Previously worked if I didn't do the single list bubble sort first)
Bubble sort and Swap.
void bubbleSort() {
City *temp = NULL;
City *current = head;
while (current != NULL) { //for the rest in list
if (current->getName().compare(current->next->getName()) > 0) { //compare distance
if (current == head) {
head = current->next;
}
swap(current, current->next);
}
current = current->next;
}
}
Swap
void swap(City* i, City* j) {
if (i->previous) i->previous->next = j;
if (j->previous) j->previous->next = i;
if (i->next) i->next->previous = j;
if (j->next) j->next->previous = i;
City* temp;
temp = i->previous;
i->previous = j->previous;
j->previous = temp;
temp = i->next;
i->next = j->next;
j->next = temp;
}
This is the now broken reverse list.
void reverseList() {
City *temp = NULL;
City *current = head;
while (current != NULL) {
temp = current->previous;
current->previous = current->next;
current->next = temp;
current = current->previous;
}
if (temp != NULL) {
head = temp->previous;
}
}
Question What have I missed out of my bubble sort that breaks the list?
One error is your bubble sort implementation. It should be making multiple passes through the data, since bubble sort has O(n*n) complexity, where n is the number of items to be sorted.
In other words, you need to execute the while loop in bubbleSort until you've detected that the data is sorted. That can be done either by using a boolean flag that is only set when a swap occurs and then testing that flag, or just make n passes through the data.
I'm getting mad with infinite loop, what do you think is suitable solution?
void sorting () {
node * temphead = head;
node * tempnode = NULL;
for (int i=0; i<count; i++) {
for (int j=0; j<count-i; j++) {
if (temphead->data > temphead->next->data) {
tempnode = temphead;
temphead = temphead->next;
temphead->next = tempnode;
}
temphead=temphead->next;
count++;
}
}
}
I tried to increment count and use many conditions with while- before and after the for loop with no result
An easier way to slide through a linked list is like this:
for (node *current = head; current != nullptr; current = current->next) {
// This will run through all of the nodes until we reach the end.
}
And to slide to the second to last item (ensuring that node->next exists) looks like this:
for (node *current = head; current->next != nullptr; current = current->next) {
// Go through all of the nodes that have a 'next' node.
}
If you want to count how many items are in a linked list, you do something like this:
int count = 0;
for (node *current = head; current != nullptr; current = current->next) {
count = count + 1;
}
So a selection type sort like you have above would look like this:
for (node *index = head; index->next != nullptr; index = index->next) {
for (node *selection = index->next; selection != nullptr; selection = selection->next) {
if (index->data > selection->data) {
swap(index->data, selection->data);
}
}
}
Although sorting linked lists is generally not the best way to go (unless you're performing a merge).
the problem is you are looping till count and you are incrementing count in every run of the loop//remove line count++ to avoid remove infinite loop