这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战
顺序队列的基本算法
1. 初始化一个队列
void INITIALQ(int &front, int &rear) // ※
{
front = -1;
rear = -1;
}
2. 判断队列是否为空
int EMPTYQ(int front, int rear) // ※
{
return front === rear;
}
3. 获取当前队头元素 ※
- 判断队列是否为空
- 获取当前队头元素赋值给item
该操作不改变队头指针的位置
int GETQ(QElemType QUEUE[], int front, int rear, QElemType &item)
{
if(EMPTYQ(front, rear))
return 0; // 队列为空,操作失败,返回0
else {
item = QUEUE[font + 1]; // 取出队头元素赋值给变量item
return 1; // 队列非空,操作成功,返回1
}
}
4. 队列的插入(进队) ※
在容量为M的队列中插入一个新的元素item
- 判断上溢条件,如果产生溢出,则返回0,表示插入失败
- 先将队尾指针rear加1,然后将新的元素item插入到
修改之后的rear指出的新的队尾位置上,返回1,表示插入成功
int ADD(QElemType QUEUE[], int &rear, QElemType item)
{
if (rear == M - 1)
return 0; // 队列已满,插入失败,返回0
else {
QUEUE[++rear] = item;
return 1; // 队列未满,插入成功,返回1
}
}
5. 队列的删除(出队) ※
从队列中退出当前队头元素,并保存在变量item中
- 判断队列是否为空队,若为空,返回0,删除失败
- 将要删除的队头元素需要用到的话,将其保存在变量item中,队头指针front加1,返回1,删除成功
所谓删除,并不是把队头元素从原存储位置上物理地删除,只是将队头指针向队尾方向移动一个位置,这样,原来的那个队头元素就认为不再包含在队列中了。
int DELQ(QElemType QUEUE[], int &front, int rear, QElemType &item)
{
if (EMPEYQ(front, rear))
return 0; // 队列为空,删除失败,返回0
else {
item = QUEUE[++front]; // 保存队头元素
return 1; // 队列非空,删除成功,返回1
}
}
上面5个算法的实际复杂度均为O(1)
循环队列
在队列的插入算法中,QUEUE[0]~QUEUE[M-1]都被占用时,有rear = M - 1,若次数在进行插入操作会提示产生溢出的信息。 队列出现的问题:假溢出
- 每次总是删除当前的队头元素,插入操作是在队尾进行
- 当队尾指针rear = M - 1时,队列的前端可能还有许多由于此前进行了删除操作而产生的空的(可用的)位置
解决假溢出问题的办法之一是:每次删除队头的1个元素后,就把整个队列往前(往左)移动1个位置
算法修改为:
int DELQ(QElemType QUEUE[], int &rear, QElemType &item)
{
if (rear == -1)
return 0; // 队列为空,删除失败,返回0
else {
item = QUEUE[0]; // 保存队头元素
for (i = 0; i < rear; i++) {
QUEUE[i] = QUEUE[i + 1];
}
return 1; // 队列非空,删除成功,返回1
}
}
这种方法效率极低,不可取:时间复杂度较大分析,出现了循环,为了节省存储空间而白白浪费了大量的时间
另一种办法是:在初始化队列时,令front = rear = 0,并且把队列设想称为头尾相连的循环表,使得空间可以重复使用——这就是
循环队列
- 进行插入操作时,当队列的第M个位置(数组下标为M-1)被占用以后,只要队列还用可用空间,新的元素加入队列时就可以从第1个位置(数组下标为0)开始。 插入算法中修改队尾指针的语句可修改为:
if (rear == M-1)
return 0;
else
rear ++;
修改后的队尾指针满足rear == front,则产生溢出.
- 上述算法采用“求模”运算,则可以改为更简单的赋值语句,效果完全相同
rear = (rear + 1) % M
删除算法中有:
front = (front + 1) % M
循环队列的插入 ※
int ADDCQ(QElemType QUEUE[], int front, int &rear, QElemType item)
{
if ((rear + 1) % M == front) // ※
return 0; // 循环队列已满,插入失败,返回0
else {
QUEUE[++rear % M] = item; // ※
return 1; // 循环队列未满,插入成功,返回1
}
}
循环队列的删除
int DELCQ(QElemType QUEUE[], int &front, int rear, QElemType &item)
{
if (front == rear)
return 0; // 循环队列为空,删除失败,返回0
else {
front = (front + 1) % M; // ※
item = QUEUE[front]; // ※
return 1; // 循环队列为空,删除成功,返回1
}
}