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

队列是一种先入先出的数据结构,队列可以看作日常的排队,先到的现办理业务。

队列的常规操作:push/pop/front/back/empty/size

    queue<int> queue;
    queue.push(1);//入列
    queue.push(3);
    queue.push(5);
    queue.push(7);
    //此时队列为 1 3 5 7

    cout<<queue.front()<<endl;//队首元素访问
    
    queue.pop();//队首元素出列
    
    cout<<queue.back()<<endl;//队尾元素访问

    bool Empty=queue.empty();//队列是否为空

单项队列实现

队列实现必须具备一端加入元素,另一端删除元素的特征,数组和链表都具备这样的特性。

1.基于数组实现

由于数组删除首元素的时间复杂度是O(n),所以导致出队效率比较低,可以采用以下方式避免这个问题。

使用front指向队首元素的索引,使用size维护队列长度,定义rear=front+size,即rear是队尾元素的下一个位置索引。此时队列的有效元素全部在数组的有效区间[front, rear-1]内。

        入队: 元素赋值到索引为rear处,size加1;

        出队: front往下移动一位,即front++,同时size--;

此时,无论入队还是出队时间复杂度都是O(n)。

此时发现,无论是入队还是出队,front和rear都在往后移动,当达到数组尾部就无法移动了!因此使用环形数组(让front或rear越过数组尾部时,从头继续遍历)可以解决这个问题。

//基于数组实现的队列
class ArrayQueue{

private:
    int *nums;
    int queSize;
    int front;
    int queCapacity;

public:
    //构造函数初始化队列
    ArrayQueue(int capacity){
        front=queSize=0;
        nums= new int[capacity];
        queCapacity=capacity;
    }

    ~ArrayQueue(){
        delete []nums;
    }


    //获取队列容量
    int capacity(){
        return queCapacity;
    }

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

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

    //入队操作
    void push(int num){
        if(queSize==queCapacity){
            cout<<"队列已满"<<endl;
            return ;
        }
        int rear=(front+queSize)%queCapacity;//通过取余使得rear越过数组尾端,继续从头遍历

        nums[queSize]=num;
        queSize++;
    }

    //出队操作
    int pop(){
        int num=peek();
        // 队首指针向后移动一位,若越过尾部,则返回到数组头部
        front=(front+1)%queCapacity;
        queSize--;
        return num;
    }

    //访问队列首元素
    int peek(){
        if (empty()) throw out_of_range(" 队列为空"); 
        return nums[front];
    }

    //将数组转换为Vector并返回
    vector<int> toVector(){
        //仅转换为有效长度范围内的列表元素
        vector<int> arr(queSize);
        for(int i =0, j=front;i<queSize;i++,j++){
            arr[i]=nums[j%queCapacity];
        }
        return arr;
    }
};

2.基于链表实现的队列

可以将链表的头节点和尾节点分别看作“队首”和“队尾”。并规定队首仅可以删除节点,队尾尽可以添加节点。

class LinkedListQueue{
 private:
     ListNode *front,*rear;//头节点,尾节点
     int queSize;

 public:
    LinkedListQueue(){
        front =nullptr;
        rear=nullptr;
        queSize=0;
    }

    ~LinkedListQueue(){
        //遍历链表删除节点,释放内存
        freeMemoryLinkedList(front);
    }

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

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

    //入队操作
    void push(int num){
        //在尾节点后添加num
        ListNode *node=new ListNode(num);
        //若队列为空,说明添加的这个节点是唯一节点,头节点和尾节点都指向它
        if(front==nullptr){
            front = node;
            rear = node;
        }
        else{
            rear->next=node;
            rear = node;
        }
        queSize++;
    }

    //出队操作
    int pop(){
        int num=peek();//用于出队时,返回到底出队的元素是什么
        ListNode* tmp = fornt;
        front = front->next;
        //释放内存
        delete tmp;
        queSize--;
        return num;
    }

    //访问队首元素
    int peek(){
        if(size()==0){
            throw out_of_range("队列是空的");
        }
        return front->val;
    }

    //将链表转换为vector并返回
    vector<int> toVector(){
        ListNode* node =front;
        vector<int> ans(size());
        for( int i =0;i<ans.size();i++){
            ans[i]=node->val;
            node=node->next;
        }
        return ans;
    }
};

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值