C语言判断队列满or空

文章介绍了两种队列实现方式:静态数组循环队列和动态数组队列。静态数组循环队列利用front和rear指针判断队列状态,动态数组队列在需要时动态调整数组大小。动态数组队列在频繁添加和删除元素时更高效,而链式队列适合于需要快速访问任意位置的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 静态数组队列

循环队列通常使用数组来实现,判别循环队列是否满或空,可以借助两个变量front和rear。

  1. 判空:当front和rear相等时,队列为空。

  2. 判满:当(front + 1) % n = rear时,队列为满,其中n为循环队列的长度。需要注意的是,为了区分队列满和队列空的情况,队列中必须要有一个空间不存储元素。

下面是一个简单的循环队列的实现示例:

#define MAXSIZE 10 // 定义循环队列的最大容量

typedef struct {
    int data[MAXSIZE]; // 存储队列元素
    int front; // 队头指针
    int rear; // 队尾指针
} CircularQueue;

// 初始化循环队列
void initCircularQueue(CircularQueue *q) {
    q->front = q->rear = 0;
}

// 判断循环队列是否为空
bool isEmpty(CircularQueue *q) {
    return q->front == q->rear;
}

// 判断循环队列是否已满
bool isFull(CircularQueue *q) {
    return (q->rear + 1) % MAXSIZE == q->front;
}

在实现过程中,需要留出一位空间来区分队列为满和队列为空的情况。这里我们设置循环队列的最大容量为MAXSIZE,因此循环队列的存储空间实际上是MAXSIZE-1。当队尾指针rear指向数组最后一个位置时,如果再插入一个元素就会导致rear指向第一个位置,此时队列为满;而当队头指针front和队尾指针rear相同时,队列为空。

2 动态数组队列

动态数组队列是一种数据结构,在队列的基础上,使用动态数组来实现队列的操作。它允许在队列中添加和删除元素,具有先进先出(FIFO)的特点。

在动态数组队列中,元素存储在数组中,并通过一个指针来跟踪队列的头部和尾部。当队列长度增长时,内部数组也随之扩容。相反,当队列长度减小,内部数组也会缩小以减少内存占用。

动态数组队列的时间复杂度如下:

  • 入队:O(1) 或 O(n)(需要扩容)
  • 出队:O(1)
  • 获取队列大小:O(1)

需要注意的是,当需要频繁添加和删除元素时,使用动态数组队列比静态数组队列更加高效。但对于需要快速访问队列任意位置的应用,链表队列可能更适合。

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

// 定义队列结构体
typedef struct queue {
    int *data;      // 存储队列元素的数组指针
    int front;      // 队头下标
    int rear;       // 队尾下标
    int size;       // 队列大小
    int capacity;   // 队列容量
} Queue;

// 初始化队列
void initQueue(Queue *queue, int capacity) {
    // 申请存储队列元素的数组空间
    queue->data = (int*) malloc(sizeof(int) * capacity);
    if (!queue->data) {
        printf("Memory allocation failed.\n");
        exit(1);
    }

    // 初始化队列参数
    queue->front = 0;
    queue->rear = -1;
    queue->size = 0;
    queue->capacity = capacity;
}

// 判断队列是否为空
int isEmpty(Queue *queue) {
    return queue->size == 0;
}

// 判断队列是否已满
int isFull(Queue *queue) {
    return queue->size == queue->capacity;
}

// 入队
void enqueue(Queue *queue, int element) {
    if (isFull(queue)) {
        printf("Queue is full.\n");
        return;
    }

    // 计算新的队尾下标
    int newRear = (queue->rear + 1) % queue->capacity;
    queue->data[newRear] = element;
    queue->rear = newRear;
    queue->size++;
}

// 出队
int dequeue(Queue *queue) {
    if (isEmpty(queue)) {
        printf("Queue is empty.\n");
        return -1;
    }

    int element = queue->data[queue->front];
    queue->front = (queue->front + 1) % queue->capacity;
    queue->size--;
    return element;
}

// 打印队列元素
void printQueue(Queue *queue) {
    if (isEmpty(queue)) {
        printf("Queue is empty.\n");
        return;
    }

    printf("Queue elements: ");
    for (int i = 0; i < queue->size; i++) {
        int index = (queue->front + i) % queue->capacity;
        printf("%d ", queue->data[index]);
    }
    printf("\n");
}

// 销毁队列
void destroyQueue(Queue *queue) {
    free(queue->data);
}

int main() {
    Queue queue;
    initQueue(&queue, 5);

    // 入队
    enqueue(&queue, 1);
    enqueue(&queue, 2);
    enqueue(&queue, 3);
    enqueue(&queue, 4);
    enqueue(&queue, 5);
    printQueue(&queue);     // 队列元素: 1 2 3 4 5

    // 出队
    dequeue(&queue);
    dequeue(&queue);
    printQueue(&queue);     // 队列元素: 3 4 5

    // 入队
    enqueue(&queue, 6);
    enqueue(&queue, 7);
    printQueue(&queue);     // 队列元素: 3 4 5 6 7

    destroyQueue(&queue);
    return 0;
}

链式队列

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

// 定义队列结构体
typedef struct node {
    int data; // 数据域
    struct node *next; // 指针域,指向下一个节点
} Node;

// 定义队列结构体,包含头节点和尾节点
typedef struct queue {
    Node *front; // 头节点
    Node *rear; // 尾节点
} Queue;

// 初始化队列
Queue *init() {
    Queue *q = (Queue*)malloc(sizeof(Queue)); // 创建队列内存空间
    Node *p = (Node*)malloc(sizeof(Node)); // 创建头节点内存空间
    p->next = NULL;
    q->front = p; // 队列的头指针指向头节点
    q->rear = p; // 队列的尾指针也指向头节点
    return q;
}

// 入队操作
void enqueue(Queue *q, int data) {
    Node *p = (Node*)malloc(sizeof(Node)); // 创建新节点内存空间
    p->data = data;
    p->next = NULL;
    q->rear->next = p; // 将新节点接到队列尾部
    q->rear = p; // 更新队列尾指针
}

// 出队操作
int dequeue(Queue *q) {
    if (q->front == q->rear) { // 队列为空
        printf("queue is empty\n");
        return -1;
    }
    Node *p = q->front->next;
    int data = p->data;
    q->front->next = p->next; // 将头节点指向下一个节点,相当于删除了队列中的第一个节点
    if (q->rear == p) { // 如果队列中只有一个元素,出队后需要更新尾节点指针
        q->rear = q->front;
    }
    free(p); // 释放被删除节点内存空间
    return data;
}

// 获取队列长度
int length(Queue *q) {
    int len = 0;
    Node *p = q->front->next;
    while (p != NULL) {
        len++;
        p = p->next;
    }
    return len;
}

// 打印队列
void print(Queue *q) {
    Node *p = q->front->next;
    printf("queue: ");
    while (p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

int main() {
    Queue *q = init(); // 初始化队列
    enqueue(q, 1); // 入队操作
    enqueue(q, 2);
    enqueue(q, 3);
    print(q); // 打印队列
    dequeue(q); // 出队操作
    print(q); // 打印队列
    printf("queue length: %d\n", length(q)); // 获取队列长度
    return 0;
}

循环队列的队条件是指,在循环队列中,已存储的元素数量(由`length`表示)加上当前位置`rear`等于数组的容量减去1。这是因为当我们尝试向队尾添加新的元素时,如果队尾已经指向数组的第一个位置,而下一个位置刚好是最后一个位置(即`rear + 1 == (rear + length) % queue_size`),那么队列就已经了,不能再插入更多的元素。 以下是循环队列的入队(enqueue)和出队(dequeue)算法的C语言实现: ```c // 定义循环队列的结构体 typedef struct { int *data; // 存储元素的数组 int rear; // 队尾指针 int front; // 队头指针,初始值为-1,表示队列 int capacity; // 队列容量 } CQueue; // 入队操作:判断并处理 void enqueue(CQueue* q, int value) { if (q->front == -1) { // 初始队 q->front = 0; } if ((q->rear + 1) % q->capacity == q->front) { // 队 printf("Error: Queue is full.\n"); return; } q->rear = (q->rear + 1) % q->capacity; // 把新元素放在队尾 q->data[q->rear] = value; } // 出队操作:返回队头元素并更新队首位置,处理队列 int dequeue(CQueue* q) { if (q->front == -1 || q->front == q->rear) { // 队列或只有一个元素 printf("Error: Queue is empty or has only one element.\n"); return -1; // 或者抛出异常 } int value = q->data[q->front]; // 返回队头元素 q->front = (q->front + 1) % q->capacity; // 更新队首 return value; } ``` 在这个实现中,队列满队列的检查都是在入队和出队操作前进行的,这样可以简化算法,并确保数据结构的一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值