1、定义
从栈的学习我们知道栈是只允许在一端进行插入或删除操作的线性表。
而队列:是只允许在一端进行插入在另一端删除的线性表。在生活中比如说到饭堂排队打饭,一端进一端出,这就是队列。
2、队列顺序实现
2.1、队列的基本形式
typedef int Elemtype;//需要时可以改为自己需要的元素类型
#define MaxSize 10 //定义队列中元素的最大值
typedef struct {
Elemtype data[MaxSize];//用静态数组存放列表元素
int front, rear;//队头指针和队尾指针
}SqQueue;
void textQueue()
{
SqQueue Q;
}
2.2、入队操作
typedef struct {
Elemtype data[MaxSize];//用静态数组存放列表元素
int front, rear;//队头指针和队尾指针
}SqQueue;
bool QueueEmpty(SqQueue &Q)
{
if (Q.front == Q.rear)//队空条件
return false;
else
return true;
}
//入队
bool EnterQueue(SqQueue& Q, Elemtype x)
{
if ((Q.rear+1)% MaxSize==Q.front)
return false;//队满则报错
Q.data[Q.rear] = x;//新元素加入队尾
Q.rear = (Q.rear + 1) % MaxSize;//队尾指针加一取模
return true;
}
Q.rear = (Q.rear + 1) % MaxSize;
许多人看到这一条就会疑惑,为什么要加一取模?
队列并没有所规定的头或尾,如果加到data[MaxSize],而data[0]没有元素,便能将元素加到data[0],而不用浪费空间。这样操作便能将队列在存储空间在逻辑上变成了“环状”。
用模运算便能从最大值变为最小值:例如你现在元素存储到data[9],(9+1)%10=0,你的下一个元素便能存储到data[0]。
2.3、出队操作
进行出队操作时要记住一件事:只能让对头元素出队!
typedef int Elemtype;//需要时可以改为自己需要的元素类型
#define MaxSize 10 //定义队列中元素的最大值
typedef struct {
Elemtype data[MaxSize];//用静态数组存放列表元素
int front, rear;//队头指针和队尾指针
}SqQueue;
//出队(删除一个队头元素,并用x返回)
bool DeleteQueue(SqQueue &Q,Elemtype x)
{
if (Q.rear == Q.front)//判断队空
return false;//队空则判错
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;//队头指针后移
return true;
}
注:入队还是出队都是让指针后移一位
2.4、获得队头元素
获得队头元素这个操作与出队相似,不过获得队头元素只是将队头元素通过x返回,并不改变队列里的数据。
bool GetHead(SqQueue& Q, Elemtype &x)
{
if (Q.rear == Q.front)//判断队空
return false;//空则判错
x = Q.data[Q.front];
return true;
}
2.5、判断队空/队满
一般来说队空/队满很容易判断,这里给出两个方法:
(1)计算出队列中的元素个数:(rear+MaxSize-front)%MaxSize
队满条件是(Q.rear + 1) % MaxSize ==Q.front,队空条件是rear=front。
(2)设置一个长度,在入队或出队过程中进行计算:
typedef int Elemtype;//需要时可以改为自己需要的元素类型
#define MaxSize 10 //定义队列中元素的最大值
typedef struct {
Elemtype data[MaxSize];//用静态数组存放列表元素
int front, rear;//队头指针和队尾指针
int size;
}SqQueue;
初始化为rear=front=0,size=0
队满条件是size==MaxSize,队空条件是size==0。
3、队列的链式实现
3.1、链式队列的一个结点
typedef int Elemtype;
typedef struct LinkNode {//链式队列结点
Elemtype data;
struct LinkNode* next;
}LinkNode;
typedef struct {//链式队列
LinkNode* front, *rear;//队列的队头和队尾指针
}LinkQueue;
3.2、初始化(带头结点)
//初始化队列(带头结点)
void InitQueue(LinkQueue& Q)
{
Q.front = Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
Q.front->next = NULL;
}
//判断队列是否为空
bool IsEmpty(LinkQueue& Q)
{
if (Q.front == Q.rear)
return true;
else
return false;
}
3.3、入队(带头结点)
//新元素入队(带头结点)
void EnQueue(LinkQueue &Q,Elemtype x)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = NULL;
Q.rear ->next= s;//新结点插入到rear后面
Q.rear = s;//修改表尾指针
}
3.4、入队(不带头结点)
//新元素入队(不带头结点)
void EnQueue(LinkQueue& Q, Elemtype x)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = NULL;
if (Q.front = NULL)//在空列中插入第一个元素
{
Q.front = s;//修改队头队尾指针
Q.rear = s;
}
else {
Q.rear->next = s;//新结点插入到rear后面
Q.rear = s;//修改表尾指针
}
}
3.5、出队(带头结点)
//出队(带头结点)
bool DeQueue(LinkQueue& Q, Elemtype& x)
{
if (Q.front == Q.rear)//空队返回
return false;
LinkNode* p = Q.front->next;//
x = p->data;//用变量x返回队头指针
Q.front->next = p->next;//修改头结点的next指针
if (Q.rear = p)//此次是最后一个结点出队
Q.rear = Q.front;//修改rear指针
free(p);//释放结点空间
return true;
}
3.6、出队(不带头结点)
//出队(不带头结点)
bool DeQueue(LinkQueue& Q, Elemtype& x)
{
if (Q.front == NULL)
return false;//空队
LinkNode* p = Q.front;//p指向出队的头结点
x = p->data;//用x返回队头元素
Q.front = p->next;//修改front指针
if (Q.rear == p)//此次是最后一个结点出队
{
Q.front = NULL;//front指向NULL
Q.rear = NULL;//rear指向NULL
}
free(p);
return true;
}