1.顺序循环队列
顺序循环队列里base作为数组存放数据,定义front和rear的整型数值,控制队列的起始位置。当rear超过数组长度时,若数组的第一个位置还有空间,就将数据压入的base里的第一个位置,并且rear等于0。当base里的存储长度减去1等于定义的长度时,队列为满队。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// 循环队列,先进先出
#define MAXSIZE 5
typedef struct queue
{
int *base;
int front;
int rear;
// rear = front队列为空, (rear+1)%MAXSIZE = front队列为满队(如果不留一个位置,当队列满时,rear = front)
} Queue;
void InitQueue(Queue *Q)
{
Q->base = (int *)malloc(MAXSIZE * sizeof(int));
Q->front = 0;
Q->rear = 0;
}
// 入队: rear = rear + 1, 当rear指向最后一个位置时, rear = MAXSIZE - 1, rear+1后重新从0开始计数。
void EnQueue(Queue *Q, int data)
{
if ((Q->rear + 1) % MAXSIZE == Q->front)
{
puts("队列已满");
}
else
{
Q->base[Q->rear] = data;
printf("%d入队\n", data);
Q->rear = (Q->rear + 1) % MAXSIZE;
}
}
void DeQueue(Queue *Q, int *data)
{
if (Q->front == Q->rear)
{
puts("队列为空");
}
else
{
*data = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
printf("%d出队\n", *data);
}
};
void printQueue(Queue *Q)
{
if (Q->front == Q->rear)
{
puts("队列为空");
return;
}
int start = Q->front;
int end = Q->rear > Q->front ? Q->rear : (Q->rear + MAXSIZE);
puts("---打印队列---");
for (int k = start; k < end; k++)
{
int location = k % MAXSIZE;
printf("地址为%d的数据为%d\n", location, Q->base[location]);
}
}
void GetQueueHead(Queue *Q, int *data)
{
*data = Q->base[Q->front];
}
int main()
{
struct queue Q;
InitQueue(&Q);
EnQueue(&Q, 11);
EnQueue(&Q, 12);
EnQueue(&Q, 13);
EnQueue(&Q, 14);
printQueue(&Q);
int data = -1;
DeQueue(&Q, &data);
DeQueue(&Q, &data);
EnQueue(&Q, 15);
EnQueue(&Q, 16);
EnQueue(&Q, 17);
printQueue(&Q);
int head;
GetQueueHead(&Q, &head);
printf("循环队列的头指针的数据是:%d\n", head);
}
循环队列的长度为5,最多存储4个数据,避免头指针front和尾指针指向同一个地址,和队列为空加以区别,先删除两个数,在加三个数,第三个数17不能入队:
2. 链式队列
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// 链式队列
#define MAXSIZE 5
typedef struct QNode
{
int data;
struct QNode *next;
} QNode, *QueuePointer;
typedef struct {
QueuePointer front; // 队头指针
QueuePointer rear; // 队尾指针
} LinkQueue;
void InitQueue(LinkQueue *Q) {
QueuePointer node = (struct QNode *)malloc(sizeof(struct QNode));
node->data = 0;
node->next = NULL;
Q->front = node;
Q->rear = node;
// 空队列
}
// 入队
void EnQueue(LinkQueue *Q, int data) {
struct QNode *node = (struct QNode *)malloc(sizeof(struct QNode));
node->data = data;
node->next = NULL;
Q->rear->next = node; // 第一次设置rear,front的next指针也会指向新的节点
Q->rear = node; // rear指向新的节点,在队尾
// Q->front的next指向第一个有数据的节点。Q->front->data为空或者默认为0,不计入队列。
}
// 出队
void DeQueue(LinkQueue *Q, int *data) {
LinkQueue *p;
p = Q;
struct QNode *temp;
if (p->front == p->rear) {
puts("队列为空");
return;
}
if (p->front->next == p->rear) {
*data = p->rear->data;
p->rear = p->front; // 只有一个节点,删除后队尾指针指向队头指针
temp = p->front->next;
delete temp; // 释放删除节点的内存
} else {
*data = p->front->next->data;
temp = p->front->next;
p->front->next = temp->next; // 跨过要删除的节点,指向下下个节点
delete temp;
}
}
int GetQueueHead(LinkQueue *Q) {
if (Q->front != Q->rear) {
return Q->front->next->data;
}
}
void PrintQueue(LinkQueue *Q) {
LinkQueue *p;
p = Q;
struct QNode *head = p->front->next;
if (p->front == p->rear) {
puts("队列为空");
return;
}
puts("---打印队列---");
while(head) {
printf("队列的数据为%d\n", head->data);
head = head->next;
}
}
int EmptyQueue(LinkQueue *Q) {
if (Q->front == Q->rear) {
return 1;
} else return 0;
}
void conversion(LinkQueue *Q, int n) {
InitQueue(Q);
int number = n;
while(number) {
EnQueue(Q, number % 2);
number = number / 2;
}
PrintQueue(Q);
printf("---将10进制数据%d转化2进制---\n", n);
while(!EmptyQueue(Q)) {
int data;
DeQueue(Q, &data);
printf("%d", data);
}
printf("\n");
puts("---end---");
}
int main()
{
LinkQueue *linkQueue;
linkQueue = (LinkQueue *)malloc(sizeof(LinkQueue));
InitQueue(linkQueue);
EnQueue(linkQueue, 101);
EnQueue(linkQueue, 102);
EnQueue(linkQueue, 103);
EnQueue(linkQueue, 104);
PrintQueue(linkQueue);
int data = GetQueueHead(linkQueue);
printf("队列头节点数据:%d\n", data);
DeQueue(linkQueue, &data);
DeQueue(linkQueue, &data);
DeQueue(linkQueue, &data);
PrintQueue(linkQueue);
DeQueue(linkQueue, &data);
PrintQueue(linkQueue);
LinkQueue *queue;
queue = (LinkQueue *)malloc(sizeof(LinkQueue));
InitQueue(queue);
// Segmentation fault: 11
return 0;
}
main函数里的linkQueue变量和queue变量都使用malloc函数分配了内存,如果去掉这两行程序报错:Segmentation fault: 11。而分配内存的操作通常放在init初始化函数里,如果在init函数里执行Q= (LinkQueue *)malloc(sizeof(LinkQueue)); ,操作非法:
void InitQueue(LinkQueue *Q) {
QueuePointer node = (struct QNode *)malloc(sizeof(struct QNode));
Q = (LinkQueue *)malloc(sizeof(LinkQueue));
node->data = 0;
node->next = NULL;
Q->front = node;
Q->rear = node;
}
以上会报错,所以需要像链表那样重新定义队列的结构:
typedef struct {
QueuePointer front; // 队头指针
QueuePointer rear; // 队尾指针
} LinkQueue, *LinkQueuePointer;
然后所有的函数都像链表那样(类比于swap(int *a, int *b)交换函数):
void InitQueue(LinkQueuePointer *Q) {
*Q = (LinkQueuePointer *)malloc(sizeof(LinkQueuePointer));
(*Q)->front = NULL;
(*Q)->rear = NULL;
}
此时Q是结构体指针的指针,*Q是结构体指针,使用(*Q)->front代替Q.front去操作变量。
当然,还有一种方法,就是队列不使用指针初始化,可以这样做:
LinkQueue linkQueue;
InitQueue(&queue);
...
此时linkQueue = (LinkQueue *)malloc(sizeof(LinkQueue));就可以不要了。
另外,取地址符也是可以改指针的值(这个值是所指向的变量的地址,非指针自己的地址)。试想交换两个数字的函数:swap(&a, &b){a = b;}如果a是指针也是可以改的,即a本来指向一个地址,a=b以后a会指向b所指向的值的地址:
void InitQueue(LinkQueuePointer &T) {
T = (struct LinkQueue *)malloc(sizeof(struct LinkQueue));
}