【数据结构--队列】

队列的逻辑结构

队列(queue)是只允许在一端进行插入操作,在另一端进行删除操作的线性表,允许插入(也称入队、进队)的一端称为队尾(queue-tail),允许删除(也称出队)的一端称为队头(queue-head)。

如图是一个有5个元素的队列,入队的顺序为a1,a2,a3,a4,a5,出队的顺序依然是a1,a2,a3,a4,a5,即最先入队者最先出队。所以队列中的元素除了具有线性关系外,还具有先进先出(first in first out)的特性。
在这里插入图片描述

顺序队列的存储结构

队列的顺序存储结构称为顺序队列(sequential)。假设队列有n个元素,顺序队列把所有元素存储在数组的前n个单元。如果把队头元素放在数组中下标为0的一端,则入队操作相当于追加,不需要移动元素,其时间性能为O(1);但出队操作的时间性能为O(n),因为要保证剩下的n-1个元素仍然存储在数组的前n-1个单元,所有元素都要向前移动一个位置。
在这里插入图片描述
如果放款队列的所有元素必须存储在数组的前n个单元这一条件,就可以得到一种更为有效的存储方法,如上图最后一个结构所示。此时入队和出队操作的时间性能都是O(1),因为没有移动任何元素,但是队头和队尾都是活动的,因此需要设置队头、队尾两个位置变量front和rear,入队时rear加1,出队时front加1.并且约定:front指向队头元素的前一个位置,rear指向队尾元素的位置。

循环队列的存储结构及实现

在顺序队列中,随着队列的插入和删除操作,整个队列向数组的高端移过去,从而产生了队列的“单向移动性”。当元素被插入到数组下标最大的位置之后,数组空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出(false overflow)。

解决假溢出的方法是将存储队列的数组看成是头尾相接的循环结构,即允许队列直接从数组中下标最大的位置延续到下标最小的位置。这可以通过取模操作来实现,设存储队列的数组长度为QueueSize,操作语句为rear = (rear + 1) % QueueSize。队列的这种头尾相接的顺序存储结构称为循环队列(circular queue)。

循环队列如何判定队空和队满

如下图(a)和图©所示,队列中只有一个元素,执行出队操作,则队头位置在循环意义下加1后与队尾位置相等,即队空的条件是front = rear
在这里插入图片描述
如下图(a)和图©所示,数组中只有一个空闲单元,执行入队操作,则队尾位置在循环意义下加1后与队头位置相等,即队满的条件也是front = rear
在这里插入图片描述
这样如何区分队空和队满的情况呢,可以浪费一个数组元素的空间,把图(a)和图©的情况视为队满,此时队尾位置和队头位置正好相差1,即队满的条件是 **(rear + 1) % QueueSize = front **

循环队列的实现

循环队列的类定义
const int QueueSize = 100;
template <typename DataType>
class CirQueue{
public: 
    CirQueue();                 //构造函数,初始化空队列
    ~CirQueue();                //析构函数
    void EnQueue(DataType x);   //入队操作,将元素x入队
    DataType DeQueue();         //出队操作,将元素x出队
    DataType GetHead();         //取队头元素,并不删除
    int Empty();                //判断队列是否为空
private:
    DataType data[QueueSize];   //存放队列元素的数组
    int front, rear;            //游标,队头指针和队尾指针
};
成员函数的实现
template <typename DataType>
CirQueue<DataType>::CirQueue(){
    //初始化一个空的循环队列只需将队头front和队尾rear同时指向数组的某一个位置,一般是数组的高端
    rear = front = QueueSize - 1;
}

template <typename DataType>
void CirQueue<DataType>::EnQueue(DataType x){
    if((rear + 1) % QueueSize == front)
        throw "上溢";
    rear = (rear + 1) % QueueSize;
    data[rear] = x;
}

template <typename DataType>
DataType CirQueue<DataType>::DeQueue(){
    if(rear == front)
        throw "下溢";
    front = (front + 1) % QueueSize;
    return data[front];
}

template <typename DataType>
DataType CirQueue<DataType>::GetHead(){
    if(rear == front)
        throw "下溢";
    return data[(front + 1) % QueueSize];
}

template <typename DataType>
int CirQueue<DataType>::Empty(){
    return front == rear;
}

队列的连接存储结构及实现

队列的连接存储结构称为链队列(linked queue),通常用单链表表示,其结点结构与单链表的结点结构相同。为了使空队列和非空队列的操作一致,链队列也加上头结点。根据队列的先进先出特性,为了操作上的方便,设置队头指针指向链队列的头结点,队尾指针指向终端节点。
在这里插入图片描述

链队列的实现

链队列的类定义
template <typename DataType>
struct Node{
    DataType data;
    Node<DataType> *next;
};

template <typename DataType>
class LinkQueue{
public:
    LinkQueue();                    //初始化空的链队列
    ~LinkQueue();                   //释放链队列的存储空间
    void EnQueue(DataType x);       //入队操作,将元素x入队
    DataType DeQueue();             //出队操作,将队头元素出队
    DataType GetHead();             //取链队列的队头元素
    int Empty();                    //判断链队列是否为空
private:
    Node<DataType> *front, *rear;   //队头和队尾指针
};
成员函数的实现
template <typename DataType>
LinkQueue<DataType>::LinkQueue(){
    Node<DataType> *s = nullptr;
    s = new Node<DataType>;
    s->next = nullptr;
    front = rear = nullptr;
}

template <typename DataType>
LinkQueue<DataType>::~LinkQueue(){
    Node<DataType> *p;
    while(front!=nullptr){
        p = front;
        front = front->next;
        delete p;
    }
}

template <typename DataType>
void LinkQueue<DataType>::EnQueue(DataType x){
    Node<DataType> *s = nullptr;
    s = new Node<DataType>;
    s->data = x;
    s->next = nullptr;
    rear->next = s;
    rear = s;
}

template <typename DataType>
DataType LinkQueue<DataType>::DeQueue(){
    DataType x;
    Node<DataType> *p = nullptr;
    if(rear == front)
        throw "下溢";
    p = front->next;
    x = p->data;
    front->next = p->next;
    if(p->next == nullptr)
        rear = front;
    delete p;
    return x;
}

template <typename DataType>
DataType LinkQueue<DataType>::GetHead(){
    DataType x;
    Node<DataType> *p = nullptr;
    if(rear == front)
        throw "下溢";
    p = front->next;
    x = p->data;
    return x;
}

template <typename DataType>
int LinkQueue<DataType>::Empty(){
    return front == rear;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值