特殊的线性表,先进先出(FIFO)
(1)数据:对于非空的队列,表头没有直接前驱,表尾没有直接后继,其他有且仅有一个直接前驱和一个直接后继。
(2)操作:只允许在表尾插入数据,在表头删除数据
定义:
它是顺序表的一种,具有顺序表同样的数据结构,由数组定义,配合用数组下标表示对头指针和队尾指针完成各种操作。
表示:
#define MAXSIZE 10
typedef int datatype;/* 定义队列中数据元素的数据类型*/
typedef struct seq{
datatype data[MAXSIZE]; /* 用数组作为队列的存储空间*/
int front;//front:始终存放队头位置的前一个下标;
int rear; //rear:始终存放队尾元素的下标
}seqqueue,*seqqueue_p; /* 顺序队列类型定义*/
存在的问题:
1、入队和出队:随着入队、出队操作的进行,整个队列会整体向后移动,这样就出现了下图的现象:队尾指针虽然已经移到了最后,而队列却未真满的“假溢出”现象,使得队列的空间没有得到有
效的利用。
改进前:
改进方法:改进为一个循环队列
改进后:
2、根据问题1的改进后,可得到一个循环队列,如下图所示,这时候我们初始化队列时就不应该将front和rear初始化为-1了(当然也不是不可以,只是根据循环队列更好理解),那么我们就应该把front和rear初始化为MAXSIZE-1;这时候问题又来了,当我们一直入队操作,当满了之后,front和rear又相等了,这就不能判断队列到底为空还是为满(因为rear==front这个条件也为空队列时的条件)。无法区别满对和空对
改进办法:少用(损失)一个空间,以队尾下标加1等于对头下标作为队满的标志。因此:当front=rear=MAXSIZE-1,表示循环队列为空;当front ==(rear+1)% MAXLEN,表示循环队列为满。
示例程序:用循环队列实现如下功能:用户从键盘输入整数,程序将其入队,用户输入字母,程序将对头元素出队,并在每次出队和入队之后打印队列元素。
代码实现:
seqqueue.c
#include "seqqueue.h"
void create_seqqueue(seqqueue_p *seq)//创建一个队列
{
(*seq) = (seqqueue_p)malloc(sizeof(seqqueue));
if(NULL == (*seq))
{
perror("malloc");
exit(-1);
}
// 断其臂,保其身,最后一个空。定义为满状态
(*seq)->front = (*seq)->rear = MAXSIZE-1;//初始化队头以及队尾指针
return;
}
/* 判断队列是否已满*/
bool is_full_seqqueue(seqqueue_p seq)
{
if( (seq->rear+1)%MAXSIZE == seq->front )
{
//已满
return true;
}
else
{
return false;
}
}
/* 入队*/
bool in_seqqueue(seqqueue_p seq,datatype data)
{
//判断队列是否已满
if(is_full_seqqueue(seq))
{
printf("队列已满\r\n");
return false;
}
//入队
seq->rear = (seq->rear+1) % MAXSIZE;
seq->data[seq->rear] = data;
return true;
}
/* 判断队列是否为空*/
bool is_empty_seqqueue(seqqueue_p seq)
{
if(seq->front == seq->rear)
{
//已空
return true;
}
return false;
}
/* 出队*/
bool out_seqqueue(seqqueue_p seq,datatype* data)
{
//判断队列是否为空
if(is_empty_seqqueue(seq))
{
printf("队列已空\r\n");
return false;
}
//出队
seq->front = (seq->front+1)%MAXSIZE;
*data = seq->data[seq->front];
return true;
}
/* 打印*/
void show_seqqueue(seqqueue_p seq)
{
int i;
if(is_empty_seqqueue(seq))
{
/* 空不打印*/
return;
}
/* 非空时,从对头打印数据到队尾*/
for(i=(seq->front+1)%MAXSIZE ;i!=(seq->rear+1)%MAXSIZE; i=(i+1)%MAXSIZE)
{
printf("%d\r\n",seq->data[i]);
}
return;
}
seqqueue.h
#ifndef __SEQQUEUE_H__
#define __SEQQUEUE_H__
#include
#include
#include
#include
#define MAXSIZE 10
typedef int datatype;/* 定义队列中数据元素的数据类型*/
typedef struct seq{
datatype data[MAXSIZE]; /* 用数组作为队列的存储空间*/
int front,rear;//front:指向队头位置的前一个元素的下标; rear;指向队尾元素的下标
}seqqueue,*seqqueue_p; /* 顺序队列类型定义*/
/**************************函数声明*******************************/
void create_seqqueue(seqqueue_p *seq);//创建一个队列
/* 入队*/
bool in_seqqueue(seqqueue_p seq,datatype data);
/* 出队*/
bool out_seqqueue(seqqueue_p seq,datatype* data);
/* 打印*/
void show_seqqueue(seqqueue_p seq);
#endif
main.c
#include "seqqueue.h"
int main()
{
datatype data,t;
seqqueue_p seq;
int ret;
create_seqqueue(&seq);//顺序队列初始化
while(1)
{
printf("请输入一个整数:");
ret = scanf("%d",&data);
//输入的是整数,入队
if(ret == 1)
{
if(in_seqqueue(seq,data))
{
//插入元素成功
show_seqqueue(seq);
}
}
//输入为字符时,出队
else
{
if(out_seqqueue(seq,&t))
{
printf("out:%d\r\n",t);
show_seqqueue(seq);
}
//将前一个scanf输入的缓冲区通过循环全部清空
while (getchar() != '\n');//表示只要字符不是回车就继续吃缓冲区字符
}
}
return 0;
}
定义:
链式队列中每个元素定义成一个结点,含数据域与指针域(指向下一结点),并设头尾指针。用图表示就是。
规定:
front: 指向队头节点的前一个节点(头节点)的指针。
rear: 指向队尾节点的指针。
typedef int datatype; /* 定义链对列中数据元素的数据类型*/
typedef struct node{
datatype data; /* 数据域*/
struct node *next; /* 链接指针域*/
}linklist; /* 链对元素类型定义*/
typedef struct{
linklist *front,*rear; /* 链队列指针*/
}linqueue,*linqueue_p; /* 链队列类型定义*/
lsqueue *CreateLqueue()
{
linkqueue * head = (linkqueue *)malloc(sizeof(linkqueue));
if(head == NULL)
return NULL;
head->data = -1;
head->next = NULL;
lsqueue * lq = (lsqueue *)malloc(sizeof(lsqueue));
if(lq == NULL)
return NULL;
lq->front = lq->rear = head;
return lq;
}
int EnLqueue(lsqueue *lq,data_t data)
{
if(lq == NULL)
return -1;
linkqueue *new = (linkqueue *)malloc(sizeof(linkqueue));
if(new == NULL)
return -1;
new->data = data;
new->next = NULL;
lq->rear->next = new;
lq->rear = new;
return 0;
}
data_t DeLqueue(lsqueue *lq)
{
if(lq == NULL || Lsqueue_is_Empty(lq))
return -1;
linkqueue *p = lq->front->next;
data_t m = p->data;
//如果p是最后一个有效结点 那么需要把rear 调整回跟 front 相等
if(p->next != NULL)
{
lq->front->next = p->next;
free(p);
p = NULL;
}else{
lq->front->next = p->next;
lq->rear = lq->front;
free(p);
p = NULL;
}
return m;
}
int Lsqueue_is_Empty(lsqueue *lq)
{
if(lq == NULL)
return -1;
return lq->front == lq->rear;
}
int PrintLinkqueue(lsqueue *lq)
{
if(lq == NULL)
return -1;
linkqueue *p = lq->front->next;
while(p != NULL)
{
printf(" %d ",p->data);
p = p->next;
}
printf("\n");
}