1.顺序队列的常用基本操作及条件判断

队空:    Q.front=Q.rear
队满: Q.rear=Maxlen
求队长: Q.rear-Q.front

入队: 1)新元素按 rear 指示位置加入
2)rear = rear + 1队尾指针加一
出队: 1)将front指示的元素取出。
2)front = front + 1队头指针加一
2.顺序队列的类型定义

#define MAXLEN 100
typedef struct
{datatype Q[MAXLEN];
int front=0;
int rear=0;
} SeqQueue,*P;

问:什么叫“假溢出” ?如何解决?
答:在顺序队中,当尾指针已经到了数组的上界,不能再有入队操作,但其实数组中还有空位置,这就叫“假溢出”。
解决假溢出的途径———采用循环列队

循环队列

想象为一个首尾相接的圆环,并称这种向量为循环向量,存储在其中的队列称为循环队列。

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_循环队列操作的实现

新问题:在循环队列中,空队特征是Q.front=Q.rear;队满时也会有Q.front=Q.rear;判决条件将出现二义性!
解决方案有三:
①使用一个计数器记录队列中元素个数(即队列长度);
②加设标志位,删除时置1,插入时置0,则可识别当前Q.front=Q.rear属于何种情况
③ 人为浪费一个单元,则队满特征可改为Q.front=(Q.rear+1)%MAXLEN;

实际中常选用方案3(人为浪费一个单元):
即front和rear二者之一指向实元素,另一个指向空闲元素。

队空条件 :  Q.front =Q. rear       (初始化时:Q.front = Q.rear )
队满条件: Q.front = (Q.rear+1) % N (N=maxsize)
队列长度(即数据元素个数):L=(N+Q.rear-Q.front)% N

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_链队列结构_02


例1:数组Q[n]用来表示一个循环队列,f 为当前队列头元素的前一位置,r 为队尾元素的位置。假定队列中元素的个数小于n,计算队列中元素的公式为:

A) r-f (B)(n+f-r)% n

(C)n+r-f (D) (n+r-f)% n

要分析4种公式哪种最合理?

当 r ≥f 时(A)合理;

当 r < f 时(C)合理; 综合2种情况,以(D)的表达最为合理

例2:在一个循环队列中,若约定队首指针指向队首元素的前一个位置。那么,从循环队列中删除一个元素时,其操作是 先 移动队首指针,后取出元素

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_顺序队列的类型定义_03


c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_循环队列操作的实现_04

怎样构成循环队列?
在循环队列中进行出队、入队操作时,头尾指针仍要加1,朝前移动。
只不过当头尾指针指向向量上界(MAXLEN-1)时,其加1操作的结果是指向向量的下界0。
加1操作的结是指向向量的下界0的办法

*(front+1)%M       (rear+1)%M*

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_循环队列操作的实现_05

队空:Q.front =Q. rear
队满:Q.front =(Q.rear + 1) % MAXLEN
入队: Q.rear = (Q.rear + 1) % MAXLEN
出队: Q.front = (front + 1) % MAXLEN;
求队长:(Q.rear-Q.front+ MAXLEN)% MAXLEN

- 3)循环队列的类型定义

#define MAXLEN 100
typedef struct
{datatype *data[MAXLEN];
int front;
int rear;
int n;/*判队空,队满的另一方法*/
} CseqQueue

- 4)循环队列操作的实现

①初始化队列

CseqQueue * IniQueue (CseqQueue *Q) 
{ //构造空队列
Q= (CseqQueue *) malloc(sizeof(CseqQueue ));
Q->rear = Q->front = 0;
return Q;
}

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_顺序队列的类型定义_06


②判队空

int QueueEmpty (CseqQueue *Q ) 
{
return(Q->rear == Q->front);
}

③判队满

int QueueFull (CseqQueue *Q ) 
{
return((Q->rear+1) % MAXLEN == Q->front);
}

④判队满

int QueueFull (CseqQueue *Q ) 
{
return( (Q->n) == MAXLEN);
}

⑤入队

int InQueue (CseqQueue *Q, datatype x ) 
{
if (QueueFull (Q) )
return 0;
else
{Q->data[Q->rear] = x;
Q->rear = ( Q->rear+1) % MAXLEN;
Q->n++;
return 1;
}
}

⑥出队

int DeQueue (CseqQueue *Q, datatype *x ) 
{
if ( QueueEmpty (Q) )
return 0;
else
{*x = Q->data[Q->front];
Q->front = ( Q->front+1) % MAXLEN;
Q->n--;
return 1;
}
}

⑦取队头

int GetFront (CseqQueue *Q, datatype *x ) 
{
if ( QueueEmpty (Q) )
return 0;
*x = Q->data[Q->front];
return 1;
}

⑧求队列长度

int QueueLength (CseqQueue  *Q)
{
return( (Q->rear – Q->front + MAXSIZE) % MAXSIZE);
}

链队列结构

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_顺序队列的类型定义_07

**

链队列示意图

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_链队列结构_08


(2)链队列的描述

和顺序队列类似,我们也是将这两个指针封装在一起,将链队列的类型LinkQueue定义为一个结构类型:

typedef struct queuenode
{ datatype data;
struct queuenode *next;
}queuenode;
typedef struct
{ queuenode *front;
queuenode *rear;
}Linkqueue;

3)链队列上实现的基本运算
1)构造一个空队列(带头结点空队列)

  void initqueue(Linkqueue  *q)
{ q.front=(queuenode *)malloc(sizeof(queuenode));
q.rear=q.front
q.front->next=q.rear->next= NULL;
}

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_顺序队列的类型定义_09


2)入队操作

c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_循环队列操作的实现_10


入队操作算法

void inqueue(Linkqueue  *q,datatype  x)
{queuenode *p
p=(queuenode * )malloc(sizeof(queuenode));
p–>data=x;
p–>next=NULL;
q.rear–>next=p;
q.rear=p;
}

3)队列的判空

int queueempty(Linkqueue  *q)
{
return (q.front->next= =NULL &&
q.rear->next= =NULL);
}
  1. 出队操作
  2. c语言 队列定义.顺序队列,循环队列,链队列结构(详细的)_顺序队列的类型定义_11

  3. 4)出队操作算法
Datatype dequeue(Linkqueue *q)
{ datatype x;
queuenode *p
if(queueempty(q))
{ printf(“队列为空”); return;}
p=q.front–>next;
x=p–>data;
q.front–>next=p–>next;
if(q.rear = =p) /删除的是尾结点/
q.rear=q.front;
free§;
return x;
}

有什么问题请留言 会及时修改的