您的位置:首页 > 其它

循环队列的顺序存储

2016-03-20 10:57 351 查看
在学习队列的过程中,我积累了一些更好的分析问题的方法,现加以总结,如下:

1.对于队列的顺序存储结构,如果要将第一个元素存在数组的第一个位置,则之后在插入和删除时平均要移动n个元素,时间复杂度为O(n);细细想来,其实不把第一个元素放在第一个位置上也可以,这种方案不仅仅是增强了灵活性,更重要的是它解决了插入删除过程中移动n个元素的问题;由于第一个元素不需要在第一个位置上,队首指针和队尾指针的前后顺序并没有明确的规定(或者说队首指针不一定要在队尾指针的前面) 每当队尾指针到队尾时,就让队尾指针重新回到队首,如果队首还有空间就让新数据存入队首的空间中;这样能够避免因队尾指针到末端无空间后(实际上前端还有空间)造成的”假溢出”现象;

那么队尾指针循环移动是如何做到的呢?答案十分巧妙:rear=(rear+1)%maxsize;

2.循环队列如何判断队列已满呢?;我想到的第一种方法:队首指针==队尾指针且不为0。但细想之后发现不妥,既然队首指针不一定要在队尾指针的前面,那么队首==队尾时也不一定意味着满队列;在参阅书籍之后,我发现了一种巧妙地办法:当队列满时,保留一个元素空间。

那么如何用C语言实现呢,如下:(rear+1)%maxsize==front;

3.第三个问题,循环队列在带来了诸多的好处的同时,由于其指针的灵活性与不确定性,其长度变得难以求解;下面给出循环队列长度公式length=(rear-front+maxsize)%maxsize

有了上述三点,循环队列就变得十分容易处理且便于使用了;

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define maxsize 20
typedef int status;
typedef int elemtype;

/*定义队列*/
typedef struct queue{
elemtype data[maxsize];
int front;//定义队首指针
int rear;//定义队尾指针
}queue;

status visit(elemtype c){
printf("%d ",c);
return OK;
}

/*初始化队列*/
status initqueue(queue *Q){
Q->front=0;/*让队首队尾指针全部为0,为空队列状态*/
Q->rear=0;
return OK;
}

/*判断队列是否为空*/
status emptyqueue(queue *Q){
if(Q->front==Q->rear)/*队列为空的条件是Q->front==Q->rear,而队列满的条件是(Q->rear+1)%maxsize==Q->front*/
printf("空队列\n");
}

/*返回队列长度*/
status queuelength(queue *Q){
return (Q->rear-Q->front+maxsize)%maxsize;/*此为队列长度计算公式*/
}

/*判断是否满队列*/
status fullqueue(queue *Q){
if((Q->rear+1)%maxsize==Q->front){/*队列满的条件是(Q->rear+1)%maxsize==Q->front,意思是rear和front只差1个单位*/
return TRUE;
}
else{
return FALSE;
}
}

/*入队列*/
status enterqueue(queue *Q,elemtype data){
if((Q->rear+1)%maxsize==Q->front){
printf("队列已满\n");
return ERROR;
}
Q->data[Q->rear]=data;/*把元素赋值给Q->data数组,同时队尾指针后移*/
Q->rear=(Q->rear+1)%maxsize;/*此处不写Q->rear++的原因是:如果队首指针不在队列开始处,容易造成队首还有若干个空间而却误认为队列已满
,形成"假溢出”*/
return OK;
}

status exitqueue(queue *Q,elemtype data){
if(Q->front==Q->rear){
printf("空队列\n");
return ERROR;
}
data=Q->data[Q->front];/*出队列时从队首指针指向的元素开始*/
printf("%d ",data);
Q->front=(Q->front+1)%maxsize;/*队首指针后移,若队首指针在队尾指针之后(存在此种可能,切记!!),则在越过队列末端后
重新回到队列首端*/
}

status traversequeue(queue *Q){
int i=Q->front;
while(i!=Q->rear){/*用于判断是否达到了队列末端*/
visit(Q->data[i]);
i=(i+1)%maxsize;
}
return OK;
}

int main(void){
queue Q;
elemtype e;
initqueue(&Q);
emptyqueue(&Q);

printf("队列长%d\n",queuelength(&Q));

printf("入队列 ");
for(int i=0;i<maxsize-1;i++){
enterqueue(&Q,i);
}
traversequeue(&Q);
printf("\n");

printf("删除队列首端两个元素\n");
for(int i=0;i<2;i++){
exitqueue(&Q,e);
}
printf("\n");

printf("出队列:");
for(int i=0;i<maxsize-3;i++){
exitqueue(&Q,e);
}
printf("\n");

printf("队列长为%d\n",queuelength(&Q));

initqueue(&Q);
printf("清空队列后,");

emptyqueue(&Q);

printf("队列长为%d\n",queuelength(&Q));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: