Priority queue in C for operating system - c

I need to write a new function called enqueue_priority using my previous enqueue and dequeue functions I cant use sort premade sort I dont know how to implement the priority queue. This is for a simple linux operating system. I am just dragging this out because stack says that My question is mostly code and needs more words but I dont have anything else to say about it
this struct is in a different file
struct pcb {
uint32_t esp;
uint32_t pid;
struct pcb *next;
uint32_t priority;
};
typedef struct pcb pcb_t;
#endif
starts new file
struct pcbq {
pcb_t *head;
pcb_t *tail;
};
typedef struct pcbq pcbq_t;
pcbq_t RR_q;
pcb_t *Running;
void initq(pcbq_t *q) {
q->head = q->tail = 0;
}
bool comparePTR(pcb_t *a1, pcb_t *a2) {
return a1->priority < a2->priority;
}
void enqueue_priority (pcbq_t *q, pcb_t *item){
// item->next = 0;
// if (q->tail == 0) {
// q->tail = q->head = item;
// } else {
// q->tail->next = item;
// q->tail = item;
// }
}
void enqueue(pcbq_t *q, pcb_t *item) {
item->next = 0;
if (q->tail == 0) {
q->tail = q->head = item;
} else {
q->tail->next = item;
q->tail = item;
}
}
void default_handler();
pcb_t *dequeue(pcbq_t *q) {
if (q->head == 0) {
default_handler();
}
pcb_t *item = q->head;
q->head = q->head->next;
return item;
}
void init_rrq() {
Running = 0;
initq(&RR_q);
}
// returns 1 if no process is on the ready Q
int rr_schedule() {
if (Running == 0) {
default_handler();
}
if (RR_q.head == 0)
return 1; // running process is the only one in the system
enqueue(&RR_q, Running);
Running = dequeue(&RR_q);
return 0;
}
void rr_schedule_first() {
if (RR_q.head == 0)
default_handler();
Running = dequeue(&RR_q);
}
void rr_enqueue(pcb_t *pcb) {
enqueue(&RR_q, pcb);
}

Note: As others have mentioned, there are better ways to implement a priority queue. But ...
To implement a priority queue with a linked list, one way is to insert the new item in the correct sorted place when we add a new item.
We have to scan the list looking for the proper place.
Your code had elements of both a doubly linked list and singly linked list. But, it was mostly a singly linked list (e.g. your pcb didn't have a prev pointer).
The only time the tail was used, was to append to the back of the list (in enqueue).
But, to maintain the sort, we'd probably never want to use that, but, only enqueue_priority.
So, I've simplified the code. Also, the RR* stuff wasn't relevant to the queue insertion, so I've elided that as well.
I've coded this, but not tested it:
#include <stdio.h>
#include <stdint.h>
struct pcb {
uint32_t esp;
uint32_t pid;
uint32_t priority;
struct pcb *next;
};
typedef struct pcb pcb_t;
struct pcbq {
pcb_t *head;
};
typedef struct pcbq pcbq_t;
void
initq(pcbq_t *q)
{
q->head = NULL;
}
// enqueue_priority -- enqueue item in proper sorted order
void
enqueue_priority(pcbq_t *q, pcb_t *item)
{
pcb_t *bef = NULL;
pcb_t *cur = q->head;
item->next = NULL;
// find the lower priority (use rightmost of same/equal priority)
for (; cur != NULL; cur = cur->next) {
if (cur->priority > item->priority)
break;
bef = cur;
}
do {
// empty queue
if (q->head == NULL) {
q->head = item;
break;
}
// insert after lower
if (bef != NULL) {
item->next = bef->next;
bef->next = item;
}
// insert before head of non-empty queue
else {
item->next = q->head;
q->head = item;
}
} while (0);
}
// enqueue -- enqueue at back of queue
void
enqueue(pcbq_t *q, pcb_t *item)
{
pcb_t *cur = q->head;
pcb_t *bef = NULL;
item->next = NULL;
for (; cur != NULL; cur = cur->next)
bef = cur;
// append to end of queue
if (bef != NULL)
bef->next = item;
// empty list
else
q->head = item;
}
// dequeue -- dequeue from front of queue
pcb_t *
dequeue(pcbq_t *q)
{
pcb_t *item = q->head;
do {
if (item == NULL)
break;
q->head = item->next;
item->next = NULL;
} while (0);
return item;
}
UPDATE:
The above requires a list scan. However, if we used separate queues for each priority level, we could use a modified version of the above to enqueue and dequeue faster (we add back the tail pointer).
This is [AFAIK] how OSes actually do it. It requires that we look at each queue and check for a non-null head, but with few(er) priority levels (e.g. 10), this will be faster when we have (e.g.) thousands of processes.
So, here's the modified version:
#include <stdio.h>
#include <stdint.h>
struct pcb {
uint32_t esp;
uint32_t pid;
uint32_t priority;
struct pcb *next;
};
typedef struct pcb pcb_t;
struct pcbq {
pcb_t *head;
pcb_t *tail;
};
typedef struct pcbq pcbq_t;
#define MAXPRIORITY 10
pcbq_t allqueues[MAXPRIORITY];
void
initq(pcbq_t *q)
{
q->head = NULL;
}
// enqueue -- enqueue at back of queue
void
enqueue(pcbq_t *q, pcb_t *item)
{
item->next = NULL;
// empty list
if (q->tail == NULL) {
q->tail = item;
q->head = item;
}
// append to end of queue
else {
q->tail->next = item;
q->tail = item;
}
}
// enqueue_priority -- enqueue item in proper sorted order
void
enqueue_priority(pcbq_t *q, pcb_t *item)
{
q += item->priority;
enqueue(q,item);
}
// dequeue -- dequeue from front of queue
pcb_t *
dequeue(pcbq_t *q)
{
pcb_t *item = q->head;
do {
if (item == NULL)
break;
q->head = item->next;
if (item == q->tail)
q->tail = NULL;
} while (0);
return item;
}
// dequeue_priority -- dequeue from front of highest priority queue
pcb_t *
dequeue_priority(pcbq_t *q)
{
pcb_t *item = NULL;
for (int qidx = 0; qidx < MAXPRIORITY; ++qidx, ++q) {
if (q->head != NULL) {
item = dequeue(q);
break;
}
}
return item;
}

Related

Descending Priority Queue using Linked List without taking Priority as input

I tried with following code, for inserting an element into Descending Priority Queue. I was helpless as there are several answers for this question with people taking priority as an input from user. Here i am trying to sort with following condition:
#include<stdio.h>
#include<stdlib.h>
struct qElem
{
int ele;
int priority;
struct qElem *next;
};
struct queue
{
struct qElem *front, *rear;
int size;
};
void enQueue(struct queue *q, int ele)
{
struct qElem *temp;
temp = (struct qElem *) malloc (sizeof(struct qElem));
temp->ele = ele;
temp->next = NULL;
if (q->rear == NULL) {
q->rear = temp;
q->front = temp;
}
else if (q-> rear -> ele < temp->ele){
q-> rear = temp;
temp->next = q->rear;
}
++ q->size;
}
void display_pqueue(struct queue *q) {
if(q->front == NULL)
printf("\nQueue is Empty!!!\n");
else{
struct qElem *temp = q->front;
while(temp->next != NULL){
printf("%d--->",temp->ele);
temp = temp -> next;
}
printf("%d--->NULL\n",temp->ele);
}
}
The insertion is not happening as per the order. Please help me in EnQueue and Display operations.
Your enQueue doesn't scan for the insertion point.
And, you don't provide a [separate] priority as an argument, so you can't do an insertion properly.
For illustration, I've used ele to set both ele and priority.
There are multiple insertion cases to handle:
empty list
insert at rear
insert in the middle
insert before first element in non-empty list
Anyway, here is the code. Note that although it sets rear, this was not tested:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
struct qElem {
int ele;
int priority;
struct qElem *next;
};
struct queue {
struct qElem *front, *rear;
int size;
};
#ifdef DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
int
show(struct qElem *cur)
{
int val;
if (cur != NULL)
val = cur->priority;
else
val = -1;
return val;
}
void
enQueue(struct queue *q, int ele)
{
struct qElem *temp;
struct qElem *cur;
struct qElem *prev;
temp = malloc(sizeof(*temp));
temp->ele = ele;
#if 1
temp->priority = ele;
#endif
temp->next = NULL;
dbgprt("enQueue: ele=%d\n",ele);
// find correct insertion point (place to insert _after_)
// NOTE: this is descending (e.g. 3->2->1). For ascending, use ">"
prev = NULL;
for (cur = q->front; cur != NULL; cur = cur->next) {
if (cur->priority < ele)
break;
prev = cur;
}
do {
dbgprt("prev=%d\n",show(cur));
dbgprt("cur=%d\n",show(cur));
dbgprt("front=%d\n",show(q->front));
dbgprt("rear=%d\n",show(q->rear));
// empty list
if (q->front == NULL) {
q->front = temp;
q->rear = temp;
break;
}
// insert at front
if (prev == NULL) {
temp->next = q->front;
q->front = temp;
break;
}
// insert in priority place
temp->next = prev->next;
prev->next = temp;
} while (0);
// new rear of list
if (prev == q->rear)
q->rear = temp;
// increase number of elements in list
q->size += 1;
}
void
display_pqueue(struct queue *q)
{
if (q->front == NULL)
printf("\nQueue is Empty!!!\n");
else {
struct qElem *temp = q->front;
while (temp->next != NULL) {
printf("%d--->", temp->ele);
temp = temp->next;
}
printf("%d--->NULL\n", temp->ele);
}
}
void
dotest(struct queue *q,...)
{
va_list ap;
memset(q,0,sizeof(*q));
printf("\n");
printf("dotest:");
va_start(ap,q);
while (1) {
int val = va_arg(ap,int);
if (val < 0)
break;
printf(" %d",val);
enQueue(q,val);
}
printf("\n");
display_pqueue(q);
struct qElem *next;
for (struct qElem *temp = q->front; temp != NULL; temp = next) {
next = temp->next;
free(temp);
}
}
int
main(void)
{
struct queue q;
dotest(&q,5,1,3,4,12,99,18,19,20,-1);
return 0;
}

Queue resets after every operation

I am working on a queue implementation and something weird is happening. The Enqueue seems to work but the changes are not being registered (the size stays the same at 0). From what I can tell, the code will enqueue an element but immediately forget about it. The output is:
Data passed: a34
Back befor:(null)
Back a:a34
Data passed: bg
Back befor:(null)
Back a:bg
Print (null)
Print 0
Based on this I'm guessing it's something to do with memory and scope, but I'm not sure how to resolve it.Below is the code.
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
typedef struct node_s{
void* data;
struct node_s* next;
} node;
// queue structure
typedef struct queue_s{
node* back;
node* front;
int size;
} queue_t;
//helpers
node *newNode(void *data)
{
//create a new node* with data->data. #return: a node*
node *temp = (node *)malloc(sizeof(node));
temp->data = data;
temp->next = NULL;
return temp;
}
//deep copy a n2
node* copy(node* n2){
node *temp = (node *)malloc(sizeof(node));
temp->data=n2->data;
temp->next=n2->next;
return temp;
}
queue_t que_create(void)
{
queue_t new;
new.size = 0;
node *front = (node *)malloc(sizeof(node));
node *back = (node *)malloc(sizeof(node));
new.front=front;
new.back=back;
return new;
}
void que_destroy(queue_t queue)
{
while (queue.size > 0)
{
que_dequeue(queue);
}
}
void que_clear(queue_t queue)
{
while (que_size(queue) != 0)
{
que_dequeue(queue);
}
}
void que_enqueue(queue_t queue, void *data)
{
// Create a new LL node
printf("Data passed: %s\n",data);
node *temp = newNode(data);
// If queue is empty, then new node is front and back
if (queue.size == 0){
printf("Back befor:%s\n",queue.back->data);
queue.front = copy(temp);
queue.back = copy(temp);
queue.size=queue.size+1;
free(temp);
printf("Back a:%s\n",queue.back->data);
return;
}
// Add the new node at the end of queue
queue.back->next = copy(temp);
queue.back = temp;
printf("Back2:%s\n",queue.back->data);
if (data != NULL){
queue.size=queue.size+1;
}
//free(temp);
}
void que_dequeue(queue_t queue)
{
if (queue.size == 0)
{
printf("Deq on an empty q");
return; //break here
}
else if (queue.size == 1)
{
//only 1 element
queue.front = NULL;
queue.back = NULL;
}
else
{
node* temp = newNode(NULL);
temp=queue.front->next;
queue.front = copy(temp);
free(temp);
}
queue.size=queue.size-1;
}
const void *que_front(const queue_t queue)
{
//return queue.front->data;
return queue.front;
}
size_t que_size(queue_t queue)
{
return (size_t)queue.size;
}
int main(void){
queue_t q=que_create();
que_enqueue(q,"a34");
que_enqueue(q,"bg");
node* f=(node *)que_front(q);
printf("Print %s\n",f->data);
printf("Print %d\n",q.size);
return 0;
}
The question was answered in the comments by #Paul Ogilvie. C is not "pass by value", so the code will edit a copy of the queue not the actual thing. This is fixed by passing a pointer that will change the value at the address

How to implement a queue in a linked list in c?

I am given these structure declarations in order to implement a queue collection that uses a circular linked list.
typedef struct intnode {
int value;
struct intnode *next;
} intnode_t;
typedef struct {
intnode_t *rear; // Points to the node at the tail of the
// queue's linked list
int size; // The # of nodes in the queue's linked list
} intqueue_t;
intnode_t *intnode_construct(int value, intnode_t *next)
{
intnode_t *p = malloc(sizeof(intnode_t));
assert (p != NULL);
p->value = value;
p->next = next;
return p;
}
/* Return a pointer to a new, empty queue.
* Terminate (via assert) if memory for the queue cannot be allocated.
*/
intqueue_t *intqueue_construct(void)
{
intqueue_t *queue = malloc(sizeof(intqueue_t));
assert(queue != NULL);
queue->rear = NULL;
queue->size = 0;
return queue;
}
I'm trying to create a function that will enqueue at a specified value (append it to the rear of the queue), and I need to consider the two cases in which the queue is empty and when the queue has one or more elements. This is the code I have so far:
void intqueue_enqueue(intqueue_t *queue, int value)
{
intnode_t *p = intnode_construct(value, NULL);
if(queue->rear->next == NULL) {
//the queue is empty
queue->rear->next =p;
} else {
//the queue is not empty
queue->rear=p;
}
queue->rear=p;
queue->size++;
}
This code gives me a runtime error so I'm not sure whats wrong. In the code, I'm assuming queue->rear->next is the front, however I think this is where the problem might be. All help is greatly appreciated. Thanks!
UPDATE--
I've tried to rework the code and got this:
void intqueue_enqueue(intqueue_t *queue, int value)
{
assert(queue!=NULL);
intnode_t *p = intnode_construct(value,NULL);
if (queue->size==0){
queue->rear=p;
queue->size++;
queue->rear->next=p;
free(p);
}
else {
p->next = queue->rear;
queue->rear=p;
queue->size++;
free(p);
}
}
This works only when it is empty but not when it is not empty.
Circular Queue in Linked List
Your code is too large to read out, So here what I use to implement Circular Queue:
#include
using namespace std;
// Structure of a Node
struct Node
{
int data;
struct Node* link;
};
struct Queue
{
struct Node *front, *rear;
};
// Function to create Circular queue
void enQueue(Queue *q, int value)
{
struct Node *temp = new Node;
temp->data = value;
if (q->front == NULL)
q->front = temp;
else
q->rear->link = temp;
q->rear = temp;
q->rear->link = q->front;
}
// Function to delete element from Circular Queue
int deQueue(Queue *q)
{
if (q->front == NULL)
{
printf ("Queue is empty");
return INT_MIN;
}
// If this is the last node to be deleted
int value; // Value to be dequeued
if (q->front == q->rear)
{
value = q->front->data;
free(q->front);
q->front = NULL;
q->rear = NULL;
}
else // There are more than one nodes
{
struct Node *temp = q->front;
value = temp->data;
q->front = q->front->link;
q->rear->link= q->front;
free(temp);
}
return value ;
}
// Function displaying the elements of Circular Queue
void displayQueue(struct Queue *q)
{
struct Node *temp = q->front;
printf("\nElements in Circular Queue are: ");
while (temp->link != q->front)
{
printf("%d ", temp->data);
temp = temp->link;
}
printf("%d", temp->data);
}
/* Driver of the program */
int main()
{
// Create a queue and initialize front and rear
Queue *q = new Queue;
q->front = q->rear = NULL;
// Inserting elements in Circular Queue
enQueue(q, 14);
enQueue(q, 22);
enQueue(q, 6);
// Display elements present in Circular Queue
displayQueue(q);
// Deleting elements from Circular Queue
printf("\nDeleted value = %d", deQueue(q));
printf("\nDeleted value = %d", deQueue(q));
// Remaining elements in Circular Queue
displayQueue(q);
enQueue(q, 9);
enQueue(q, 20);
displayQueue(q);
return 0;
}

Binary Tree implementation on C

I am trying to implement tree in C but the thing is whenever i try to traverse it, it only shows the first three nodes of the tree and the rest are lost. like, if i enter 100, 200, 300, 400, 500, 600, 700 then only 100 ,200, 300 will be in the output. I think the problem is with insert function but i just can't figure it out.
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *prev;
struct node *next;
};
typedef struct node list;
list *head, *tail, *current, *newn;
void inorder(struct node *t)
{
if(t != NULL)
{
inorder(t->prev);
printf("%d->",t->data);
inorder(t->next);
}
}
struct node * insert(int key, struct node *t)
{
if(t == NULL)
{
t = (list*)malloc(sizeof(list));
t->data = key;
t->prev = NULL;
t->next = NULL;
}
else if(t->prev == NULL)
{
t->prev = insert(key,t->prev);
}
else if(t->next == NULL)
{
t->next = insert(key,t->next);
}
return(t);
}
int main()
{
int x=1, y, z=1;
current = (list*)malloc(sizeof(list));
printf("Enter data:");
scanf("%d",&current->data);
current->next = NULL;
current->prev = NULL;
head = current;
while(z == 1)
{
printf("Enter data:");
scanf("%d",&y);
current = insert(y,current);
printf("want to insert more:");
scanf("%d",&z);
}
printf("\nInorder Traversal:");
newn = head;
inorder(newn);
}
only 100 ,200, 300 will be in the output.
at Insert function
if(t == NULL)
{
...
}
else if(t->prev == NULL)
{
...
}
else if(t->next == NULL)
{
...
}
return(t);
Because it is
When t, t->prev and t->next are not all NULL
Nothing (that is, inserting) is done.
When adding conditions and recursive calls like
else if(t->prev->prev == NULL)
{
t->prev->prev = insert(key, t->prev->prev);
}
Insertion of the node is done, but since growth becomes like depth-first search, the growth of the tree becomes biased.
So, as an approach you need to search for the next insertion point like breadth first search.
I think there are some methods,
As a method I propose, it is a way to keep it as a pool when creating a NULL node rather than searching.
A concrete implementation using a queue as a node pool is as follows(Please note that many checks are omitted And using global variables).
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node *prev;
struct node *next;
};
typedef struct node list;
void inorder(struct node *t){
if(t != NULL){
inorder(t->prev);
printf("%d->",t->data);
inorder(t->next);
}
}
//node of queue
typedef struct null_node {
list **nodepp;
struct null_node *next;
} node_pool;
//queue
typedef struct queue {
node_pool *head;
node_pool *tail;
} queue;
//enqueue
void push(queue *q, list **nodepp){
node_pool *np = malloc(sizeof(*np));
np->nodepp = nodepp;
np->next = NULL;
if(q->head == NULL){
q->tail = q->head = np;
} else {
q->tail = q->tail->next = np;
}
}
//dequeue
list **pop(queue *q){
node_pool *head = q->head;
if(head == NULL)
return NULL;
q->head = q->head->next;
if(q->head == NULL)
q->tail = NULL;
list **nodepp = head->nodepp;
free(head);
return nodepp;
}
void clear_queue(queue *q){
while(pop(q));
}
list *Head;
queue Q;
struct node *insert(int key, struct node *root){
list *t = malloc(sizeof(*t));
t->data = key;
t->next = t->prev = NULL;
push(&Q, &t->prev);//enqueue a NULL node
push(&Q, &t->next);
if(root == NULL){
return t;
}
list **null_nodep = pop(&Q);//dequeue the node
*null_nodep = t;//Replace with new node
return root;
}
int main(void){
int /*x=1, unused x*/ y, z=1;
Head = NULL;
while(z == 1){
printf("Enter data:");
scanf("%d",&y);
Head = insert(y, Head);
printf("want to insert more:");
scanf("%d",&z);
}
printf("\nInorder Traversal:");
inorder(Head);
clear_queue(&Q);//Discard queued nodes
}

Creating a queue from a LinkedList in C

currently I'm writing a code which requires me to "copy" a series of integers(user input) from a linkedlist and place them into a queue.
I understand that I require a function called enqueue to proceed, however, I was taught that by simply using the insertNode() function, I can create a basic enqueue function. e.g
void enqueue(Queue *q, int item)
{
insertNode(&(q->ll),q->ll.size, item);
removeNode(ll,0);
}
Given insertNode() :
int insertNode(LinkedList *ll, int index, int value)
{
ListNode *pre, *cur;
if (ll == NULL || index < 0 || index > ll->size + 1)
return -1;
if (ll->head == NULL || index == 0) {
cur = ll->head;
ll->head = malloc(sizeof(ListNode));
ll->head->item = value;
ll->head->next = cur;
ll->size++;
return 0;
}
if ((pre = findNode(ll, index - 1)) != NULL) {
cur = pre->next;
pre->next = malloc(sizeof(ListNode));
pre->next->item = value;
pre->next->next = cur;
ll->size++;
return 0;
}
return -1;
}
and then finally by using another function to make use of the enqueue()
void createQueueFromLinkedList(LinkedList *ll, Queue * q)
{
if (isEmptyQueue) {
removeAllItemsFromQueue(q);
}// empty the queue if it is not empty
while (ll->size)
{
enqueue(q, ll->head->item);
//code to remove ll->size by 1 each time
}
}
int isEmptyQueue(Queue *q)
{
if ((q->ll).size == 0){
return 0;
}
return 1;
}
The problem which I'm facing is that I am not sure whether is my enqueue() working correctly or if there is a better way of going about doing it?
Thanks in advance.
definition of Queue, Linkedlist and ListNode; Suppose I'm not allow to change them :
typedef struct _listnode
{
int item;
struct _listnode *next;
} ListNode;
typedef struct _linkedlist
{
int size;
ListNode *head;
} LinkedList;
typedef struct _queue
{
LinkedList ll;
} Queue;

Resources