赞
踩
队列:也是一种受到限制的线性表,一端进行入队,另一端进行出队,我们将入队的一端一般称作队尾,另一端称作队头。
特点:先进先出。
那么顺序表实现的队列为什么叫做循环队列?
关于循环队列队列的三个难点:
第一个难点:怎么让队列也可以实现入队和出队的时间复杂度都是O(1)?
最开始这是由顺序表实现的一个队列,里面的数据为1到5。
我们将6入队,会发现入队的时间复杂度为O(1),只需将6放在5号下标的格子位置。
如果将1出队,那么我们需要将0号下标位置里的1删除,还要将后边的数据依次向前移一个格子,这个时候时间复杂度为O(n),因为需要移动数据。
那应该怎么办呢?这个时候就需要一个队头指针和一个队尾指针,队尾指针指向的是下一个存放数据的位置。
解决办法:想象成环形,让数据不动,指针动。
比如将1出队,我们只需要将0号下标位置里的元素删除,然后再将队头指针指向1号下标的位置。
同时我们还要将它想象成一个环状,如果2到9号下标都有元素,0号和1号下标位置为空,此时,队头指针在2号下标位置,但该队列并没有满(因为0号和1号下标),我们把它想象成环状,这个时候就可以将队尾指针指向0号下标,又可以入队。
注意:这个循环只是一个概念,真是并不存在!
第二个难点:在第一个解决问题的基础上,会发现一个BUG,判空和判满条件一致(队头指针==队尾指针),怎么将其区分开?
队列为空时队头指针和队尾指针都指向同一个位置,队列满的时候也是相同情况(队头指针==队尾指针)
这里给出两种解决方案:
第一种:加上一个计数器cout(保存有效值个数)
队头指针==队尾指针&&cout==0(判空)
队头指针==队尾指针&&cout!=0(判满)
第二种:在队尾处:浪费一个空间不用,这个浪费的空间不在存储有效值,而是当做一个标记位
一般来说我们用第二种办法,这里的代码也是第二种办法。
第三个难点:怎么求有效长度?
这里记住公式:length=(rear-front+MAX_SIZE)%MAX_SIZE
rear(队尾指针),front(队头指针),MAX_SIZE(可以理解为格子数),此指针非彼指针。
循环队列结构体设计:
- // 循环队列结构体设计:
- typedef int ELEM_TYPE;
- typedef struct Queue
- {
- ELEM_TYPE* data;//这个指针用来接收malloc从堆里申请的数组
- int front;//队头指针(实际上保存的是数组下标,int)
- int rear;//队尾指针 (实际上保存的是数组下标,int)
- }Queue,*PQueue;
循环队列可执行函数声明:
- //初始化
- void Init_queue(PQueue pq);
-
- //入队
- bool Push(PQueue pq, ELEM_TYPE val);
-
- //出队(还要获取出队的值,需要借助一个输出参数rtval)
- bool Pop(PQueue pq, ELEM_TYPE* rtval);
-
- //获取队头值
- bool Top(PQueue pq, ELEM_TYPE* rtval);
-
- //判空
- bool IsEmpty(PQueue pq);
-
- //判满
- bool IsFull(PQueue pq);
-
- //获取有效长度
- int Get_length(PQueue pq);
-
- //查找
- int Search(PQueue pq, ELEM_TYPE val);
-
- //清空
- void Clear(PQueue pq);
-
- //销毁
- void Destroy(PQueue pq);
-
- //打印
- void Show(PQueue pq);
代码:
先设立一个宏
#define MAX_SIZE 100
初始化:
- //初始化
- void Init_queue(PQueue pq)
- {
- assert(pq!= NULL);
- pq->data = (ELEM_TYPE*)malloc(sizeof(ELEM_TYPE) * MAX_SIZE);
- assert(pq->data != NULL);
- pq->front = pq->rear = 0;
- }
入队:
- bool Push(PQueue pq, ELEM_TYPE val)
- {
- assert(pq != NULL);
- if (IsFull(pq))//判满
- {
- return false;
- }
-
- pq->data[pq->rear] = val;
- //pq->rear++;//error
- pq->rear = (pq->rear + 1) % MAX_SIZE;
-
- return true;
- }
注意,这里的队尾指针不可以通过++方式向后移,而是pq->rear = (pq->rear + 1) % MAX_SIZE;
出队:
- //出队(还要获取出队的值,需要借助一个输出参数rtval)
- bool Pop(PQueue pq, ELEM_TYPE* rtval)
- {
- assert(pq != NULL);
- assert(rtval != NULL);
- if (IsEmpty(pq))//判空,如果空,返回假
- {
- return false;
- }
- *rtval = pq->data[pq->front];
- //pq->front++;//error
- pq->front = (pq->front + 1) % MAX_SIZE;
- return true;
- }
获取队头值
- //获取队头值
- bool Top(PQueue pq, ELEM_TYPE* rtval)
- {
- assert(pq != NULL);
- assert(rtval != NULL);
- *rtval = pq->data[pq->front];
- return true;
- }
判空,判满,获取有效长度,查找
- //判空
- bool IsEmpty(PQueue pq)
- {
- assert(pq != NULL);
- return pq->rear == pq->front;
- }
-
- //判满
- bool IsFull(PQueue pq)
- {
- assert(pq != NULL);
- return pq->front == (pq->rear + 1) % MAX_SIZE;
- }
-
- //获取有效长度
- int Get_length(PQueue pq)
- {
- assert(pq != NULL);
- return (pq->rear - pq->front + MAX_SIZE) % MAX_SIZE;
- }
-
- //查找
- int Search(PQueue pq, ELEM_TYPE val)
- {
- assert(pq != NULL);
- for (int i = pq->front; i != pq->rear; i = (i + 1) % MAX_SIZE)
- {
- if (pq->data[i] == val)
- {
- return i;
- }
- }
-
- return -1;
- }
清空,销毁,打印
- //清空
- void Clear(PQueue pq)
- {
- assert(pq != NULL);
- pq->front = pq->rear = 0;
- }
-
- //销毁
- void Destroy(PQueue pq)
- {
- assert(pq != NULL);
- free(pq->data);
- pq->data = NULL;
- pq->front = pq->rear = 0;
- }
-
- //打印
- void Show(PQueue pq)
- {
- assert(pq != NULL);
- for (int i = pq->front; i != pq->rear; i=(i + 1) % MAX_SIZE)
- {
- printf("%d ", pq->data[i]);
- }
- printf("\n");
- }
测试:
- int main()
- {
- Queue head;//建立一个循环队列
- Init_queue(&head);//初始化
-
- for(int i=0; i<20; i++)//将1到20进队
- {
- Push(&head, i+1);
- }
- Show(&head);//打印
-
- ELEM_TYPE tmp;
- Pop(&head, &tmp);//出队
- printf("pop = %d\n", tmp);//打印出队的值
- Show(&head);//打印出队后的队列
- printf("length = %d\n", Get_length(&head));//打印队列有效长度
-
- ELEM_TYPE flag;
- Top(&head, &flag);//获取队头元素
- printf("top = %d\n", flag);//打印队头元素
- Show(&head);//打印队列,没有出队
- printf("length = %d\n", Get_length(&head));//打印有效长度
-
- Clear(&head);//清空
- Show(&head);//打印
- printf("length = %d\n", Get_length(&head));//打印有效长度
-
- Destroy(&head);//销毁
- return 0;
- }
结果:没有内存泄漏!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。