数据结构与算法实战 3.31.顺序队列 (青岛大学 周强)

  1 /*队列,在两端进行操作,入队enQueue,出队deQueue,查看队首元素front
  2 有顺序队列和链式队列,顺序队列通常使用循环队列,为什么?
  3 因为用数组实现队列的时候,当一个元素进行出队操作,该位置将不再能使用,会造成空间的浪费。
  4 
  5 那么如何初始化循环队列,画图画一个圆形来分析。
  6 1.当front和rear都是0开始的时候,入队:rear ++,因为front指向队首,所以rear往后面指,指向队尾元素的后一个位置
  7   当队列满的时候,front和rear又同时指向了0号元素,例如6个元素的队列,当5号位置进入的时候,rear+1
  8   (注意这里的是循环+1找下一个位置,而不是数值上的+1,要通过取余实现),此时,我们无法通过rear和front区分队列的空和满的状态
  9   那么我们就有两个办法:第一:把5号位置空着,不能放东西,即rear如果再往下一个位置的时候就是0的时候为满
 10                       第二:有时候我们队列中存放的每个东西占用空间很大,空着一个的话会有一点浪费,
 11                             此时,我们可以给队列增加一个计数器size,去计算是否满了。
 12 2.front = 0, rear = 0的前一个元素(循环里的前一个),入队的时候操作照旧rear+1(循环的+1,比如6个元素,5号位置+1 = 0号位置)
 13 这就相当于我们栈中的top = 0和top = -1了,当top = 0的时候,top指向的是栈顶元素的前一个空格位置,当top = -1的时候,top指向的就是栈顶元素
 14 
 15 
 16 链式队列
 17 因为我们可能并不知道有多少元素,链式队列可以不断去入队,比较方便
 18 由于多了指针域,所以相比较同等长度的顺序队列的话空间耗得更多一点
 19 由于单链表的操作基本都是从头到尾去进行的,而队列要操作队头和队尾,所以呢,我们要对链表进行改造
 20 用一个front指向表头,用一个rear指向表尾,[front|rear]
 21 A     ->       B      ->          C     ->        d
 22     \                                          /
 23      front             |                    rear
 24 这样的话,删除表头很容易,在表尾入队一个元素也不难
 25 如果反过来,a作为表尾,d作为表头,要删除表尾会变得很麻烦,要先找到B,然后修改B的指针域
 26 */
 27 
 28 #include<iostream>
 29 #include<cstdlib>
 30 
 31 struct  Queue
 32 {
 33     int *data;//为了创建时候动态分配大小
 34     int capacity;//容量
 35     int front;
 36     int rear;
 37     //int size; 该程序中使用front和rear的相对位置判断是否队满 所以不需要size了
 38 };
 39 
 40 void init(struct Queue *pq, int capacity){
 41     pq->capacity = capacity;
 42     //因为要用rear即将赶上front的时候判断为满,那么我们又要存放capacity个元素,所以要+1个空间给rear去指着
 43     pq-data = (int*)malloc(sizeof(int) * (capacity + 1));
 44     pq->front = pq->rear = 0;//也可以用一前一后的方式来初始化front rear,要注意初始化的不一样会导致后面的判断方式不一样
 45 }
 46 
 47 int isFull(const struct Queue *pq){//并不需要改变队列,只是查看,所以用了const的指针
 48     //比如0...5 当5是rear,再循环+1的时候就是0了,那么如何变成0,5 + 1 % 6 = 0
 49     if((pq->rear + 1) % (pq->capacity + 1)== pq->front) return 1;
 50     else return 0;
 51 
 52 }
 53 
 54 bool enQueue(struct Queue *pq, int data){
 55     //满队异常判断
 56     if(isFull(pq)) return 0;
 57     else{
 58         pq->data[pq->rear] = x;
 59         //这里的加1是循环加1 解释参照isFull里面
 60         pq->rear = (pq->rear + 1) % (pq->capacity + 1);
 61         return 1;
 62     }
 63 }
 64 
 65 int isEmpty(const struct Queue *pq){
 66     return pq->front == pq->rear;
 67 }
 68 
 69 int deQueue(struct Queue *pq, int *px){
 70     if(isEmpty(pq)) return 0;
 71     else{
 72         *px = pq->data[pq->front];//出队首
 73         pq->front = (pq->front + 1) % (pq->capacity + 1);//出队之后下一个元素为队首 所以要循环+1
 74         return 1;
 75     }
 76 }
 77 
 78 int main(){
 79     struct Queue q;
 80     init(&q, 5);//队列;容量
 81     enQueue(&q, 11);//哪个队列?;入队元素
 82     enQueue(&q, 22);
 83     enQueue(&q, 33);
 84     enQueue(&q, 44);
 85     enQueue(&q, 55);
 86     enQueue(&q, 66);
 87     int x;
 88     deQueue(&q, &x);//哪个队列?;出队元素
 89     printf("%d\n",x);
 90     deQueue(&q, &x);//哪个队列?;出队元素
 91     printf("%d\n",x);
 92     deQueue(&q, &x);//哪个队列?;出队元素
 93     printf("%d\n",x);
 94     deQueue(&q, &x);//哪个队列?;出队元素
 95     printf("%d\n",x);
 96     deQueue(&q, &x);//哪个队列?;出队元素
 97     printf("%d\n",x);
 98     deQueue(&q, &x);//哪个队列?;出队元素
 99     printf("%d\n",x);
100     return 0;
101 }

 

posted @ 2021-07-22 17:06  WriteOnce_layForever  阅读(142)  评论(0编辑  收藏  举报