Inserting Before/After Node in Linked List - c++

I am trying to insert nodes in a list based on the value of a data member. Basically, if the member isVip evaluates to true, that node gets precedence, and should be inserted ahead of any regular node (but behind any existing VIP nodes). Regular nodes simply get added at the end of the list.
I'm pretty sure I have a good idea of how to use two pointers to step through the list and insert elements for n > 2 where n is the number of current list members, but I'm sort of conceptually stuck for the case when there's only one node.
Here is my working version of code below:
void SelfStorageList::rentLocker(Locker e) {
int count = 0;
LockerNode *p = head;
if (isEmpty()) {
head = new LockerNode(e);
tail = head;
}
for(;p!=0;count++, p=p->next) {
if(count == 1) {
if (e.isVip) {
if(p->objLocker.isVip) {
LockerNode*p = new LockerNode(e, p->next);
}
}
}
}
As you can see, I'm checking to see if the passed in object is VIP, and then whether the current one is. Here, I've hit some trouble. Assuming both are VIP, will this line:
LockerNode*p = new LockerNode(e, p->next);
put the passed in locker object in the correct place (i.e. after the current VIP one). If so, would:
LockerNode*p = new LockerNode(e, p);
equivalently place it before? Is the use or absence of the 'next' member of the node what defines the placement location, or is it something entirely different?
Hope someone can clear my doubts, and sorry if it seem a foolish question! Thanks!

Simply iterate over the list while the next node have isVip set (current->next->isVip). After the iteration, the last node visited will be the last with isVip set, and you should insert the new node after that one.
It can be implemented in fewer lines, without the explicit isEmpty check, and without any counter. Even less than that if you use a standard container instead.

Related

Tree traversal falls into infinite loop (with huffman algorithm implementation)

I am trying implementing the huffman algorithm following the steps described in this tutorial: https://www.programiz.com/dsa/huffman-coding, and so far I got this code:
void encode(string filename) {
List<HuffmanNode> priorityQueue;
List<Node<HuffmanNode>> encodeList;
BinaryTree<HuffmanNode> toEncode;
//Map<char, string> encodeTable;
fstream input;
input.open(filename, ios_base::in);
if (input.is_open()) {
char c;
while (!input.eof()) {
input.get(c);
HuffmanNode node;
node.data = c;
node.frequency = 1;
int pos = priorityQueue.find(node);
if(pos) {
HuffmanNode value = priorityQueue.get(pos)->getData();
value++;
priorityQueue.update(pos, value);
} else {
priorityQueue.insert(node);
}
}
}
input.close();
priorityQueue.sort();
for(int i=1; i<=priorityQueue.size(); i++)
encodeList.insert( priorityQueue.get(i) );
while(encodeList.size() > 1) {
Node<HuffmanNode> * left = new Node<HuffmanNode>(encodeList.get(1)->getData());
Node<HuffmanNode> * right = new Node<HuffmanNode>(encodeList.get(2)->getData());
HuffmanNode z;
z.data = 0;
z.frequency = left->getData().frequency + right->getData().frequency;
Node<HuffmanNode> z_node;
z_node.setData(z);
z_node.setPrevious(left);
z_node.setNext(right);
encodeList.remove(1);
encodeList.remove(1);
encodeList.insert(z_node);
}
Node<HuffmanNode> node_root = encodeList.get(1)->getData();
toEncode.setRoot(&node_root);
}
full code for the main.cpp here: https://pastebin.com/Uw5g9s7j.
When I try run this, the program read the bytes from the file, group each character by frequency and order the list, but when I try generate the huffman tree, I am unable to traverse this tree, always falling into a infinte loop (the method get stuck in the nodes containing the 2 first items from the priorityQueue above).
I tried the tree class with BinaryTree<int>, and everything works fine in this case, but with the code above the issue happens. The code for the tree is this (in the code, previous == left and next == right - I am using here the same Node class already implemented for my List class): https://pastebin.com/ZKLjuBc8.
The code for the List used in this example is: https://pastebin.com/Dprh1Pfa. And the code for the Node class used for both the List and the BinaryTree classes is: https://pastebin.com/ATLvYyft. Anyone can tell me what I am missing here? What I am getting wrong here?
UPDATE
I have tried a version using only c++ stl (with no custom List or BinaryTree implementations),but the same problem happened. The code is that: https://pastebin.com/q0wrVYBB.
Too many things to mention as comments so I'm using an answer, sorry:
So going top to bottom through the code:
Why are you defining all methods outside the class? That just makes the code so much harder to read and is much more work to type.
Node::Node()
NULL is C code, use nullptr. And why not use member initialization in the class?
class Node {
private:
T data{};
Node * previous{nullptr};
Node * next{nullptr};
...
Node::Node(Node * node) {
What is that supposed to be? You create a new node, copy the value and attach it to the existing list of Nodes like a Remora.
Is this supposed to replace the old Node? Be a move constructor?
Node::Node(T data)
Write
Node<T>::Node(T data_ = T{}) : data{data_} { }
and remove the default constructor. The member initialization from (1) initializes the remaining members.
Node::Node(T data, Node * previous, Node * next)
Again creating a Remora. This is not inserting into an existing list.
T Node::getData(), void Node::setData(T value)
If everyone can get and set data then just make it public. That will also mean it will work with cons Node<T>. Your functions are not const correct because you lack all the const versions.
Same for previous and next. But those should actually do something when you set the member. The node you point to should point back to you or made to do so:
void Node::setPrevious(Node * previous) {
// don't break an existing list
assert(this->previous == nullptr);
assert(previous->next == nullptr);
this->previous = previous;
previous->next = this;
}
Think about the copy and move constructors and assignment.
Follow the rule of 0/3/5: https://en.cppreference.com/w/cpp/language/rule_of_three . This goes for Node, List, ... all the classes.
List::List()
Simpler to use
Node<T> * first{nullptr};
List::~List()
You are deleting the elements of the list front to back, each time traversing the list from front till you find index number i. While horrible inefficient the front nodes have also already been deleted. This is "use after free".
void List::insert(T data)
this->first = new Node<T>();
this->first->setData(data);
just write
first = new Node<T>(data);
And if insert will append to the tail of the list then why not keep track of the tail so the insert runs in O(1)?
void List::update(int index, T data)
If you need access to a list by index that is a clear sign that you are using the wrong data structure. Use a vector, not a list, if you need this.
void List::remove(int index)
As mentioned in comments there are 2 memory leaks here. Also aux->next->previous still points at the deleted aux likely causing "use after free" later on.
int List::size()
Nothing wrong here, that's a first. But if you need this frequently you could keep track of the size of the list in the List class.
Node * List::get(int index)
Nothing wrong except the place where you use this has already freed the nodes so this blows up. Missing the const counterpart. And again a strong indication you should be using a vector.
void List::set(int index, Node * value)
What's this supposed to do? Replace the n-th node in a list with a new node? Insert the node at a specific position? What it actually does it follow the list for index steps and then assign the local variable aux the value of value. Meaning it does absolutely nothing, slowly.
int List::find(T data)
Why return an index? Why not return a reference to the node? Also const and non-const version.
void List::sort()
This code looks like a bubblesort. Assuming it wasn't totaly broken by all the previous issues, would be O(n^4). I'm assuming the if(jMin != i) is supposed to swap the two elements in the list. Well, it's not.
I'm giving up now. This is all just the support classes to implement the BinaryTree, which itself is just support. 565 lines of code before you even start with your actual problem and it seems a lot of it broken one way or another. None of it can work with the state Node and List are in. Especially with copy construction / copy assignment of lists.

reverse linked list using recursion

I am trying to reverse a linked list using recursion. I made the reverse() function to reverse the list. I created a linked list in main() and also defined print() method.
I don't know what mistake I am making. Please help me correct it. The code snippets are given below.
struct node
{
int data;
struct node *next;
}*head;
void reverse(node **firstnode,node *n)
{
if(n==NULL)
{
head=n;
return;
}
reverse(&head,n->next);
struct node *q=n->next;
n->next=q;
q->next=NULL;
}
void main()
{
......
head=first;
reverse(&first,first);
print(head);
}
It may not address your question directly. However, you mentioned C++11 in the tags. So, take look at std::forward_list. It is a standard container that is based on single linked-list.
List* recur_rlist(List* head)
{
List* result;
if(!(head && head->next))
return head;
result = recur_rlist(head->next);
head->next->next = head;
head->next = NULL;
return result;
}
void printList(List* head)
{
while(head != NULL) {
std::cout<<head->data<<" ";
head = head->next;
}
}
void main()
{
List* list = createNode(2);
append(list, createNode(3));
append(list, createNode(4));
append(list, createNode(5));
append(list, createNode(6));
List* revlist = recur_rlist(list);
printList(revlist);
}
I think you mixed up your addressing at the end of the reverse function, it should probably look like:
q->next=n;
n->next=NULL;
Also, I am not sure if you need the "firstnode" argument.
Since you want to understand the code, and you have several great resources with finished code already, more finished code examples aren't needed. I'll just answer with some concepts and point you at the errors you need to fix.
First, some background concepts.
Linked lists: first and rest
Any linked list is either empty, or can be broken down into first (a node) and rest (a smaller linked list, or empty). This makes recursion much easier.
if (head){
node * first = head;
node * rest = head->next;
}
Invariant (simplified): A guarantee that is always true at the start and end of your function.
In a linked list, you expect that head points to a node, which points to another node, and so forth, until you get to the end, which is signaled by a nullptr. All of the nodes are different. All of the nodes are valid. These are the guarantees that must be true before you call your function and when your function returns.
In a recursive function, the invariants must hold on the sublist you are reversing at every step, because you return from the function at every step. But this makes recursion much easier because all you have to do is make sure that if the input is good, then your function will return a good value at the current step.
End of recursion:
You can prove that your recursive function never gets in an infinite loop by combining the previous concepts. If the invariants hold, then each step will work, and because each recursive call will take rest, which is guaranteed to be either nullptr or a shorter list, eventually we have to reach the end. And of course show that you handle the end.
Okay, on to the actual problems:
You don't handle end of recursion correctly. You just set head=nullptr at the end, and I'm pretty sure that's not what you want for head. You may want to handle the end if (nullptr == n->next), because then you know that is the last node. Of course, you still have to correctly handle the trivial case where nullptr==head.
You don't preserve invariants. You tried, but it looks like your bookkeeping is just all wrong. I suggest using the debugger or 3x5 notecards to step through what you're actually doing to fix the actual work of swapping things around. For example, it looks like you just confused which node is which in this code snippet:
struct node *q=n->next; // n is first, q is rest
// what if nullptr == q?
n->next=q; // n->next = n->next doesn't actually change anything
q->next=NULL; // this must already be true if reverse(rest) did its job
// q and n were swapped?
Also, your function takes "firstnode" but does not use it, but instead sets the global variable "head" as a side effect.

How does a linked list with Node class work in C++?

I'm currently taking data structures and algorithms class and turns out it is heavily geared on the concepts of linked lists. These are some things I have difficulty understanding:
How do I insert a number into data?
How do I move from one node to the next?
How do I call the Node class in main and print out the data values?
I have the following code. Am I doing it wrong?
#include <iostream>
using namespace std;
class LinkedList
{
class Node
{
public:
Node (int data, Node *n);
int data;
Node *next;
};
Node *head;
};
int main()
{
LinkedList::Node NodeObj;
NodeObj.data = 5;
cout <<NodeObj.data;
return 0;
}
A nice tutorial is at: http://www.zentut.com/c-tutorial/c-linked-list/
From a programming perspective, normally your LinkedList class would have some methods to do the things you asked about, for example:
Add - create a new entry at the end of the linked list
InsertAfter(Node *n) - create a new entry after indicated node in the listed list
Remove(Node *n) - removes the indicated node from the linked list
Count() - returns a count of the number of nodes within the linked list
Get(long i) - returns a pointer to the ith entry in the linked list
Find(some type of criteria) - return a pointer to the node that matches
Destroy - remove all the nodes in the linked list
Then your mainline just invokes these methods to utilize the linked list (the whole point of object encapsulation). Note that there is a LinkedList object instantiated, and it instantiates and manages the Node objects.
So if you had 10 numbers to store from some input array (inArray), you could do something like:
Node* n;
llObj = new LinkedList;
For (i=0; i<=9; i++) {
n = llObj.add();
n.data = inArray[i];
}
To step through the linked list, you would do something like:
For (i=0; i<=llObj.Count(); i++) {
n = llObj.get(i);
n.data = n.data + 1;
}
However, if you write yourself a .get() method from the code samples below, you will see that above code is terribly inefficient, and is not the ideal way to step through the entire linked list from mainline code.
To find the number 6:
n = llObj.find(6);
And so forth. Normally a linked list does not store just one data value such as in your example, but rather stores a structure or an object. Hence methods like Find become more useful because you can create Find methods that look at various fields in a structure or an object.
An Add method just traverses all the existing entries in the listed list until the last one is found, then creates a new entry, and links the former last entry to the now new last entry.
Node* LinkedList::add() {
void *n = NULL;
if (head != NULL) {
// one or more Nodes do exist
// first loop until we find the last-most node who's n.next == NULL
n = head;
while (n.next != NULL) n = n.next;
// found the last node, now allocate a new Node, and store a pointer to it in the formerly last node's .next property
n.next = new Node;
n = n.next;
// IMPORTANT: ensure this new last Node's .next is forced to be null
n.next = NULL;
}
else
{
// the header is NULL, so there is no first node yet
// allocate a new Node and store a pointer to it in the LinkedList header
head = new Node;
n = head;
// IMPORTANT: ensure this first Node's .next is forced to be null
n.next = NULL;
{
return n;
}
Note the While loop ... this is the key linked-list traversal mechanism. That loop checks the current node's .next field ... if it has a non-NULL pointer, then the loop cycles by copying that .next pointer to the loop pointer n, and tests again. Once the loop finds a node who's .next is NULL, then the lastmost node has been found, and the loop exits, with n containing the pointer to that lastmost node.
Note also the If statement concerning the .head property of the LinkedList class. One always has to do some special code for accounting for when the linked list is empty. There are a couple of ways of handling that; I chose the one that uses the least data memory.
Removing a node means just "skipping over it" in the linked list. We traverse the listed list until we find the one to remove, the we just "move back" its .next property to the prior entry's .next pointer. A good image is in the Linked List wikipedia entry:
A code example:
void LinkedList::remove(Node* nodeToRemove) {
// do nothing if we've been given a NULL pointer
if (nodeToRemove == NULL) return;
Node *n;
if (nodeToRemove == head) {
// the node to remove is the very first node, so set the head
// to the contents of the first node's .next property
head = n.next;
delete n;
return;
}
// need to find the indicated node; the following loop locates the
// node that is immediately before the node to be removed; note too
// that we have to test for the end of the linked list because the
// caller may have provided a bad pointer value
n = head;
while (n.next != NULL && n.next != nodeToRemove) n = n.next;
if (n.next == NULL) return; // reached end of linked list without finding the node
// good, the node immediately before the node to remove has been found!
Node* r = n.next; // this is inefficient code but want to make it very clear to newbies
n.next = r.next;
delete r;
}
Note that again we have to do some special logic concerning the LinkedList header. And do pardon the fact that I've used returns in the code; many finicky stickers would consider that a no-no. Also note in the code above, we don't need to do special logic to account for the end of the linked list, only just its beginning. If the node-to-remove is the last node in the linked list (and its r.next therefore == NULL), then the "n.next = r.next" line of code just moves the NULL back one position in the linked list, which is exactly what we would want.
You should be able to now figure out how to create all those other methods in your LinkedList class that I mentioned.
===============================
I do like someone's answer that unfortunately he deleted. For a 5 year old, a linked list is indeed a lot like the game of Treasure Hunt. In a Treasure Hint, you have to physically go to each location to get the clue to the next location. And in a linked list you have to access the location of a node to find the address of the location of the next node. A perfect analogy, and kudos for the answerer that first provided it.

C++ Circular Linked List : remove element

I am done with insertion, search in circular linked list but for removal I am getting compiler errors...
Following is my structure for nodes.
struct node
{
int p_data;
struct node* p_next;
node(node* head, int data)
{
p_next = head;
p_data = data;
}
explicit node(int data)
{
p_next = nullptr;
p_data = data;
}
};
node* remove_circular(node* head, node* target)
{
if (head == target->p_next)
{
delete head;
return nullptr;
}
auto next_pointer = target->p_next;
target->p_data = next_pointer->p_data;
target->p_next = next_pointer->p_next;
delete target->p_next;
return target;
}
and in main function I call
head = remove_circular(head, head);
head = remove_circular(head, temp);
this is to remove head element and another element that temp points to.
But I am getting errors
Anybody has any idea to remove one element from circular list??
I changed it to delete target->p_next;
but now it deletes everything in the list.
Any idea???
This is how a circular linked list works:
Each node points to the next in line, and the tail of the list points to the header node. That's the difference from a circular linked list to a regular linked list (which, in the case above, would make 37 point to a terminator null).
In the case of your list having only one object, then it should look something like this:
So, as you can see, there is no object pointing to null anywhere, yet it happens on your code with your explicit constructor (which will run if I write node n = node(12)).
I suggest you take a look at this link to have a better understanding of how your algorithm should look like.
Once you resolve your compiler error, you are still going to have algorithmic issues. I suggest you draw a circular list on paper and think about the steps required to remove an element. Consider all the cases, for example: empty list, list of 1 item, element not in the list, etc.
You need to consider several things.
1.) the case of an empty list
if(head == nullptr){//Empty list case
return nullptr;
}
2.) The target to be removed is the head node and this is the only node in the list.
if (head == target && target->p_next == head){
create a temp node with the data value of target
target = nullptr;//Since nothing points to target now it is for all intents and purposes deleted from the list but the data is still there so you can do something with it. I assume this is necessary because you return a node *.
return the temp node
}
3.) Create a loop that iterates through the entire list. You have something that would only delete the next node which works if you have a two item list and target was the second item.
auto next_pointer = head->p_next;//could not be target->p_next as this assumed
while (next_pointer->p_next != target){//This while loop traverses the list rather than just deleting the next entry.
4.)Inside you loop add a check to see if the list has been traversed and target was never found.
if (next_pointer->p_next == head){
return nullptr;
}//end IF
5.) Inside the loop add the else case which means target was in an arbitrary location in the list. Since I gave you the rest I'll leave you to get this part. It's not hard just a few lines longer than the statements above.

How do you insert into a sorted linked list? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
LinkedList “node jump”
I just need to have a linked list in order by name. I can only get it as far as 1st, 3rd, 5th, .. nodes. I just can't think this far. I want to be a C++ programmer but if I can't understand this is their any hope? STL containers std::lists are not an option for me at this point as a student. What you see in the list function is what I am TRYING to understanding.
list::node::node(const winery &winery) : item( winery.getName(), winery.getLocation(),
winery.getAcres(), winery.getRating() ), nextByName( NULL ), nextByRating( NULL )
{
}
void list::insert(const winery& winery)
{
node *current_node = new node( winery ); // but came here and did this so it has new info!
node *next_node = NULL;
node *tail_node = current_node;
if ( headByName == NULL ) // then we are here for the first item
{
headByName = current_node; // the list ptrs will have the first node's address.
headByRating = current_node;
}
while ( headByName->nextByName != NULL )
{
headByName->nextByName = tail_node;
tail_node = next_node;
//next_node = current_node;
}
tail_node = new node( winery );
headByName->nextByName = tail_node;
}
And the pointers that are available to me:
struct node
{
winery item;
node * nextByName;
node * nextByRating;
};
class list
{
...
private:
node * headByName;
node * headByRating;
};
Of course there's hope, we all have to start somewhere! :)
First of all, I must point out a dangerous practice in your implementation that my own students used, and it usually resulted in lots of head scratching to find the problem:
while ( headByName->nextByName != NULL )
{
headByName->nextByName = tail_node;
tail_node = next_node;
//next_node = current_node;
}
Don't use a list member like headByName as your iterating variable within your loop unless it is absolutely necessary. You should find the appropriate node first using a local variable, and then modify that node.
That said, Rob Kennedy is right that you should handle the name and rating separately (in other words a 'pure' implementation would have two instances of a generic list class that is unaware of what 'name' and 'rating' mean), however I assume the interfaces for list, node and function above were given to you in the assignment (if not, disregard the rest of my answer :) ).
Given the above interfaces, my approach would be as follows:
void list::insert(const winery& winery)
{
node* wineryNode = new node(winery);
assert (wineryNode);
// Find a node in the list with a name greater than wineryNode's
node* prevNode = NULL;
node* searchNode = headByName; // Note: not using the list member itself to iterate but a local variable
while (NULL != searchNode &&
searchNode.winery.getName() < wineryNode.winery.getName())
{
// Keep iterating through the list until there are no more items, or the right node is found
prevNode = searchNode;
searchNode = searchNode->nextByName;
}
/* At this point searchNode is either NULL
or it's name is greater than or equal to wineryNode's */
// Check for the case where the list was empty, or the first item was what we wanted
if (NULL == prevNode)
{
headByName = wineryNode;
}
else
{
// prevNode is not NULL, and it's Name is less wineryNode's
prevNode-> nextByName = wineryNode;
}
wineryNode->nextByName = searchNode;
/* Now you just need to insert sorted by rating using the same approach as above, except initialize searchNode to headByRating,
and compare and iterate by ratings in the while loop. Don't forget to reset prevNode to NULL */
}
You called this a doubly linked list, and although it's true that your nodes each have two links, this isn't really what most people think of when they hear about doubly linked lists. Since your two links are apparently unrelated to each other — nobody rates wineries alphabetically — it will be a little easier if you don't think of this as a doubly linked list.
The usual place to insert into a linked list, when a more specific order isn't required, is at the end of the list. The steps to do that are as follows:
Create a new node.
Find the place to insert the new node (i.e., the last node, at end of the list)
Update the last node's "next" pointer to point to the new node.
When you're inserting into what may be the middle of the list, as is the case for you, then there is another step:
2.5. Update the new node's "next" pointer.
The reason that step isn't usually there is that when inserting at the end of a list, the new node's "next" pointer is already null from when you constructed the new node object.
You've figured out the first step already. In fact, you've done it too well because your code actually creates two new nodes. One you store in current_node and the other you store in tail_node. Get rid of the second one.
Step 2 is about figuring out which node should be the one that immediately precedes the new node. When ordering by name, that would be the node that comes before the first node you find that has a name after the current name. You're going to have to walk along the list, possibly looking at every node, until you find one that belongs after the new node's name. As you move along the list, you're going to have to keep track of which node came before that node, too, because once you find the node you're looking for, you're going to have to backtrack.
Worry about the name and the rating separately. Don't try to solve both parts at once. Once you get the winery inserted correctly by name, then duplicate that code and replace "name" with "rating." But don't create another node object. Keep using the same one you created before.
As you've worked on this assignment, have you drawn any pictures of nodes with arrows pointing to other nodes? Try it. You've surely seen it done in your textbook or on your teacher's chalkboard. If a problem is too big for you to reason about entirely in your head, then use something to help you keep track of things outside your head. The professionals do it, too. Since each node has multiple pointers, you should either label the pointers or use different colors for name and rating.
To be a doubly-linked list each node must have a pointer to the node before and after it. You can also store a head and tail node if you like, but that would be more for personal convenience than to meet the requirements of a doubly-linked list.
I'm not sure I understand your question exactly. Going just from the topic "How do you insert into a sorted linked list?" I would do something like this (pseudocode):
list::insert(Winery winery) {
Winery node = getHeadNode();
// winery comes before the head node
if (winery.name < node.name) {
// the old head node now goes after this new node
// and this new node becomes the new head node
winery.next = node;
setHeadNode(winery);
return;
}
// let's iterate over the rest of the nodes in the list
Winery previous_node = node;
node = node.next;
while (node != NULL) {
// we found our insertion point
if (winery.name < node.name) {
// insert our new node
previous_node.next = winery;
winery.next = node;
return;
}
// insertion point not found, move to the next node and repeat
previous_node = node;
node = node.next;
}
// all elements visited, append our new element to the end of the list
previous_node.next = winery;
winery.next = NULL;
}
The above algorithm will insert your new node in the appropriate place in the list, assuming the list is sorted by name.