队列

1 概念

队列是一种先进先出(FIFO,First-In-First-Out)或后进后出(LILO,Last-In-Last-Out)的线性表,通常用链表或者数组来实现。

队列只能在队尾插入元素(入队),只能在队首删除元素(出队)。

2 基本操作

2.1 结构定义

实现队列需要引入两个变量,head用于标记队首元素的位置,tail用来标记队尾元素的位置;

// 普通队列的结构定义
typedef struct Queue {
    int *data;
    int head, tail, length;
} Queue;

// 循环队列的结构定义(顺序表)
typedef struct Queue {
    int *data;
    int head, tail, length;
    int count;  // 循环队列中元素的个数
} Queue;

// 链队列的结构定义
typedef struct Node {
    int data;
    struct Node *next;
} Node;

typedef struct Queue {
    Node head, *tail;
    int length;
} Queue;

2.2 出队(head后移)

2.3 入队(tail后移)

3 普通队列的“假溢出”问题

对于普通队列而言,一旦队列出队发生,这就意味着有了空闲的空间,然而这些空闲空间并不会被使用。当多次向队列执行入队操作,直到tail标记指向了队列容量的上限时,就有出现“假溢出”现象。如何避免“假溢出”呢?使用循环队列,通过累计队列元素的个数来判断队列的容量上限,而不是简单地通过tail标记做判断;或者通过链队列来实现。

4 代码演示

4.1 循环队列(入队+扩容、出队)

// 结构定义
typedef struct Queue {
    int *data;
    int head, tail, length;
    int count;
} Queue;

// 创建队列
Queue *init(int n) {
    Queue *q = (Queue *)malloc(sizeof(Queue));
    q->data = (int *)malloc(sizeof(int) * n);
    q->length = n;
    q->head = q->tail = 0;
    q->count = 0;
    return q;
}

// 清空队列
void clear(Queue *q) {
    if (q == NULL) return ;
    free(q->data);
    free(q);
    return ;
}

// 队列判空操作
int empty(Queue *q) {
    return q->count == 0; 
}

// 获取队首元素
int front(Queue *q) {
    return q->data[q->head];
}

// 入队
int push(Queue *q, int val) {
    if (q == NULL) return 0;
    // 队列已满,给队列扩容
    if (q->count == q->length) {
        if (!expand(q)) {
            printf(RED("fail to expand!\n"));
            return 0;
        } 
        printf(GREEN("success to expand! the new size = %d\n"), q->length);
    }
    q->data[q->tail++] = val;
    if (q->tail == q->length) q->tail = 0;  // 循环队列首尾位置转换
    q->count += 1;
    return 1;
}

// 出队
int pop(Queue *q) {
    if (q == NULL) return 0;
    if (empty(q)) return 0;
    q->head += 1;
    if (q->head == q->length) q->head = 0;  // 循环队列首尾位置转换
    q->count -= 1;
    return 1;
}

// 遍历
void output(Queue *q) {
    printf("Queue(%d) : [", q->count);
    for (int i = q->head, j = 0; j < q->count; j++) {
        j && printf(", ");
        printf("%d", q->data[(i + j) % q->length]);
    }
    printf("]\n");
    return ;
}

// 扩容
int expand(Queue *q) {
    int extr_size = q->length;
    int *temp;
    while (extr_size) {
        temp = (int *)malloc(sizeof(int) * (q->length + extr_size));
        if (temp != NULL) break;
        extr_size >> 1;
    }
    if (temp == NULL) return 0; // 扩容失败(没有足够的内存)
    for (int i = q->head, j = 0; j < q->count; j++) {
        temp[j] = q->data[(i + j) % q->length];
    }
    free(q->data);
    q->data = temp;
    q->head = 0, q->tail = q->count;
    q->length += extr_size;
    return 1;
} 

4.2 链队列(入队、出队)

// 链队列的结构定义
typedef struct Node {
    int data;
    struct Node *next;
} Node;

typedef struct Queue {
    Node head, *tail;
    int length;
} Queue;

Node *getNewNode(int val) {
    Node *p = (Node *)malloc(sizeof(Node));
    p->data = val;
    p->next = NULL;
    return p;
}

Queue *init_queue() {
    Queue *q = (Queue *)malloc(sizeof(Queue));
    q->head.next = NULL;    // q->head.next 指向队首元素的地址
    q->tail = &(q->head);   // q->tail指向队首元素的虚拟地址
    q->length = 0;
    return q;
}

int empty(Queue *q) {
    return q->length == 0;
}

int front(Queue *q) {
    return q->head.next->data;
}

int push(Queue *q, int val) {
    if (q == NULL) return 0;
    Node *temp = getNewNode(val);
    q->tail->next = temp;   // 入队操作
    q->tail = temp;         // 指针后移
    q->length += 1;
    return 1;
}

int pop(Queue *q) {
    if (q == NULL) return 0;
    if (empty(q)) return 0;
    Node *temp = q->head.next;
    q->head.next = temp->next;  // 指针后移
    clear_node(temp);           // 出队操作
    q->length -= 1;
    if (q->length == 0) q->tail = &(q->head);   // 队列为空时,需要将q->tail指向队首元素的虚拟地址
    return 1;
}

void clear_node(Node *node) {
    if (node == NULL) return ;
    free(node);
    return ;
}

void clear(Queue *q) {
    if (q == NULL) return ;
    Node *p = q->head.next, *temp;
    while (p != NULL) {
        temp = p->next;
        clear_node(p);
        p = temp;
    }
    free(q);
    return ;
}

void output(Queue *q) {
    if (q == NULL) return ;
    printf("Queue(%d) : [", q->length);
    for (Node *p = q->head.next; p != NULL; p = p->next) {
        p != q->head.next && printf(", ");
        printf("%d", p->data);
    }
    printf("]\n");
    return ;
}
posted @ 2022-02-22 21:03  PRO_Z  阅读(139)  评论(0编辑  收藏  举报