哈喽!小伙伴们,大家好!
今天还是咱们的数据额结构,队列。队列也是受限定的线性表,不过它是限制只能在表的一端进行插入,在表的另一端进行删除的线性表。 之所叫它队列,就是因为它最大的特点就是“先进先出”,就像排队一样,来得早了就站在前面,先轮到你。
队尾(rear)——允许插入的一端
队头(front)——允许删除的一端
送道题帮你理解队列
请听题:
一个队列的入列顺序是1,2,3,4,则队列的输出系列是 (② )
① 4,3,2,1 ② 1,2,3,4
③1,4,3,2 ④ 3,2,4,1
解答:很好理解嘛,队列是先进先出的。入队顺序是1,2,3,4那么出队顺序也是1,2,3,4啦。
链队列
结点定义
typedef struct QNode
{
QElemType data;
struct QNode *next;
}*QueuePtr;
队列的定义
struct LinkQueue
{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
} ;
空队列
初始化
void InitQueue ( LinkQueue *Q )
{
Q.rear= Q.front=(QueuePtr)malloc(sizeof(QNode));
if(!Q.front)exit(OVERFLOW);
Q.front->next=NULL;
return OK;
}
链队列的主要操作
判断队列是否为空
int QueueEmpty ( LinkQueue *Q )
{
return Q.front->next == NULL;
}
取队头元素
int GetFront ( LinkQueue *Q, QueueData &x )
{
if ( QueueEmpty (Q) ) return 0;
x = Q.front->next->data;
return 1;
}
入队
int EnQueue ( LinkQueue *Q, QueueData x )
{
QueueNode *p = ( QueueNode * ) malloc( sizeof ( QueueNode ) );
if(!p) exit(OVERFLOW);
p->data = x;
p->next = NULL;
Q->rear->next=p;
Q->rear =p;
}
出队
int DeQueue ( LinkQueue *Q, QueueData &e)
{ //删去队头结点,并返回队头元素的值
if ( QueueEmpty (Q) ) return 0; //判队空
QueueNode *p = Q.front->next;
e = p->data; //保存队头的值
Q.front->next= p->next; //新队头
if(Q.rear==p) //队列被删除之后为空
Q.rear=Q.front;
free (p);
return 1;
}
循环队列
顺序队列是用一组地址连续的存储单元依次存放从队列头到队列尾的元素,
指针front和rear分别指示队头元素和队尾元素下一个的位置。
插入新的队尾元素,尾指针增1,rear = rear + 1,
删除队头元素,头指针增1, front = front + 1,
因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置。
存在一个问题?
队列的进队和出队
存在的问题
设数组长度为M,则:
当front=0,rear=M时,再有元素入队发生溢出——真溢出
当front0,rear=M时,再有元素入队发生溢出——假溢出
解决方案
队首固定,每次出队剩余元素向下移动——浪费时间
循环队列的基本思想:把队列设想成环形,让sq[0]接在sq[M-1]之后,若rear+1==M,则令rear=0;
新的问题
队空用front == rear;判断
队满时front==rear;
出现矛盾。
解决方案
1.另外设一个标志以区别队空、队满
2.少用一个元素空间:
队空:front==rear
队满:(rear+1)%M==front
少用一个元素空间:
队空:front==rear
队满:(rear+1)%M==front
循环队列 特点:
队头、队尾指针加1,可用取模(余数)运算实现。
队头指针进1(出队): front = (front+1) %M;
队尾指针进1(入队): rear = (rear+1) % M;
队列初始化:front = rear = 0;
队空条件:front == rear;
队满条件:(rear+1) % M == front;
循环队列的类型定义
#define MAXSIZE 100
struct SqQueue{
QueueType *base;
int front;
int rear;
};
初始化队列
void InitQueue ( SqQueue *Q )
{//构造空队列
Q.base=(QElemType *)malloc(MAXSIZE *sizeof(QElemType));
if(! Q.base)exit(OVERFLOW);
Q->rear = Q->front = 0;
return OK;
}
判队空
int QueueEmpty ( SeqQueue *Q )
{
return Q->rear == Q->front;
}
判队满
int QueueFull ( SeqQueue *Q )
{
return (Q->rear+1) % QueueSize == Q->front;
}
入队
int EnQueue ( SeqQueue *Q, QueueData e )
{
if ( QueueFull (Q) ) return 0;
Q.base[Q->rear] = e;
Q->rear = ( Q->rear+1) % MAXSIZE;
return 1;
}
出队
int DeQueue ( SeqQueue *Q, QueueData &x )
{
if ( QueueEmpty (Q) ) return 0;
x = Q.base[Q->front];
Q->front = ( Q->front+1) % MAXSIZE;
return 1;
}
取队头int GetFront ( SeqQueue *Q, QueueData &x )
{
if ( QueueEmpty (Q) ) return 0;
x = Q.base[Q->front];
return 1;
}
好啦,小伙伴们!今天的分享就到这里,你们学会了吗?如果有什么问题可以在微信公众号私信给我,明天见喽!