bubble sort linked list not sorting - c++

Why won't my bubble sort algorithm sort the linked list?
When given a list, and calling the method, it will output the same list. What's wrong with my current logic inside my for loop?
private:
IntNode *head, *tail;
node structure:
struct IntNode
{
int data;
IntNode * next;
};
bubble sort method:
void NodeSLList::SortList()
{
if (head == NULL || head->next == NULL)
return;
IntNode * current = head;
IntNode * nextElement = current->next;
IntNode * temp = NULL;
int changed = 1;
while (changed)
{
changed = 0;
for (current; (current != NULL) && (nextElement = NULL); )
{
if (current->data > nextElement->data)
{
temp = current->next;
current->next = nextElement->next;
nextElement->next = temp;
changed = 1;
}
current = current->next;
nextElement = nextElement->next;
}
}
}

The problem is caused by assigning in the for-loop, instead of comparing.
If you are implementing a linked list, may I suggest using a sentry, instead of a head
and NULL as end. This removes all 'corner-cases' during inserts and removes.
A sentry-node always exists, contains no data, points to the first item,
and the last item points to it.
May I also suggest using Mergesort, it works well for linked list, running in O(NlogN),
and having no space overhead. You can find an implementation here

Try running it through a debugger. If you look at the value of current on the second time round the changed loop, you will see that current is still null, so the second time round the changed loop it will not go through the current loop.

Related

Pointer in deleting a node in single linked list

In place of *head_ref = temp->next;, why can't I assign it as *head_ref = *head_ref->next?
Why should I use temp? Aren't they pointing to the same place?
class Node{
public:
int data;
Node* next;
};
void deleteNode(Node** head_ref, int key){
Node* temp = *head_ref;
Node* prev = NULL;
if(temp!=NULL && temp->data==key){
*head_ref = temp->next;
delete temp;
return;
}
else{
while(temp!=NULL && *head_ref->data!=key){
prev = temp;
temp = temp->next;
}
}
Your code does not compile, *head_ref->data should be (*head_ref)->data.
The reason why you should use temp is that you want to modify *head_ref only if the element you want to delete is the head element. If you delete any other element of the list, the head pointer must stay the same.
But your code is wrong anyway. You're doing things in the wrong order. You must first find the element you want to delete, and then handle the deletion.
Your code handles the deletion first and then finds the element to delete which is absurd.
You want this:
void deleteNode(Node** head_ref, int key) {
Node* current = *head_ref;
Node* previous = NULL;
// find element to delete
while (current && current->data != key)
{
previous = current;
current = current->next;
}
// if current is NULL here then the element has not been found
if (current != NULL)
{
// element found,
// current points to element found
// previous points to previous element or NULL if current is head
if (previous == NULL)
{
// deleting head element -> we need to update head_ref
*head_ref = current->next;
}
else
{
// deleting any other element -> update next pointer of previous element
previous->next = current->next;
}
delete current;
}
}
That being said, this is rather C code than C++ code. You should use standard containers rather than making your own, or at least use C++ idioms such as constructors.

c++ Linked List with priority queue

I trying to code out the Linked List with priority queue and i encountered some problem.
I have about 7 priority from 1 the most to 7 the least important.
here's my current insert method.
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* newnode= new node;
newnode->priority= newPriority;
newnode->fare = newFare;
newnode->cusID = custID;
newnode->next= NULL;
if (isempty())
{
front = back = newnode;
}
else
{
node* temp = front;
if(newnode->priority < temp->priority)
{
newnode->next = front;
front = newnode;
}
else
{
while(newnode->priority < temp->priority)
{
if(temp->next == NULL)
{
break;
temp = temp->next;
}
}
if(temp->next == NULL && newnode->priority < temp->priority)
{
back->next = newnode;
back = newnode;
}
else
{
newnode->next = temp->next;
temp->next = newnode;
}
}
}
}
Invoked as:
qList->addToQueueList(2, 488.88, A);
qList->addToQueueList(1, 388.88, B);
qList->addToQueueList(3, 488.88, C);
Expected result should be :
B, A, C
THe result shows :
B, C, A
Your making this considerably harder than it needs to be. Ultimately you need to walk the list, find the insertion point, remember how you arrived at that insertion point, and wire both your fore and aft pointers appropriately. Also a priority queue has no reason to keep a "back" pointer, so I'm not sure why you have one.
There are a number of ways to do this. First, to make the code cleaner to understand, providing a proper parameterized constructor for node is both trivial and helpful:
struct node
{
int priority;
double fare;
int cusID;
node *next;
node(int p, double f, int id, node *nxt = nullptr)
: priority(p), fare(f), cusID(id), next(nxt)
{
}
};
One you have that, you can go down the road you were apparently trying to navigate, using a pointer-value list walking approach. To do that you need to maintain a previous pointer:
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* temp = front, *prev = NULL;
while (temp && temp->priority < newPriority)
{
prev = temp; // remember how we got here
temp = temp->next; // advance to next node
}
// create new node, linking to temp
node *newnode = new node(newPriority, newFair, custID, temp);
// link to previous node or assign as new head, whichever is needed
if (prev != nullptr)
prev->next = newnode;
else
head = newnode;
// though there is no need for a back pointer in a priority queue
// you had one none-the-less, so....
if (!temp)
back = newnode;
}
it is worth noting that this algorithm will insert new arrivals with similar priority at the head of that priority section of the list. I.e. the newest arrivals for a given priority are always at the forefront of that priority's position in the queue. If you want the oldest arrivals of a given priority to be "ahead" of their brethren, you simply need to change this:
while (temp && temp->priority < newPriority)
to this:
while (temp && temp->priority <= newPriority) // note < is now <=
Best of luck.
The comparison in your while loop is wrong. When inserting C newnode->priority == 3 and temp(B)->priority == 1. Thus the while loop is never entered.
Also, the temp = temp->next inside the while loop should be outside (after) the if statement. Otherwise this will be an infinite loop.
Assuming you are correcting these: you will always insert the new element after temp. Be aware of this in your fix of your comparisons. You are likely to add comparisons with temp->next->priority as well.
I agree with Joachim in the comments: step through the code with a debugger. Then you can see the values of the variables and which comparisons produce which results.

Writing an Insert Algorithm for an Ordered Linked List C++

I'm writing an insert algorithm for an ordered linked list. I've got most of the algorithm completed, but the one while loop condition is throwing me off. I think the rest of it I have correct, but any help with it would be appreciated, thanks!
bool MyLinkedList::Insert(ListNode *newNode)
{
// Assume ListNode is a structure and contains the variable int key;
// Assume the function returns true if it successfully inserts the node
ListNode *back = NULL, *temp = head;
if(head == NULL) // Check for inserting first node into an empty list
{
head = newNode;
return true;
}
else
{ // Search for insert location
while((**???**) && (**???**))
{
back = temp; // Advance to next node
temp = temp -> next;
{
// Check for inserting at head of the list
if(back == NULL)
{
newNode -> next = head; // Insert at head of list
head = newNode;
return true;
}
else // Insert elsewhere in the list
{
newNode -> next = temp;
back -> next = newNode;
return true;
}
}
return false; // Should never get here
}
I am assuming you have the following structure for ListNode (based on your prior comment).
struct ListNode {
int Key;
double dataValue;
ListNode *next;
}
On the assumption that the list is ordered based on the key values, the while loop condition should look like this:
while((temp != NULL) && (temp->Key < newNode->Key))
The rest of the code seems to agree with it.
The second argument would need change if the comparison methodology for ordering the sorted list is different than simple key comparison.
while((**???**) && (**???**))
You need to insert your comparisons here. Whatever kind of data is inside the ListNode, you should have some way of comparing two of them. I suspect you have an overloaded operator if it isn't a primitive type.

Why isn't my remove node function working?

I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.

How can I use iteration instead of recursion to input values into a linked list?

Ok so let's say we have a linked list of characters with a head pointer. How can I create a loop to enter a string of characters into the linked list? My problem is when I think of head and head->next and head->next->next . . . it only seems natural to use a recursive function to set the characters at each node.
It's trivial to do it with iteration. You would just start at head, and use a loop to iterate over the list by doing current = current->next, until you hit a NULL.
Basically something like:
node* n = head;
while (n) {
// ... do something with n
n = n->next;
}
As you are using C++, then using std::list and an iterator would seem to be the way to go. Writing your own linked list is OK as a learning exercise, but please don't use such a thing in real code.
Assuming your linked list already has enough space in it:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
n->data = input[i];
n=n->next;
}
Otherwise you need to check each time for a null value before adding the data:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
if !(n)
{
break;
}
n->data = input[i];
n=n->next;
}
Another solution would involve adding a new element when you hit the end:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
n->data = input[i];
if (!n->next && i < len-1)
{
n->next = new Node;
}
n = n->next;
}
First, it depends on whether it's a doubly-linked list, or a singly linked list -- but it sounds like you're dealing with a singly-linked list.
With a singly linked list it's easiest to add nodes to the beginning of the list. If that works for you, something like:
node *head; // head of the list
// insert node:
new_node->next = head;
head = new_node;
If you want to add to the end of the list, you walk through the list first:
// If the list is empty, just add the node at the head:
if (head == NULL) {
new_node->next = head;
head = new_node;
}
else {
// There's already data in the list, so walk to the end of the list:
node *pos;
for (pos=head; pos->next!=NULL; pos=pos->next)
;
new_node->next = NULL;
pos->next = new_node;
}
As a general rule, neither of these makes a lot of sense though. It's only really sensible to use a linked list when you plan on doing insertions and deletions somewhere in the middle of the list, and you normally save the position (i.e. a pointer to) where you're going to do the insertion or deletion.