数据结构-C语言版本(四)队列

数据结构中的队列:概念、操作与实战

第一部分 队列分类及常见形式

队列是一种遵循先进先出(FIFO, First In First Out)原则的线性数据结构。队列主要有以下几种实现形式:

1. 数组实现的队列(顺序队列)

c 复制代码
#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int front;  // 队头指针
    int rear;   // 队尾指针
} ArrayQueue;

2. 链表实现的队列(链式队列)

c 复制代码
typedef struct QueueNode {
    int data;
    struct QueueNode* next;
} QueueNode;

typedef struct {
    QueueNode* front;
    QueueNode* rear;
} LinkedQueue;

3. 循环队列

解决顺序队列"假溢出"问题的实现方式

c 复制代码
typedef struct {
    int data[MAX_SIZE];
    int front;
    int rear;
} CircularQueue;

4. 双端队列

可以在两端进行插入和删除操作的队列

c 复制代码
typedef struct {
    int data[MAX_SIZE];
    int front;
    int rear;
} Deque;

5. 优先队列

元素带有优先级,出队按优先级顺序

c 复制代码
typedef struct {
    int data[MAX_SIZE];
    int size;
} PriorityQueue;

第二部分 队列常见操作

1. 初始化队列

c 复制代码
// 初始化顺序队列
void initArrayQueue(ArrayQueue *queue) {
    queue->front = 0;
    queue->rear = 0;
}

// 初始化链式队列
void initLinkedQueue(LinkedQueue *queue) {
    queue->front = NULL;
    queue->rear = NULL;
}

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

2. 入队操作

c 复制代码
// 顺序队列入队
void enArrayQueue(ArrayQueue *queue, int value) {
    if(queue->rear >= MAX_SIZE) {
        printf("队列已满\n");
        return;
    }
    queue->data[queue->rear++] = value;
}

// 链式队列入队
void enLinkedQueue(LinkedQueue *queue, int value) {
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    newNode->data = value;
    newNode->next = NULL;
    
    if(queue->rear == NULL) {
        queue->front = queue->rear = newNode;
    } else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
}

// 循环队列入队
void enCircularQueue(CircularQueue *queue, int value) {
    if((queue->rear + 1) % MAX_SIZE == queue->front) {
        printf("队列已满\n");
        return;
    }
    queue->data[queue->rear] = value;
    queue->rear = (queue->rear + 1) % MAX_SIZE;
}

3. 出队操作

c 复制代码
// 顺序队列出队
int deArrayQueue(ArrayQueue *queue) {
    if(queue->front == queue->rear) {
        printf("队列为空\n");
        return -1;
    }
    return queue->data[queue->front++];
}

// 链式队列出队
int deLinkedQueue(LinkedQueue *queue) {
    if(queue->front == NULL) {
        printf("队列为空\n");
        return -1;
    }
    QueueNode* temp = queue->front;
    int value = temp->data;
    queue->front = queue->front->next;
    
    if(queue->front == NULL) {
        queue->rear = NULL;
    }
    
    free(temp);
    return value;
}

// 循环队列出队
int deCircularQueue(CircularQueue *queue) {
    if(queue->front == queue->rear) {
        printf("队列为空\n");
        return -1;
    }
    int value = queue->data[queue->front];
    queue->front = (queue->front + 1) % MAX_SIZE;
    return value;
}

4. 查看队头元素

c 复制代码
// 查看顺序队列队头
int frontArrayQueue(ArrayQueue *queue) {
    if(queue->front == queue->rear) {
        printf("队列为空\n");
        return -1;
    }
    return queue->data[queue->front];
}

// 查看链式队列队头
int frontLinkedQueue(LinkedQueue *queue) {
    if(queue->front == NULL) {
        printf("队列为空\n");
        return -1;
    }
    return queue->front->data;
}

5. 判断队列是否为空

c 复制代码
// 判断顺序队列是否为空
int isEmptyArrayQueue(ArrayQueue *queue) {
    return queue->front == queue->rear;
}

// 判断链式队列是否为空
int isEmptyLinkedQueue(LinkedQueue *queue) {
    return queue->front == NULL;
}

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

6. 判断队列是否已满

c 复制代码
// 判断顺序队列是否已满
int isFullArrayQueue(ArrayQueue *queue) {
    return queue->rear == MAX_SIZE;
}

// 判断循环队列是否已满
int isFullCircularQueue(CircularQueue *queue) {
    return (queue->rear + 1) % MAX_SIZE == queue->front;
}

第三部分 队列编程题例子

1. 用队列实现栈

c 复制代码
typedef struct {
    ArrayQueue q1;
    ArrayQueue q2;
} MyStack;

MyStack* myStackCreate() {
    MyStack* stack = (MyStack*)malloc(sizeof(MyStack));
    initArrayQueue(&stack->q1);
    initArrayQueue(&stack->q2);
    return stack;
}

void myStackPush(MyStack* obj, int x) {
    enArrayQueue(&obj->q1, x);
    // 将q2中的元素全部转移到q1
    while(!isEmptyArrayQueue(&obj->q2)) {
        enArrayQueue(&obj->q1, deArrayQueue(&obj->q2));
    }
    // 交换q1和q2
    ArrayQueue temp = obj->q1;
    obj->q1 = obj->q2;
    obj->q2 = temp;
}

int myStackPop(MyStack* obj) {
    return deArrayQueue(&obj->q2);
}

int myStackTop(MyStack* obj) {
    return frontArrayQueue(&obj->q2);
}

int myStackEmpty(MyStack* obj) {
    return isEmptyArrayQueue(&obj->q2);
}

2. 用栈实现队列

c 复制代码
typedef struct {
    ArrayStack s1;  // 用于入队
    ArrayStack s2;  // 用于出队
} MyQueue;

MyQueue* myQueueCreate() {
    MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
    initArrayStack(&queue->s1);
    initArrayStack(&queue->s2);
    return queue;
}

void myQueuePush(MyQueue* obj, int x) {
    pushArrayStack(&obj->s1, x);
}

int myQueuePop(MyQueue* obj) {
    if(isEmptyArrayStack(&obj->s2)) {
        while(!isEmptyArrayStack(&obj->s1)) {
            pushArrayStack(&obj->s2, popArrayStack(&obj->s1));
        }
    }
    return popArrayStack(&obj->s2);
}

int myQueuePeek(MyQueue* obj) {
    if(isEmptyArrayStack(&obj->s2)) {
        while(!isEmptyArrayStack(&obj->s1)) {
            pushArrayStack(&obj->s2, popArrayStack(&obj->s1));
        }
    }
    return peekArrayStack(&obj->s2);
}

int myQueueEmpty(MyQueue* obj) {
    return isEmptyArrayStack(&obj->s1) && isEmptyArrayStack(&obj->s2);
}

3. 滑动窗口最大值

c 复制代码
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    if(numsSize == 0) {
        *returnSize = 0;
        return NULL;
    }
    
    *returnSize = numsSize - k + 1;
    int* result = (int*)malloc(*returnSize * sizeof(int));
    int deque[numsSize];
    int front = 0, rear = 0;
    
    for(int i = 0; i < numsSize; i++) {
        // 移除不在窗口内的元素
        while(front < rear && deque[front] < i - k + 1) {
            front++;
        }
        
        // 移除小于当前元素的元素
        while(front < rear && nums[deque[rear-1]] < nums[i]) {
            rear--;
        }
        
        // 添加当前元素
        deque[rear++] = i;
        
        // 窗口形成后记录最大值
        if(i >= k - 1) {
            result[i - k + 1] = nums[deque[front]];
        }
    }
    
    return result;
}

4. 设计循环双端队列

c 复制代码
typedef struct {
    int *data;
    int front;
    int rear;
    int capacity;
} MyCircularDeque;

MyCircularDeque* myCircularDequeCreate(int k) {
    MyCircularDeque* deque = (MyCircularDeque*)malloc(sizeof(MyCircularDeque));
    deque->data = (int*)malloc((k + 1) * sizeof(int));  // 多留一个空间判断满
    deque->front = 0;
    deque->rear = 0;
    deque->capacity = k + 1;
    return deque;
}

int myCircularDequeInsertFront(MyCircularDeque* obj, int value) {
    if((obj->rear + 1) % obj->capacity == obj->front) {
        return 0;
    }
    obj->front = (obj->front - 1 + obj->capacity) % obj->capacity;
    obj->data[obj->front] = value;
    return 1;
}

int myCircularDequeInsertLast(MyCircularDeque* obj, int value) {
    if((obj->rear + 1) % obj->capacity == obj->front) {
        return 0;
    }
    obj->data[obj->rear] = value;
    obj->rear = (obj->rear + 1) % obj->capacity;
    return 1;
}

int myCircularDequeDeleteFront(MyCircularDeque* obj) {
    if(obj->front == obj->rear) {
        return 0;
    }
    obj->front = (obj->front + 1) % obj->capacity;
    return 1;
}

int myCircularDequeDeleteLast(MyCircularDeque* obj) {
    if(obj->front == obj->rear) {
        return 0;
    }
    obj->rear = (obj->rear - 1 + obj->capacity) % obj->capacity;
    return 1;
}

int myCircularDequeGetFront(MyCircularDeque* obj) {
    if(obj->front == obj->rear) {
        return -1;
    }
    return obj->data[obj->front];
}

int myCircularDequeGetRear(MyCircularDeque* obj) {
    if(obj->front == obj->rear) {
        return -1;
    }
    return obj->data[(obj->rear - 1 + obj->capacity) % obj->capacity];
}

int myCircularDequeIsEmpty(MyCircularDeque* obj) {
    return obj->front == obj->rear;
}

int myCircularDequeIsFull(MyCircularDeque* obj) {
    return (obj->rear + 1) % obj->capacity == obj->front;
}

5. 最近的请求次数(RecentCounter)

c 复制代码
typedef struct {
    int *requests;
    int front;
    int rear;
    int capacity;
} RecentCounter;

RecentCounter* recentCounterCreate() {
    RecentCounter* counter = (RecentCounter*)malloc(sizeof(RecentCounter));
    counter->requests = (int*)malloc(10000 * sizeof(int));
    counter->front = 0;
    counter->rear = 0;
    counter->capacity = 10000;
    return counter;
}

int recentCounterPing(RecentCounter* obj, int t) {
    obj->requests[obj->rear++] = t;
    while(obj->requests[obj->front] < t - 3000) {
        obj->front++;
    }
    return obj->rear - obj->front;
}

void recentCounterFree(RecentCounter* obj) {
    free(obj->requests);
    free(obj);
}

6. 任务调度器

c 复制代码
int leastInterval(char* tasks, int tasksSize, int n) {
    int count[26] = {0};
    for(int i = 0; i < tasksSize; i++) {
        count[tasks[i] - 'A']++;
    }
    
    // 找出最大出现次数
    int maxCount = 0;
    for(int i = 0; i < 26; i++) {
        if(count[i] > maxCount) {
            maxCount = count[i];
        }
    }
    
    // 计算有多少个任务具有最大出现次数
    int maxTasks = 0;
    for(int i = 0; i < 26; i++) {
        if(count[i] == maxCount) {
            maxTasks++;
        }
    }
    
    // 计算最小时间
    int result = (maxCount - 1) * (n + 1) + maxTasks;
    return result > tasksSize ? result : tasksSize;
}

队列作为一种基础数据结构,在操作系统调度、网络通信、广度优先搜索等领域有广泛应用。掌握队列的各种实现方式及其典型应用场景,对于解决实际问题具有重要意义。通过练习这些题目,可以深入理解队列的特性及其在算法中的应用。

相关推荐
汤姆_5111 小时前
【c语言】深度理解指针4——sizeof和strlen
c语言·开发语言
_GR2 小时前
2025年蓝桥杯第十六届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·贪心算法·蓝桥杯·动态规划
shinelord明3 小时前
【软件系统架构】事件驱动架构
数据结构·设计模式·架构·系统架构·软件工程
照海19Gin3 小时前
数据结构中的宝藏秘籍之广义表
c语言·数据结构·算法
加点油。。。。3 小时前
C语言高频面试题——strcpy与memcpy区别
c语言·开发语言
大炮筒4 小时前
CPPlist初识
数据结构·c++·list
浅浅2804 小时前
numpy、pandas内存优化操作整理
数据结构·经验分享·python·学习·性能优化·numpy·pandas
bloxd yzh4 小时前
筛选法(埃氏筛法)C++
数据结构·算法
双叶8364 小时前
(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)
c语言·数据库·单片机·嵌入式硬件·mongodb·51单片机·nosql
那就摆吧4 小时前
数据结构-栈
android·java·c语言·数据结构