数据结构整理-队列(双向)篇

本文详细介绍了双向队列的工作原理,展示了在不同编程语言中如何使用内置或自定义双向队列进行操作,包括数组和链表两种实现方式,以及相应的入队、出队、访问元素等方法。
摘要由CSDN通过智能技术生成

单向队列仅能从队列的头部删除元素、在队列的尾部添加元素。与其相比,双向队列的灵活性更好,可以在头尾执行元素的添加或删除。

一般编程语言中有已实现的双向队列,双向队列的一般操作有:

注意:上面的方法名不一定是双向队列的正确的成员函数名,只是便于理解。

使用编程语言内部的双向队列有以下代码:

    //初始化双向队列
    deque<int> deque;

    //入队
    deque.push_back(2);//队尾加入元素
    deque.push_back(3);
    deque.push_front(7);//队首加入元素
    deque.push_front(8);

    //此时双向队列:8 7 2 3

    //访问双向队列的元素
    int front =deque.front();//队首元素
    int back = deque.back();//队尾元素

    //元素出队
    deque.pop_front();//队首元素出队,此时双向队列:7 2 3
    deque.pop_back();//队尾元素出队,此时双向队列: 7 2

    //获取双向队列的长度
    int size=deque.size();

    //判断双向队列是否为空
    bool empty = deque.empty();

双向队列的实现与队列比较类似,同样可以使用数组或者链表实现底层数据结构。

1.基于数组的实现


class ArrayDeque{
 private:
    vector<int> nums;//储存双向队列的数组
    int front;//队首指针,指向队首元素
    int queSize;//双向队列的长度

 public:
    //构造函数,初始化双向队列
    ArrayDeque(int capacity){
        nums.resize(capacity);//由于本数组使用的内置动态数组,直接使用成员函数初始化数组容量
        front = queSize=0;
    }

    //析构函数不再需要,因为内置动态数组一般内存会自动释放,手动开辟的数组空间需要手动释放

    //获取双向队列的容量(容量是最大可以存多少个元素)
    int capacity(){
        return nums.size();
    }

    //获取双向队列的长度(长度是目前存了多少元素)
    int size(){
        return queSize;
    }

    //判断双向队列是否为空
    bool isEmpty(){
        return queSize==0;
    }

    //计算环形数组的索引
    int index(int i){
        //通过取余操作实现数组首尾相连
        //当i越过数组尾部后,回到头部
        //当i越过数组头部后,回到尾部
        return (i+capacity())%capacity();
    }

    //队首入队
    void pushFirst(int num){
        if(queSize==capacity()){
            cout<<"双向队列已满"<<endl;
            return;
        }
        //队首指针向左移动一位
        //通过取余操作实现front越过数组头部回到数组尾部
        front = index(front - 1);
        //将num添加至队首
        nums[front]=num;
        queSize++;
    }

    //队尾入队
    void pushLast(int num){
        if(queSize==capacity()){
            cout<<"双向队列已满"<<endl;
            return;
        }
        //队尾指针向右移动一位
        int rear = index(front+queSize);
        //将num添加至队尾
        nums[rear]=num;
        queSize++;
    }


    //获取队首元素
    int peekFirst(){
        if(isEmpty()) throw out_of_range("双向队列是空");
        return nums[front];
    }

    //获取队尾元素
    int peekLast(){
        if(isEmpty()) throw out_of_range("双向队列是空");
        //计算队尾元素索引
        int last =index(front+queSize-1);
        return nums[last];
    }

    //队首出队
    int popFirst(){
        int  num=peekFirst();

        //队首元素向右移动一位
        front=index(front+1);

        queSize--;
        return num;
    }

    //队尾出队
    int popLast(){
        int num=peekLast();
        queSize--;
        return num;
    }

    //返回数组用于打印
    vector<int> toVector(){
        //仅转换有效长度范围内的队列元素
        vector<int> res(queSize);
        for(int i =0, j=front;i<queSize;i++,j++){
            res[i]=nums[index(j)];
        }
        return res;
    }

};

2.基于双向链表实现

struct DoublyListNode{
    int val;
    DoublyListNode* next;
    DoublyListNode* prev;
    DoublyListNode(int val): val(val),prev(nullptr),next(nullptr){}
};

//基于双向链表实现的双向队列
class LinkedListDeque{
 private:
 DoublyListNode *front, *rear;//头节点front,尾节点rear
 int queSize=0;

 public:
 //构造函数
 LinkedListDeque(): front(nullptr),rear(nullptr){}

 //析构函数
 ~LinkedListDeque(){
    //遍历链表,删除节点,释放内存
    DoublyListNode* pre, *cur=front;
    while(cur!=nullptr){
        pre=cur;
        cur=cur->next;
        delete pre;
    }
 }

 //获取双向队列的长度
 int size(){
    return queSize;
 }

 //判断双向队列是否为空
 bool isEmpty(){
    return size()==0;
 }

 //入队操作
 void push(int num, bool isFront){
    DoublyListNode *node=new DoublyListNode(num);
    //若链表为空,则令front和rear都指向node
    if(isEmpty()) front = rear = node;

    //队首入队操作
    else if (isFront){
        //将node添加至链表头部
        front->prev=node;
        node->next=front;
        front=node;//更新头节点
    }else{
         //队尾入队操作
         //将node添加至链表尾部
         rear->next=node;
         node->prev=rear;
         rear=node;//更新尾节点
    }
    queSize++;//更新队列长度
 }


 //队首入队
 void pushFirst(int num){
    push(num,true);
 }

 //队尾入队
 void pushLast(int num){
    push(num,false);
 }


 //出队操作
 int pop(bool isFront){
    if(isFront) throw out_of_range("队列为空");
    int val;

    //队首出队操作
    if(isFront){
        val=front->val;//暂存头节点值
        //删除头节点
        DoublyListNode* fNext = front->next;
        if(fNext!=nullptr){
            fNext->prev=nullptr;
            front->next=nullptr;
        }
        delete front;
        front=fNext;//更新头节点;

    }else{
        //队尾出队操作
        val=rear->val;//暂存尾节点值
        //删除尾节点
        DoublyListNode *rPrev=rear->prev;
        if(rPrev!=nullptr){
            rPrev->next=nullptr;
            rear->prev=nullptr;
        }
        delete rear;
        rear=rPrev;//更新尾节点

    }
    queSize--;//更新队列长度
    return val;
 }
 //队首出队
 int popFirst(){
    return pop(true);
 }

 //队尾出队
 int popLast(){
    return pop(false);
 }

 //访问队首元素
 int peekFirst(){
    if(isEmpty()) throw out_of_range( " 双向队列为空");
    return front->val;
 }

 //访问队尾元素
 int peekLast(){
     if(isEmpty()) throw out_of_range( " 双向队列为空");
    return rear->val;
 }

 //返回数组用于打印
 vector<int> toVector(){
    DoublyListNode* node=front;
    vector<int> res(size());
    for(int i=0;i<res.size();i++){
        res[i]=node->val;
        node=node->next;
    }
    return res;
 }
};

声明:本人所写内容全部参考hello-algo,仅用于个人复习。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值