队列
•与栈相反,队列是一种先进先出(First In First Out, FIFO)的线性表。只允许在表尾一端进行插入操作而在表头一端进行删除操作。
队列既可以用链表实现,也可以用顺序表实现。
跟栈相反的是,栈一般我们用顺序表来实现,而队列我们常用链表来实现,简称为链队列。
//队列的链式表示和实现
typedef struct QNode{
ElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
将队头指针指向链队列的头结点,而队尾指针指向终端结点。(头结点不是必要的)
空队列时,front和rear都指向头结点。
以下将
构造一个空队列、往队列中插入元素、删除元素、销毁队列都用C语言描述
和之前的线性表类似,所以在学习这部分的时候就轻松得多。
注意:c语言中->和.的区别——->用于指针, .用于对象
"->"用于指向结构成员,它的左边应为指向该结构类型的指针(结构指针),而"."的左边应为该结构类型的变量(结构变量),如已定义了一个结构体struct student,里面有一个int a;然后有一个结构体变量struct student stu及结构体变量指针struct student *p;且有p=&stu,那么p->a和stu.a表示同一个意思。
实践:编写一个链队列,任意输入一串字符,以#作为结束标志,然后将队列中的元素显示到屏幕上
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;
typedef struct QNode{
ElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
int InitQueue(LinkQueue *q)
{
q->front = q->rear = (QueuePtr)malloc(sizeof(QNode));
if(!q->front)
{
exit(0);//存储分配失败
}
q->front->next = NULL;
return 1;
}
int InsertQueue(LinkQueue *q,ElemType e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(!q->front)
exit(0);
p->data = e;
p->next = NULL;
q->rear->next = p;
q->rear = p;
return 1;
}
int DeleteQueue(LinkQueue *q,ElemType *e)
{
QueuePtr p;
if(q->front == q->rear)
return 0;
p = q->front->next;
*e = p->data;
q->front->next = p->next;
if(q->rear == p)//队列中仅有一个元素,删除后队列为空
q->rear = q->front;
free(p);
return 1;
}
int DestroyQueue(LinkQueue *q)
{
while(q->front)
{
q->rear = q->front->next;
free(q->front);
q->front = q->rear;
}
return 1;
}
int main()
{
ElemType e;
LinkQueue q;
InitQueue(&q);
printf("请输入一个字符串,并以#号键结束输入:");
scanf("%c",&e);
while(e !='#')
{
InsertQueue(&q, e);
scanf("%c",&e);
}
printf("打印队列中的元素:");
while( q.front != q.rear )
{
DeleteQueue(&q,&e);
printf("%c",e);
}
return 0;
}
循环队列
队列的顺序存储结构:影响程序效率,也容易出现数组越界的错误。
解决假溢出的办法就是队列满了之后就再从头开始,也就是头尾相接的循环队列。
•循环队列它的容量是固定的,并且它的队头和队尾指针都可以随着元素入出队列而发生改变,这样循环队列逻辑上就好像是一个环形存储空间。
队列空条件:q.front == q.rear
队列满条件:(q.rear +1)%maxsize == 0 (此时队列实际容量为maxsize -1)
//定义一个循环队列
#define MAXSIZE 100
typedef struct
{
ElemType *base; // 用于存放内存分配基地址
// 这里也可以用数组存放
int front;
int rear;
}SqQueue;
//初始化一个循环队列
Status InitQueue(SqQueue *q)
{
q->base = (ElemType *) malloc (MAXSIZE * sizeof(ElemType));
if( !q->base )//存储分配失败
exit(0);
q->front = q->rear = 0;
return OK;
}
//插入元素e
Status EnQueue(SqQueue *q,ElemType e)
{
if((q->rear+1)%MAXSIZE == q->front)
return ERROR;
q->base[q->rear] = e;
q->rear = (q->rear+1)%MAXSIZE;
return OK;
}
//出队列操作
DeleteQueue(SqQueue *q, ElemType *e)
{
if( q->front == q->rear )
return ERROR; // 队列为空
*e = q->base[q->front];
q->front = (q->front+1) % MAXSIZE;
return OK;
}