0

I'm studying about circular queue in data structure . As you can see from the code below, I try to delete a specific data and insert data on Circular queue. However, when I try to run it there's a problem when deleting data and insert a new one. I had no clue about it. I was trying to solve this for many hours but I can't find anything. Any help would be appreciated.

#include <stdio.h>
#define SIZE 3

typedef struct queue{
    int val[SIZE]={NULL};
    int front;
    int rear;
}queue;
void display(struct queue *q);
void enqueue(struct queue *q){
    int ins,i=1;
    if((q->rear == SIZE-1 && q->front == 0) || (q->rear == q->front-1)){
        printf("Queue is full!\n");
    }
    else if (q->front == -1)
    { 
        printf("Enqueue data : ");
        scanf("%d",&ins);
        q->front = q->rear = 0; 
        q->val[q->rear] = ins; 
    }
    else if (q->rear == SIZE-1) 
    { 
        printf("Enqueue data : ");
        scanf("%d",&ins);
        q->rear = 0; 
        q->val[q->rear] = ins; 
    }   
    else
    {   
        printf("Enqueue data : ");
        scanf("%d",&ins);
        q->rear++; 
        q->val[q->rear] = ins; 
    } 
    display(q);
};

void dequeue(struct queue *q);
int main(){
    queue *q= new queue;
    q->front = -1;
    q->rear = -1;
    char select;
flag1:
    printf("\n------- Please Select Operations ---------\n");
    printf("Press e: Enqueue\n"); 
    printf("Press d: Dequeue\n");   
    printf("Press x: Exit Program\n");                   
    printf("------------------------------------------\n");
    printf("Select Menu : ");
    scanf(" %c",&select);
    switch(select){
        case 'e' : enqueue(q); goto flag1;
        case 'd' : dequeue(q); goto flag1;
        case 'x' : break;
    }
    
 return 0;  
}

void dequeue(struct queue *q){
    int deq,hold;
    if (q->front == -1) 
    { 
        printf("Queue is Empty"); 
    } 
    else
    {
     printf("Dequeue data : ");
     scanf("%d",&deq);
     for(int i=0;i<SIZE;i++){
        if(deq==q->val[i]){
           if(i==q->front){
            q->val[q->front]=NULL;
            q->front = i;
            q->rear=q->rear+1;
            if(q->rear=SIZE-1){
                q->rear=0;
               }
           }
           else
            q->val[q->front]=NULL;
        }   
    }
    display(q);
}
};

void display(struct queue *q){
    int i;
    printf("Queue : |");
    for (i= 0; i<SIZE; i++){
        if(q->val[i]==NULL){
        printf(" |");   
        }
        else
        printf("%d|", q->val[i]);
    }
};
Welbog
  • 59,154
  • 9
  • 110
  • 123
Max P Apth
  • 15
  • 1
  • 7
  • *" I was trying to solve this for many hours but I can't find anything."* - so single-stepping through this with a debugger and taking note at the specific values of the front and rear indexes whilst doing so gave you *nothing* ? – WhozCraig Dec 14 '20 at 19:27
  • Your question is tagged `c` and your code is 99.44% `c`. But, you do `new queue` which is `c++`. If you changed that to: `queue *q = malloc(sizeof(*q));` it would be 100% `c` – Craig Estey Dec 14 '20 at 19:36
  • You have `int val[SIZE] = { NULL };` This would be `c++` if you used `0` [vs. `NULL`]. So, do you want `val` to be `int` or `int *`? In `dequeue`, you do: `q->val[q->front] = NULL;`, so this implies `val` is `int *`. But, in `enqueue`, you do: `q->val[q->rear] = ins;` where `ins` is an `int`. So, this is a conflict where [in the `queue` struct] `val` has to be _both_ an `int` and an `int *` I presume that you want `int val[SIZE];` but when you delete, what value do you want for the _sentinel_ that indicates an "empty" cell? – Craig Estey Dec 14 '20 at 19:50
  • 1
    Generally the point of circular queues is to operate solely on the front and rear (rear for inserts, front for removals). Your removal function is a remove-by-value rather than just removing the front value. It appears to have a lot of issues: 1) random access instead of accessing just the front, 2) assuming that the only time the queue is empty is when `front == -1` (which is never true after the first insert), 3) checking if `i == q->front` then setting `q->front = i`, 4) updating `q->rear` during the dequeue instead of incrementing `q->front`, 5) setting `q->rear=SIZE-1` in an if condition. – Welbog Dec 14 '20 at 20:18
  • There are more problems as well, but I ran out of characters. I would suggest, in addition to the points Craig has made, revising your understanding of queues and how their operations conventionally work. If you want random access, just use an array. If you want a queue, dequeue should work only on the front address, not implement a search by value. – Welbog Dec 14 '20 at 20:19
  • @Welbog I'm glad you mentioned these things. I wasn't sure if "circular queue" meant "ring queue". That is, empty is `q->front == q->rear` [with the indexes wrapping at `SIZE`]. To me, "circular" means a doubly linked list, where `tail->next == head` and `head->prev == tail` instead of `NULL` – Craig Estey Dec 14 '20 at 20:24
  • @CraigEstey, could be that too. From the implementation of enqueue it looks like a ring queue to me. – Welbog Dec 14 '20 at 20:27
  • @CraigEstey Thank you for the comments. About int val[SIZE] = {NULL} I want int to be an int not int* so I wonder if it’s okay to change from {NULL} to 0 and change the condition in dequeue as well. – Max P Apth Dec 14 '20 at 21:07

3 Answers3

2

GIGO!
Your code is overly complex.
Complex code requires complex testing and debugging.

Try the following code:

void enqueue( struct queue *q, int v) {
    int r = (q.rear + 1) % SIZE
    if(( r == q.front) {
        printf( "Queue is full!\n");
    } else {
        q.val[ q.rear] = v;
        q.rear = r;
    }
};

int dequeue( struct queue *q) {
    if( q.front == q.rear) {
        printf( "Queue is Empty");
        v = NULL; # or whatever (required as a return value)
    } else {
        v = q.val[ q.front];
        q.front = ( q.front + 1) % SIZE;
    }
    return v;
};

int main() {
    queue *q = new queue;
    q->front = q->rear = 0;
    ...
};

To summarize:

  • rear is index of the youngest element
  • front is the index of the oldest element
  • % (the modulus operator) take care of the index overwrapping.
  • (front == rear) means empty buffer
  • ((rear +1) % SIZE == front) means full buffer.

Please note that this simple algorithm always leave an unused element in the buffer. This is required to distinguish "full" from "empty".

user3435121
  • 633
  • 4
  • 13
  • @"Max P Apth" I don't know what compiler you use. But I assume it is C++ with some C compatibility. This program is not tested but it should work. – user3435121 Dec 14 '20 at 22:06
0

Circular Queue in Java

public class CircularQueue<T> {

    private Object[] arr;
    private int front = -1, rear = -1;

    public CircularQueue(int initialCapacity) {
        this.arr = new Object[initialCapacity];
    }

    public void add(T val) throws Exception {
        if (isEmpty()) {
            rear++;
            front++;
        } else if (isFull()) {
            throw new Exception("Queue is full");
        }
        arr[rear] = val;
        rear = (rear + 1) % arr.length;
    }

    public T delete() throws Exception {
        if (isEmpty()) {
            throw new Exception("No elements in Queue");
        }
        T temp = (T) arr[front];
        front = (front + 1) % arr.length;
        return temp;
    }

    public boolean isEmpty() {
        return (front == -1 && rear == -1);
    }

    public boolean isFull() {
        return (front == rear);
    }

    @Override
    public String toString() {
        String ret = "[ ";
        int temp = front;
        do {
            ret += arr[temp] + " ";
            temp = (temp + 1) % arr.length;
        } while (temp != rear);
        ret += "]";
        return ret;
    }

}

-1

Your code is overly and dumbly complex. I think you don't understand circular-queues well.

Here's my simplified code. You can check it out and learn something.

#include<stdio.h>
#include<stdlib.h>

typedef struct _node {
    int size,front,rear,*q;
} node;

node *pu;

void initialize() {
    if(pu!=NULL)
        free(pu);
    pu = (node *)malloc(sizeof(node));
    printf("\nEnter the size of the queue :- ");
    scanf(" %d",&pu->size);
    pu->q = (int *)malloc(sizeof(int) * pu->size +1);
    pu->front = pu->rear = 0;
}

int isempty() {
    return (pu->front == pu->rear);
}

int isfull() {
    return ((pu->rear + 1) % pu->size == pu->front);
}

void enqueue(int x) {
    if(isfull())
        return;
    else {
        pu->q[pu->rear=(pu->rear +1) % pu->size] = x;
    }
}

int dequeue() {
    if(isempty())
        return '$';
    else {
        return pu->q[ pu->front = (pu->front + 1) % pu->size];
    }
}

void display() {
    if(isempty())
        return;
    else {
        for( int i = pu->front + 1; i != (pu->rear +1)%pu->size ; i = ( i +1) % pu->size)
            printf("\n %d",pu->q[i]);
    }
}

int main() {
    // do something in here with the functions.
    return 0;
}
  • -1: This code is correct but very opaque. It's unlikely anyone new to C or circular buffers could make much sense of this. The preamble is unnecessarily rude. – Welbog Dec 15 '20 at 00:07
  • @Welbog its actually a beginners' code. my professor gave me to write it with minimum characters so i wrote this. – the trickster Dec 15 '20 at 11:32