数据结构与算法实战 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 }