队列:先进先出(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...