C语言实现顺序队列、循环队列、链式队列

本文深入探讨了三种队列数据结构:顺序队列、循环队列和链式队列。详细介绍了每种队列的实现原理,包括初始化、入队、出队、判空和判满等关键操作。并通过实例演示了队列的基本操作流程。

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

队列:先进先出(FIFO)。队尾入队,队头出队。

1 顺序队列

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

#define MAXSIZE 100
typedef int dataType;

typedef struct {
    dataType data[MAXSIZE];
    int front; //指向队列中第一个元素
    int rear;  //指向队列中最后一个元素下一位置
} SeQueue;

SeQueue* initSeQueue();             //创建一个空循环队列
int push(SeQueue* Q, dataType x);   //将元素x入队。操作成功返回1,失败返回0
int pop(SeQueue* Q, dataType* x);   //队首元素出队,并将其值赋给x。操作成功返回1,失败返回0
int isEmpty(SeQueue* Q);            //队列空返回1,否则返回0
int isFull(SeQueue* Q);             //队列满返回1,否则返回0
int getSize(SeQueue* Q);            //返回队列中存储的元素个数
int front(SeQueue* Q, dataType* x); //取队首元素,并将其值赋给x。操作成功返回1,失败返回0
int back(SeQueue* Q, dataType* x);  //取队尾元素,并将其值赋给x。操作成功返回1,失败返回0

int main()
{
    SeQueue* sq;
    int i;
    dataType x;

    sq = initSeQueue();
    int len = 10;

    printf("入队:\n");
    for (i = 0; i < len; i++) {
        push(sq, i);
        printf("%d 入队,队列长度为 %d\n", i, getSize(sq));
    }

    printf("\n出队:\n");
    for (i = 0; i < len; i++) {
        pop(sq, &x);
        printf("%d 出队,剩余队列长度为 %d\n", x, getSize(sq));
    }

    return 0;
}
// 建立空队列
SeQueue* initSeQueue()
{
    SeQueue* Q = (SeQueue*)malloc(sizeof(SeQueue));
    Q->front = 0;
    Q->rear = 0;

    return Q;
}

// 返回队列长度
int getSize(SeQueue* Q)
{
    return Q->rear - Q->front;
}

// 队列空返回1,否则返回0
int isEmpty(SeQueue* Q)
{
    return getSize(Q) == 0 ? 1 : 0;
}

// 队列满返回1,否则返回0
int isFull(SeQueue* Q)
{
    return getSize(Q) == MAXSIZE ? 1 : 0;
}

// 入队
int push(SeQueue* Q, dataType x)
{
    if (isFull(Q)) {
        return 0;
    } else {
        Q->data[Q->rear] = x;
        Q->rear++;
        return 1;
    }
}

// 出队
int pop(SeQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->front];
        Q->front++;
        return 1;
    }
}

//取队首元素,并将其值赋给x。操作成功返回1,失败返回0
int front(SeQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->front];
        return 1;
    }
}
//取队尾元素,并将其值赋给x。操作成功返回1,失败返回0
int back(SeQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->rear - 1];
        return 1;
    }
}

C:\WINDOWS\system32\cmd.exe /c (gcc -fexec-charset=gbk 1.c -o 1 ^&^& 1 ^&^& del 1.exe)
入队:
0 入队,队列长度为 1
1 入队,队列长度为 2
2 入队,队列长度为 3
3 入队,队列长度为 4
4 入队,队列长度为 5
5 入队,队列长度为 6
6 入队,队列长度为 7
7 入队,队列长度为 8
8 入队,队列长度为 9
9 入队,队列长度为 10

出队:
0 出队,剩余队列长度为 9
1 出队,剩余队列长度为 8
2 出队,剩余队列长度为 7
3 出队,剩余队列长度为 6
4 出队,剩余队列长度为 5
5 出队,剩余队列长度为 4
6 出队,剩余队列长度为 3
7 出队,剩余队列长度为 2
8 出队,剩余队列长度为 1
9 出队,剩余队列长度为 0
Hit any key to close this window...

2 循环队列

1、队列:随着入队出队的进行,rear、front后移,当指针移到最后,出现假溢出,浪费存储空间
2、循环队列:通过循环移动指针,解决假溢出

设循环队列首尾指针分别为front、rear,队列容量(队列可容纳的最大元素个数,不是实际存储的元素个数)为 capacity

2.1 循环队列判满、判空

2.1.1 设置计数器num

1、num == 0,循环队列空
2、num == capacity,循环队列满

2.1.2 少用一元素空间

1、front == rear,循环队列空
2、(rear + 1) % capacity == front,循环队列满

下面使用第二种方法判满、判空方法实现代码。

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

#define CQ_INIT_SIZE 100 //队列初始容量
typedef int dataType;

typedef struct {
    dataType* data; //存储队列元素
    int front;      //指向队列中第一个元素
    int rear;       //指向队列中最后一个元素下一位置
    int cqCapacity; //最多能容纳的元素个数(队列容量)
} CQueue;

CQueue* initCQueue();              //创建一个空循环队列
int push(CQueue* Q, dataType x);   //将元素x入队。操作成功返回1,失败返回0
int pop(CQueue* Q, dataType* x);   //队首元素出队,并将其值赋给x。操作成功返回1,失败返回0
int front(CQueue* Q, dataType* x); //取队首元素,并将其值赋给x。操作成功返回1,失败返回0
int back(CQueue* Q, dataType* x);  //取队尾元素,并将其值赋给x。操作成功返回1,失败返回0
int isEmpty(CQueue* Q);            //队列空返回1,否则返回0
int isFull(CQueue* Q);             //队列满返回1,否则返回0
int getSize(CQueue* Q);            //返回队列中存储的元素个数

int main()
{
    CQueue* cq;
    int i;
    dataType x;

    cq = initCQueue();
    int n = 10;

    printf("入队:\n");
    for (i = 0; i < n; i++) {
        push(cq, i);
        printf("%d 入队,队列长度为 %d,", i, getSize(cq));

        if (back(cq, &x)) {
            printf("队尾元素为 %d\n", x);
        }
    }

    printf("\n出队:\n");
    for (i = 0; i < n; i++) {
        pop(cq, &x);
        printf("%d 出队,剩余队列长度为 %d,", x, getSize(cq));

        if (front(cq, &x)) {
            printf("队首元素为 %d\n", x);
        }
    }

    return 0;
}

// 建立空队列
CQueue* initCQueue()
{
    CQueue* Q = (CQueue*)malloc(sizeof(CQueue));
    Q->data = (dataType*)malloc(CQ_INIT_SIZE * sizeof(dataType));
    Q->front = 0;
    Q->rear = 0;
    Q->cqCapacity = CQ_INIT_SIZE;

    return Q;
}

int getSize(CQueue* Q)
{
    return (Q->rear - Q->front + Q->cqCapacity) % Q->cqCapacity;
}

int isFull(CQueue* Q)
{
    return (Q->rear + 1) % Q->cqCapacity == Q->front ? 1 : 0;
}

int isEmpty(CQueue* Q)
{
    return Q->front == Q->rear ? 1 : 0;
    // return getSize(Q) == 0 ? 1 : 0;
}

// 入队
int push(CQueue* Q, dataType x)
{
    if (isFull(Q)) {
        // 若达到最大容量,则将新容量扩大至旧容量 1.5 倍
        int increment = Q->cqCapacity / 2;
        Q->data = (dataType*)realloc(Q->data,
            (Q->cqCapacity + increment) * sizeof(dataType));

        if (!Q->data) {
            return 0;
        }
        Q->cqCapacity += increment;
    }
    Q->data[Q->rear] = x;
    Q->rear = (Q->rear + 1) % Q->cqCapacity;
    return 1;
}

// 出队
int pop(CQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->front];
        Q->front = (Q->front + 1) % Q->cqCapacity;
        return 1;
    }
}
//取队首元素,并将其值赋给x。操作成功返回1,失败返回0
int front(CQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->front];
        return 1;
    }
}
//取队尾元素,并将其值赋给x。操作成功返回1,失败返回0
int back(CQueue* Q, dataType* x)
{
    if (isEmpty(Q)) {
        return 0;
    } else {
        *x = Q->data[Q->rear - 1];
        return 1;
    }
}

C:\Windows\system32\cmd.exe /c (gcc -fexec-charset=gbk 1.c -o 1 ^&^& 1 ^&^& del 1.exe)
入队:
0 入队,队列长度为 1,队尾元素为 0
1 入队,队列长度为 2,队尾元素为 1
2 入队,队列长度为 3,队尾元素为 2
3 入队,队列长度为 4,队尾元素为 3
4 入队,队列长度为 5,队尾元素为 4
5 入队,队列长度为 6,队尾元素为 5
6 入队,队列长度为 7,队尾元素为 6
7 入队,队列长度为 8,队尾元素为 7
8 入队,队列长度为 9,队尾元素为 8
9 入队,队列长度为 10,队尾元素为 9

出队:
0 出队,剩余队列长度为 9,队首元素为 1
1 出队,剩余队列长度为 8,队首元素为 2
2 出队,剩余队列长度为 7,队首元素为 3
3 出队,剩余队列长度为 6,队首元素为 4
4 出队,剩余队列长度为 5,队首元素为 5
5 出队,剩余队列长度为 4,队首元素为 6
6 出队,剩余队列长度为 3,队首元素为 7
7 出队,剩余队列长度为 2,队首元素为 8
8 出队,剩余队列长度为 1,队首元素为 9
9 出队,剩余队列长度为 0,Hit any key to close this window...

3 链式队列

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

// nil == 2147483647
#define nil 0x7fffffff

typedef int dataType;
typedef struct node {
    dataType data;
    struct node* next;
} QNode;

typedef struct {
    QNode* front;
    QNode* rear;
} LQueue;

LQueue* initLQueue();               // 建立空队列
int length(LQueue* Q);              // 返回队列长度
int isEmpty(LQueue* Q);             // 队列为空返回1;否则返回0
int inQueue(LQueue* Q, dataType x); // 入队成功返回1
int outQueue(LQueue* Q);            // 出队成功返回出队元素;否则返回 nil(0x7fffffff)
void traverseLQueue(LQueue* Q);     // 遍历链队列并输出
void destroyLQueue(LQueue* Q);      // 销毁队列

int main()
{
    LQueue* lq;
    int i;

    lq = initLQueue();
    int len = 10;

    printf("入队:\n");
    for (i = 0; i < len; i++) {
        inQueue(lq, i);
    }
    printf("队列长度:%d\n", length(lq));
    traverseLQueue(lq);

    printf("\n出队:\n");
    for (i = 0; i < len; i++) {
        int x = outQueue(lq);
        printf("%d 出队,剩余队列长度为 %d\n", x, length(lq));
    }
    traverseLQueue(lq);

    printf("\n销毁队列\n");
    destroyLQueue(lq);

    return 0;
}

// 建立空队列
LQueue* initLQueue()
{
    LQueue* Q;
    QNode* head; // head为头节点,队列空时front、rear都指向head

    Q = (LQueue*)malloc(sizeof(LQueue));
    head = (QNode*)malloc(sizeof(QNode));
    head->next = NULL;
    Q->front = head;
    Q->rear = head;

    return Q;
}

// 返回队列长度。也可用队列头节点存储队列长度,这样只需 return Q->front->data,
// 在入队、出队操作加上Q->front->data++、Q->front->data--。可以省去遍历的时间开销。
int length(LQueue* Q)
{
    int len = 0;
    QNode* p = Q->front;

    // while(p != Q->rear)
    while (p->next) {
        len++;
        p = p->next;
    }

    return len;
}

int isEmpty(LQueue* Q)
{
    return Q->front == Q->rear ? 1 : 0;
}

// 入队
int inQueue(LQueue* Q, dataType x)
{
    QNode* p;

    p = (QNode*)malloc(sizeof(QNode));
    p->data = x;
    p->next = NULL;
    Q->rear->next = p;
    Q->rear = p;
    return 1;
}

// 出队。出队成功返回出队元素,否则返回 nil(0x7fffffff)
int outQueue(LQueue* Q)
{
    if (isEmpty(Q)) {
        return nil;
    } else {
        QNode* p;
        dataType element;

        // 首元素出队并释放内存
        p = Q->front->next;
        Q->front->next = p->next;
        element = p->data;
        free(p);

        if (Q->front->next == NULL) {
            Q->rear = Q->front;
        }
        return element;
    }
}

// 遍历链队列
void traverseLQueue(LQueue* Q)
{
    if (isEmpty(Q) == 1) {
        printf("队列为空!\n");
    } else {
        QNode* p;
        int c;

        printf("队中元素依次为:");
        p = Q->front;
        while (p->next) {
            printf("%d, ", p->next->data);
            p = p->next;
        }
        printf("\n");
    }
}

// 销毁队列
void destroyLQueue(LQueue* Q)
{
    QNode* p = Q->front->next;
    while (p) {
        Q->front->next = p->next;
        free(p);
        p = Q->front->next;
    }
    free(Q->front);
    free(Q);
    Q = NULL;
    printf("销毁成功!\n");
}
C:\WINDOWS\system32\cmd.exe /c (gcc -fexec-charset=gbk 1.c -o 1 ^&^& 1 ^&^& del 1.exe)
入队:
队列长度:10
队中元素依次为:0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

出队:
0 出队,剩余队列长度为 9
1 出队,剩余队列长度为 8
2 出队,剩余队列长度为 7
3 出队,剩余队列长度为 6
4 出队,剩余队列长度为 5
5 出队,剩余队列长度为 4
6 出队,剩余队列长度为 3
7 出队,剩余队列长度为 2
8 出队,剩余队列长度为 1
9 出队,剩余队列长度为 0
队列为空!

销毁队列
销毁成功!
Hit any key to close this window...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值