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;
问:什么叫“假溢出” ?如何解决?
答:在顺序队中,当尾指针已经到了数组的上界,不能再有入队操作,但其实数组中还有空位置,这就叫“假溢出”。
解决假溢出的途径———采用循环列队
循环队列
想象为一个首尾相接的圆环,并称这种向量为循环向量,存储在其中的队列称为循环队列。
新问题:在循环队列中,空队特征是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
例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:在一个循环队列中,若约定队首指针指向队首元素的前一个位置。那么,从循环队列中删除一个元素时,其操作是 先 移动队首指针,后取出元素。
怎样构成循环队列?
在循环队列中进行出队、入队操作时,头尾指针仍要加1,朝前移动。
只不过当头尾指针指向向量上界(MAXLEN-1)时,其加1操作的结果是指向向量的下界0。
加1操作的结是指向向量的下界0的办法
队空: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;
}
②判队空
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);
}
链队列结构
**
链队列示意图
(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;
}
2)入队操作
入队操作算法
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);
}
- 出队操作
- 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;
}
有什么问题请留言 会及时修改的