您的位置:首页 > 理论基础 > 数据结构算法

【嵌入式学习历程10】数据结构之队列

2017-12-03 10:55 561 查看
前面 我们讲了栈,知道栈有顺序存储和链式存储两种方式,今天的主角--队列也是一样的。

我们先来理清队列的概念:

1、队列是特殊的线性表;

队列仅在线性表两端进行操作;

队头(Front):取出数据的一端;

队尾(Rear):放入数据的一端;

2、性质:先进先出(FIFO)

3、顺序队列(一般采用循环队列)

规定front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear的时候,就表示该队列为空队列。
下面,我们上图



我们可以举个栗子,比如食堂打饭,下课之前,食堂空无一人,也就是空队列。下课后,大家陆陆续续来到食堂开始排队,但是由于空间限制,当这个队伍到一定的长度时,后面有一堵墙挡住了,就相当于队列有一个最大容量MAXSIZE,我们就假设是8,。但是我们看这个rear是如何规定的---rear指针指向队尾元素的下一个位置,所以,这个队伍实际上只能容纳7人,即对于一个容量为MAXSIZE的队列,最多只能存放MAXSIZE-1个元素。那么有人要问了,为啥不直接让rear指向最后一个元素呢,这样不就万事大吉了。然实则非也,之所以这样规定是有它的道理的。如果rear直接指向最后一个元素,那么当这个队列只有一个元素时,那么这个元素既是第一个也是最后一个,那么,front和rear就同时指向这个元素,当队列为空的时候也是front等于rear。那我们怎么区分0和1呢?

看到这里,我们就发现了顺序队列有个缺点,如果再来一个元素插进来,那么rear将何去何从呢,这时候会出现假溢出的现象,为了解决这个问题,我们一般采用循环队列。

循环队列,说白了就是头尾相接的队列,那么这种情况下,rear也会出现在front的前面。比如,上面图中的1号出队了,这时候又来个8号,这时候8号就排在了7号之后,但是rear就指向了1号出队后的空缺,那么front去哪了呢。我们为什么要取名为front呢,因为它是队头呀,那么当原本的队头1号出队了,front还有必要指向它吗?所以,当1号出队时,front已经指向了2号。我们说队列是先进先出的,那么当队列变成循环的了,应该先出那个呢?没错,这就是front的作用了,当然是先出front所指向的队头啦。

那么我们怎么知道队列的长度以及是否满了呢?

1.判断队列是否满:

(rear + 1) % MAXSIZE  = = front;

2.求取队列的长度:

(rear - front + MAXSIZE) % MAXSIZE;

注意:这里的rear和front都是数组的下标。

typedef  struct {

    int data[MAXSIZE];

    int front;

    int rear;

   }SqQueue;

初始化一个空队列Q:
   int InitQueue(SqQueue *Q)
   {
    Q->front = 0;
    Q->rear  = 0;
    return OK; 
   }

循环队列的入队列:
   int EnQueue(SqQueue *Q, int e)
   {
    if((Q->rear+1)%MAXSIZE ==Q->front)
    return ERROR;
    Q->data[Q->rear] = e;
    Q->rear=(Q->rear+1)%MAXSIZE;
      return OK;
   }

循环队列的出队列:
   int DeQueue(SqQueue *Q, int *e)
   {
    if(Q->rear==Q->front)
    return ERROR;
    *e=Q->data[Q->front];
    Q->front=(Q->front+1)%MAXSIZE;
    return OK;
   }

4、链队

队列的链式存储结构,其实就是线性表的单链表,只是它只能够从尾进队、从头出队。一般,我们将队头指针指向链队列的头结点,而将队尾指针指向尾结点。

下面我们来实现链队的基本功能

头文件:

#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_

#define FAILURE 10000
#define SUCCESS 10001

typedef int ElemType;

typedef struct node
{
ElemType data;
struct node *next;
}Node;

typedef Node *LinkNode;

typedef struct queue
{
LinkNode front;
LinkNode rear;
}Queue;

typedef Queue *LinkQueue;

#endif


接口函数实现:
#include <stdio.h>
#include <stdlib.h>
#include "LinkQueue.h"
/* 初始化队列 */
int InitQueue(LinkQueue *Q)
{
(*Q)->front = (LinkNode)malloc(sizeof(Node));
if ((*Q) == NULL)
{
return FAILURE;
}
(*Q)->rear = (*Q)->front;
(*Q)->front->next = NULL;
return SUCCESS;
}
/* 进队 */
int EnQueue(LinkQueue *Q, ElemType x)
{
LinkNode p = (LinkNode)malloc(sizeof(Node));

if(NULL == p)
{
return FAILURE;
}
p->data = x;
p->next = NULL;
(*Q)->rear->next = p;
(*Q)->rear = p;
return SUCCESS;
}
/* 求队列长度 */
int QueueLength(LinkQueue Q)
{
int length = 0;
LinkNode q = Q->front;
while(q->next)
{
length++;
q = q->next;
}
return length;
}
/* 出队 */
int DelQueue(LinkQueue *Q)
{
ElemType x;
LinkNode p = (*Q)->front->next;

if (NULL == p)
{
return FAILURE;
}

x = p->data;
(*Q)->front->next = p->next;
free(p);

if (NULL == p->next)
{
(*Q)->rear = (*Q)->front;
}

return x;
}
/* 获取队头 */
int GetFront(LinkQueue *Q)
{
LinkNode p = (*Q)->front->next;

if (NULL == p)
{
return FAILURE;
}
return p->data;
}
/* 清空队列 */
int ClearQueue(LinkQueue *Q)
{
LinkNode p = (*Q)->front->next;

if(NULL == p)
{
return FAILURE;
}

while(p)
{
(*Q)->front->next = p->next;
free(p);
p = (*Q)->front->next;
}

if(NULL == p)
{
(*Q)->rear = (*Q)->front;
}
return SUCCESS;
}
/* 销毁队列 */
int DestroyQueue(LinkQueue *Q)
{
if(NULL == (*Q))
{
return FAILURE;
}

free((*Q)->front);
(*Q)->front = NULL;
(*Q)->rear = NULL;
return SUCCESS;
}


主函数:
#include <stdio.h>
#include "LinkQueue.h"

int main()
{
int ret, i;
LinkQueue q;
ElemType e;

ret = InitQueue(&q);
if (FAILURE == ret)
{
printf("Init Failure!\n");
}
else
{
printf("Init Success!\n");
}

for(i = 0; i < 10; i++)
{
e = i;
ret = EnQueue(&q, e);

if (FAILURE == ret)
{
printf("Enter Element Failure!\n");
}
else
{
printf("Enter %d Success!\n",e);
}

}

printf("Length is %d\n", QueueLength(q));

for(i = 0; i < 7; i++)
{
ret = DelQueue(&q);

if (FAILURE == ret)
{
printf("Delete Element Failure!\n");
}
else
{
printf("Delete %d Success!\n",ret);
}
}

printf("Length is %d\n", QueueLength(q));

printf("Front is %d\n", GetFront(&q));

ret = ClearQueue(&q);

if (FAILURE == ret)
{
printf("Clear Failure!\n");
}
else
{
printf("Clear Success!\n");
}
printf("Length is %d\n", QueueLength(q));

ret = DestroyQueue(&q);

if (FAILURE == ret)
{
printf("Destroy Failure!\n");
}
else
{
printf("Destroy Success!\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: