Algorithm for creating a "relative" priority queue? (c/c++) - c++

I want to make a queue using linked lists.
There are numerous algorithms out there for that. But what i'm curious in is how to make a relative priority queue.
Maybe there is a special name for this type of queue, but i don't know it, and i haven't had any luck googling for the solution.
Anyways, let's say i have this struct, which will represent the Node of my list.
struct Node {
int value;
Node* next;
}
if i want to create a priority queue (where the element with the least value is first), when i insert for example 5 7 1 8 2, my list should look like this:
1 -> 2 -> 5 -> 7 -> 8
It's not really hard to implement that.
What i want to do is - when i insert the first element, other elements should have value relative to the previous element. So, in my example, the list/queue would contain the following values:
1 -> 1 -> 3 -> 2 -> 1
I'm not really sure how i would implement that? Would the following idea be applicable:
in the Node struct i add another field, which would represent the original value.
i find the position of the node i'm inserting the same way i would do when creating an ordinary linked list, and then i just say
temp->value = temp->originalValue - previous->originalValue;

You need to store extra data in each node, either the relative priority, or a "previous" pointer. Since the next node's relative priority needs to updated whenever a node is removed (how to do that without a prev pointer?), I suggest the "previous" pointer:
struct Node {
int value;
Node* next;
Node* prev;
}
Then a function can evaluate the relative priority:
int relative_priority(Node* node) {
if (node == NULL)
return 0;
if (node->prev == NULL)
return node->value;
return node->value - node->prev->value;
}
Note that I'm using C, you'll need to replace NULL with 0 for C++

You first have to identify where to insert the new node. This involves decrements on the target value, adjusting its relative value in relation to the current in the list. At the point of insertion, you have to point the previous node to the new node, and then adjust the node ahead of the new node with a new relative value.
Node * create_node (int value, Node *next) { /* ... */ }
void insert_relative_priority_queue (Node **head, int value) {
Node **prev = head, *cur;
if (*head) {
cur = *head;
while (value > cur->value) {
value -= cur->value;
prev = &cur->next;
cur = cur->next;
if (cur == 0) break;
}
*prev = create_node(value, cur);
if (cur) {
cur->value -= value;
}
} else {
*head = create_node(value, 0);
}
}
When you remove from the front of the list, you adjust the value of the new head:
void remove_relative_priority_queue (Node **head) {
if (*head) {
Node *cur = *head;
*head = cur->next;
if (*head) {
(*head)->value += cur->value;
}
free(cur);
}
}

Related

How to delete from the last node in a linked list to a specific node in that list using recursion

So i am trying to delete from a specific node in a linked list but the problem doesn't come from deleting from the node to end ,it comes from trying to delete from the last node to a specific node while trying to use a recursion.
This is what I currently have (deleting from the node to last node)
void rLL<T> :: recursiveDelete(item<T> * node)
{
if (node != nullptr)
{
item<T> * nodeptr = node -> next;
delete node;
size--;
recursiveDelete(nodeptr);
}
}
Now I have to try and switch it around.And I have no idea how to do that.
This is for a school project so please ,if possible, try to keep it simple.
edit:Let's say the list consist of 1,2,3,4,5,6,7 and node 5 was put in to the parameter node then 7 ,6 ,5 should be deleted in that specific order (to clear things up a bit)
The answer to your question is to simply perform the recursive call before calling delete.
However, even if you were able to delete the specified node without failure, the code you presented would still have a major flaw - it does not update the next field of the node prior to the specified node, so you would end up leaving the list in an invalid state, as that prior node would become the new tail node but have a non-null next pointer that does not terminate the list properly.
For a single-linked list, you would have to iterate from the front of the list in order to discover that prior node to update. But once you reach the specified node, and know its previous node, then you can use a recursive algorithm for the rest of the list, eg:
template<typename T>
void rLL<T>::recursiveDelete(item<T> *node, item<T> *previous)
{
if (!node) return;
recursiveDelete(node->next, node);
if (previous) previous->next = nullptr;
--size;
delete node;
}
void rLL<T>::deleteToEnd(item<T> *startNode)
{
if (!startNode) return;
item<T> *node = head;
item<T> *previous = nullptr;
while (node)
{
if (node == startNode)
{
recursiveDelete(node, previous);
return;
}
previous = node;
node = node->next;
}
}
Live Demo
That being said, a double-linked list is better suited for this task, as you don't need to iterate from the front of the list at all, you can start right at the specified node, eg:
void rLL<T>::deleteToEnd(item<T> *startNode)
{
if (!startNode) return;
deleteToEnd(startNode->next);
item<T> *previous = startNode->previous;
if (previous) previous->next = nullptr;
if (head == startNode) head = nullptr;
tail = previous;
--size;
delete startNode;
}
Live Demo
If I understand this correctly, you want to delete a node that points to your specific node. If I were doing this I would have 2 nodes, currentNode and prevNode. When you iterate forward you move both of them and that way when currentNode meets the specifications, you can delete prevNode. If I don't understand the question right let me know.

Linked list concepts

Value of node in *node=*(node->next), if node is the last element in linked list?
Value of node would be NULL or not?
Given a singly linked list consisting of N nodes. The task is to remove duplicates (nodes with duplicate values) from the given list (if exists).
Note: Try not to use extra space. Expected time complexity is O(N). The nodes are arranged in a sorted way.
This solution didn't work for test case 2 2 2 2 2 (five nodes with equal values).
Node *removeDuplicates(Node *root)
{
if(root->next==NULL)
return root;
Node * t1=root;
Node* t2=root->next;
while(t2!=NULL)
{
if(t1->data==t2->data)
{
*t2=*(t2->next);
}
else
{
t1=t1->next;
t2=t2->next;
}
}
return root;
}
This worked:
Node *removeDuplicates(Node *root)
{
if(root->next==NULL)
return root;
Node * t1=root;
Node* t2=root->next;
while(t2!=NULL)
{
if(t1->data==t2->data)
{
if(t2->next==NULL)
{
t1->next=NULL;
t2=NULL;
}
else
{
*t2=*(t2->next);
}
}
else
{
t1=t1->next;
t2=t2->next;
}
}
return root;
}
Normally I wouldn't post the full code for something that is clearly homework but I wasn't sure how to properly articulate all of the points. I also haven't compiled and ran this because I didn't want to create my own Node class.
First we can talk about the algorithm. If your singly linked list is already sorted and NULL terminated then essentially we have a current node pointing to a node in the list and a travel node (nextNode) that walks down the list. The main thing we need to make sure we do is update the pointers to point to the next node once we've found a non-duplicate.
In the code below I've also added NULL checks which is incredibly important. Get in the habit of knowing exactly which state your variables could be in as it is easy to accidentally call a method on a null pointer which would cause the program to crash.
Node* removeDuplicates(Node* root)
{
// Check that root isn't null before checking that its next pointer is also not NULL
if (root == NULL || root->next == NULL)
return root;
// Set up our current node and the travel node
Node* currentNode = root;
Node* nextNode = root->next;
// Until we've reached the end of the singly linked list
while (nextNode != NULL)
{
// Find the next node that isn't a duplicate
// Also check that we don't reach the end of the list
while (nextNode->data == currentNode->data && nextNode != NULL)
nextNode = nextNode.next;
// Update the current node's next pointer to point to the travel node
currentNode->next = nextNode;
// Update the current node to its next for the next iteration
currentNode = nextNode;
// Update the next node being careful to check for NULL
nextNode = nextNode == NULL ? NULL : nextNode->next;
}
return root;
}
This is not the only way to handle this problem. By reorganizing when you do certain checks and associations you can eliminate some of the NULL checks or make the program more clear. This is just one possible solution.

Adding a node to a complete tree

I'm trying to make complete tree from scratch in C++:
1st node = root
2nd node = root->left
3rd node = root->right
4th node = root->left->left
5th node = root->left->right
6th node = root->right->left
7th node = root->right->right
where the tree would look something like this:
NODE
/ \
NODE NODE
/ \ / \
NODE NODE NODE NODE
/
NEXT NODE HERE
How would I go about detecting where the next node would go so that I can just use one function to add new nodes? For instance, the 8th node would be placed at root->left->left->left
The goal is to fit 100 nodes into the tree with a simple for loop with insert(Node *newnode) in it rather than doing one at a time. It would turn into something ugly like:
100th node = root->right->left->left->right->left->left
Use a queue data structure to accomplish building a complete binary tree. STL provides std::queue.
Example code, where the function would be used in a loop as you request. I assume that the queue is already created (i.e. memory is allocated for it):
// Pass double pointer for root, to preserve changes
void insert(struct node **root, int data, std::queue<node*>& q)
{
// New 'data' node
struct node *tmp = createNode(data);
// Empty tree, initialize it with 'tmp'
if (!*root)
*root = tmp;
else
{
// Get the front node of the queue.
struct node* front = q.front();
// If the left child of this front node doesn’t exist, set the
// left child as the new node.
if (!front->left)
front->left = tmp;
// If the right child of this front node doesn’t exist, set the
// right child as the new node.
else if (!front->right)
front->right = tmp;
// If the front node has both the left child and right child, pop it.
if (front && front->left && front->right)
q.pop();
}
// Enqueue() the new node for later insertions
q.push(tmp);
}
Suppose root is node#1, root's children are node#2 and node#3, and so on. Then the path to node#k can be found with the following algorithm:
Represent k as a binary value, k = { k_{n-1}, ..., k_0 }, where each k_i is 1 bit, i = {n-1} ... 0.
It takes n-1 steps to move from root to node#k, directed by the values of k_{n-2}, ..., k_0, where
if k_i = 0 then go left
if k_i = 1 then go right
For example, to insert node#11 (binary 1011) in a complete tree, you would insert it as root->left->right->right (as directed by 011 of the binary 1011).
Using the algorithm above, it should be straightforward to write a function that, given any k, insert node#k in a complete tree to the right location. The nodes don't even need to be inserted in-order as long as new nodes are detected created properly (i.e. as the correct left or right children, respectively).
Assuming tree is always complete we may use next recursion. It does not gives best perfomance, but it is easy to understand
Node* root;
Node*& getPtr(int index){
if(index==0){
return root;
}
if(index%2==1){
return (getPtr( (index-1)/2))->left;
}
else{
return (getPtr( (index-2)/2))->right;
}
}
and then you use it like
for(int i = 0; i<100; ++i){
getPtr(i) = new Node( generatevalue(i) );
}
private Node addRecursive(*Node current, int value) {
if (current == null) {
return new Node(value);
}
if (value < current.value) {
current->left = addRecursive(current->left, value);
} else if (value > current->value) {
current->right = addRecursive(current->right, value);
} else {
// value already exists
return current;
}
return current;
}
I do not know that if your Nodes has got a value instance but:
With this code you can have a sorted binary tree by starting from the root.
if the new node’s value is lower than the current node’s, we go to the left child. If the new node’s value is greater than the current node’s, we go to the right child. When the current node is null, we’ve reached a leaf node and we can insert the new node in that position.

obtain the address of a node given a node address in a linked list

So I have a pretty good understanding of iterating through a linked list, and also obtaining the next node in the list. Now I trying to go in the other direction, but I soon realized its not as easy as it appears. Unlike an array where you can iterate forwards and backwards. I seem to be stumped.
So If I have a list of 1 -> 2 -> 3 -> 4 -> NULL How would I go about obtaining the address of node 2 given the location of node 3?
I started messing around with this code below which returns all items up to node 3. I just don't see how I can get that previous node? By the way searchList() returns the address of a node if you give it the node->data value. Using the list above searchList(3) returns the address of the node which has 3 as its data member.
struct node {
int data;
node* next;
};
void llclass::getPrevious() {
node *stop = searchList(nodeItem),
*start = head;
while (start != stop) {
cout << start->data << endl;
start = start->next;
}
}
With a singly-linked list like yours, it is not possible to obtain the address of node 2 if you're given only the address of node 3. You would have to start at the head node and iterate forward until reaching 3, keeping track of the previous node (2 in this case). Alternately, you could use a doubly-linked list that includes a "node *previous;" member.
Sounds like you want to get the previous node of a node whose value is given as input to you. This should do that for you:
node* llclass::getPrevious(int item)
{
node* previous = NULL;
node* current = head;
while(current)
{
if (current->data == item)
{
return previous;
}
else
{
previous = current;
current = current->next;
}
}
return NULL;
}

What is the pointer-to-pointer technique for the simpler traversal of linked lists? [duplicate]

This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).