【数据结构篇】线性表2 —— 栈和队列

这篇具有很好参考价值的文章主要介绍了【数据结构篇】线性表2 —— 栈和队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:上一篇我们介绍了顺序表和链表

(https://blog.csdn.net/iiiiiihuang/article/details/132615465?spm=1001.2014.3001.5501),

这一篇我们将介绍栈和队列,栈和队列都是基于顺序表和链表来实现的

目录

栈(Stack)

什么是栈 ?

栈的方法 和 使用

栈的模拟实现 

先初始化一下栈 

往栈里插入元素 (push)

栈是否为空(empty)

弹出栈顶元素(删除)(pop)

获取栈顶元素 (peek)

模拟实现完整代码 

栈的应用场景

 1. 改变元素的序列

2. 将递归转化为循环

补充 :

队列(Queue) 

什么是队列 ?

队列的方法 

队列模拟实现 

初始化 

offer 

poll

peek

完整代码(链式队列) 

循环队列 

认识循环队列 

如何把数组看作是一个循环呢?(rear 从 7 --> 0) 

设计一个循环队列 (https://leetcode.cn/problems/design-circular-queue/)

初始化 

判断队列是否是空的,和是否是满的 

入队 

 出队

得到队头元素

得到队尾元素

完整代码: (循环队列)

双端队列 (Deque)

(面试题) 1. 用队列实现栈   2. 用栈实现队列

 1. 用队列实现栈

代码实现:

入栈

出栈 

获取栈顶元素 

 判断栈空

完整代码 

 2. 用栈实现队列 

我直接上代码了: 

 


栈(Stack)

什么是栈 ?

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

后进先出原则:先进的后出,后进的先出  。我们举一个生活中的例子

比如这有个圆筒,一端封闭,一端开口,然后往圆筒里放乒乓球:

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构    

你想拿乒乓球,先拿到的肯定是后放的,那如果你想要拿到最底下的,你肯定得把上面的都拿走才行。也就是 栈的后进先出原则 (先进的后出,后进的先出)

栈的方法 和 使用

 栈的方法很少,只有这些: 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

使用 (没什么好说的😁😁)

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

栈的模拟实现 

 栈这种数据结构可以用数组来实现,也可以用链表来实现,这里我们用数组实现。

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

先初始化一下栈 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

往栈里插入元素 (push)

和顺序表异曲同工,先看看满没满,满了要扩容,再入栈 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

栈是否为空(empty)

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

弹出栈顶元素(删除)(pop)

就很简单 (顺序表那搞懂,这些方法很简单的)

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

获取栈顶元素 (peek)

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

模拟实现完整代码 

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @Author: iiiiiihuang
 */
public class MyStack {
    private int[] elem;
    private int usedSize;
    private static final int DEFAULT_CAPACITY = 10;//默认容积
    public MyStack() {
        this.elem = new int[DEFAULT_CAPACITY];
    }

    /**
     * 往栈里插入元素
     * @param val
     */
    public void push(int val) {
        isFull();
        this.elem[usedSize] = val;
        usedSize++;
    }
    private void isFull() {
        if(usedSize == this.elem.length) {
            this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);
        }
    }

    /**
     * 弹出栈顶元素
     * @return
     */
    public int pop() {
        if(empty()) {
            throw new EmptyException("栈为空");
        }
        int pop = this.elem[usedSize - 1];
        usedSize--;
        return pop;
    }

    /**
     * 获取栈顶元素
     * @return
     */
    public int peek() {
        if(empty()) {
            System.out.println("栈为空");
            return 0;
        }
        int peek = this.elem[usedSize - 1];
        return peek;
    }

    /**
     * 栈是否为空
     * @return
     */
    public boolean empty() {
        return usedSize == 0;
    }
}

栈的应用场景

 1. 改变元素的序列

我们去牛客上找两道题做做 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

根据我们上面介绍,栈 遵循 先进后出原则, 我们可以得出答案,不可能的出栈顺序是 D 选项

因为F,E出来了,下一个出来的必须是 D,这种情况下C不可能比D先出。 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

2. 将递归转化为循环
 

比如逆序打印链表: 

  1.递归方法 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 2.循环方法 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

运行结果 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

补充 :

用数组实现栈,出栈,入栈,都是O(1),

那用链表如何实现栈呢?

1.假设用单链表(单向)实现栈: 

  尾插: 

      入栈:尾插法 入栈是 O(n)

      出栈:因为栈后进的先出,这就相当于删除链表的尾巴节点,时间复杂度还是O(n);

 头插: 

      入栈:头插法 O(1)

      出栈:相等于删除头节点,时间复杂度O(1)

2.假设用双向链表实现栈:  (前后都能找到)

尾插: 

      入栈:尾插法 入栈是 O(1)

      出栈:时间复杂度还是O(1),

 头插: 

      入栈:头插法 O(1)

      出栈:时间复杂度O(1)

上述我们可知,用链表实现栈时,双向链表实现栈是最好的,不管从那边入栈,出栈 时间复杂度都是O(1)。

那使用链式栈时就可以这样使用:如果这是个栈,那peek的内容就是 4. 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

是 4. 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

那为啥会这样,你看LinkedList,里本来就有栈里的一些方法,push..... 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

push 用的是头插法 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

所以如果是顺序栈,你可以用Stack, 如果是链式栈,你就用LinkedList 

队列(Queue) 

什么是队列 ?

 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头

举例说明: 

假如有一条单行隧道,车辆必须从入口进 (入队列),从出口出(出队列)。那先驶出隧道的车辆肯定是先进去的,后驶出的肯定是后进去的,这就是 队列的先进先出原则

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

通过上述介绍,我们发现我们可以把 双向链表当成是一个 队列 ,(单链表也行,双链表更简单)

队尾进,队头出,时间复杂度O(1)

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 ps:Queue 普通队列,Deque 双端队列(两边都可以进出),LinkedList 可以当作普通队列,双端队列,链表,栈(究极打工人😭😭😭)

队列的方法 

在Java中,Queue是个接口,底层是通过链表实现的。 

队列方法少的嘞 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

offer (入队列) 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

peek 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

poll 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

......... 

add,remove ,element (和peek一个意思)是一组 

offer,  poll,  peek 是一组

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

队列模拟实现 

队列的实现使用 顺序结构 和 链式结构 都行,但链式结构更简单一点。

我们这里拿双链表去写 (前面的链表学会了,这里很简单的,信手拈来)

初始化 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

offer 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

调试一看 插进去了 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

poll

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

peek

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

完整代码(链式队列) 

/**
 * @Author: iiiiiihuang
 */
public class MyQueue {
    static class ListNode {
        private int val;
        private ListNode prev;
        private ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    private ListNode front;//头
    private ListNode rear;//尾
    private int usedSize;//计数

    /**
     * 插入--- 头插法
     * @param val
     */
    public void offer(int val) {
        ListNode node = new ListNode(val);
        if(front == null) {
            front = node;
            rear = node;
        } else {
            node.next = front;
            front.prev = node;
            node = front;
        }
        usedSize++;
    }

    /**
     * 删除 -- 尾删
     * @return
     */
    public int poll() {
        if(front == null) {
            throw new EmptyException("队列为空");
        }
        if(front == rear) {
            int poll = front.val;
            front = null;
            rear = null;
            usedSize--;
            return poll;
        }
        int poll = rear.val;
        rear = rear.prev;
        rear.next = null;
        usedSize--;
        return poll;
    }

    /**
     * 获取队头
     * @return
     */
    public int peek() {
        if(front == null) {
            throw new EmptyException("队列为空");
        }
        return rear.val;
    }
}

循环队列  

实际中我们有时还会使用一种队列叫循环队列
环形队列通常使用数组实现。 

认识循环队列 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

。。。。。 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

这就有意思了 ,

front 和 rear 第一次在一起的时候 队列 是空的,第二次 在一起的时候是队列是满的

那这怎么判断呢,其实有很多方法去判断

 1.计数  usedSize == len

 2.标记,flag

 3.浪费一个空间来区分(常用) 

 浪费一个空间,就类似下面这样

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

如何把数组看作是一个循环呢?(rear 从 7 --> 0) 

就是把 rear ++  换成 (rear + 1 )% len  (余数肯定都是小于 len的(len 数组长度)),rear++ 会越界的 (看不懂自己带数据算算)

设计一个循环队列 (https://leetcode.cn/problems/design-circular-queue/)

根据这个来 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

初始化 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

判断队列是否是空的,和是否是满的 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

入队 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 出队

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

得到队头元素

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

得到队尾元素

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

不能直接rear - 1哦

 那现在我们放到力扣里运行一下(链接在上边)

 错了 !!! 为什么,我们看看我什么

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

数组容量是 3 ,预期结果成功 插入了 3个,而我们的程序,只能插入两个,因为我们的浪费掉了一个空间 。

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

所以我们应该多给一个空间: 

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

在运行一下 ,通过了,当然你要是觉得这样奇怪,你也可以用 usedSize,很多方法啦😎😎

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

完整代码: (循环队列)
class MyCircularQueue {

    private int[] elem;
    private int front;//头
    private int rear;//尾
    public MyCircularQueue(int k) {
        this.elem = new int[k + 1];
    }
    
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        elem[rear] = value;
        rear = (rear + 1) % elem.length;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front + 1) % elem.length;
        return true;
    }
    
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        int ret = elem[front];
        return ret;
    }
    
    public int Rear() {
         if(isEmpty()) {
            return -1;
        }
        int index = (rear == 0) ? elem.length - 1 : rear - 1;//不能直接rear - 1哦
        return elem[index];
    }
    
    public boolean isEmpty() {
        return front == rear;
    }
    
    public boolean isFull() {
        if((rear + 1) % this.elem.length == front) {
            return true;
        }
        return false;
    }
}

双端队列 (Deque)  

 双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double   ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队

Deque是一个接口,使用时必须创建LinkedList的对象 。

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构 在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口

1. Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现(数组)
2. Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现 

(面试题) 1. 用队列实现栈   2. 用栈实现队列

 1. 用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

1.首先一个栈是不够用的,它俩的出栈原则不一样,栈先进后出,队列先进先出,一个队列实现不了呀 ,对不上。

2.所以我们需要两个队列,当 2 个队列都为空的时候,说明模拟栈为空。

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

3.当要出栈的时候,(出 45 ),我们要把 12,23,34,入到第二个队列里去,然后再把第一个队列里的 45 出队列 ,

结论就是,”出栈“的时候出不为空的 队列,出队列size - 1 个(俩队列轮流),最后那一个就是我们要 ”出栈“的元素

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 4.“入栈” 的时候入到不为空的队列

 思路有了,我们开始写代码:

代码实现:

入栈

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

出栈 

 用for 循环的时候注意一下,不要写成 i < queue.size() - 1,因为queue.size()一直在变。你先记录一下

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

获取栈顶元素 

 我们可以定义一个临时量,来存放栈顶元素

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

里面的元素一直被覆盖,那最后出队列的元素,就覆盖了之前的全部元素,就是栈顶元素。 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 注意:这里可别写成 queue1.offer(queue2.poll), 跳两回啦。

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

 判断栈空

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

完美通过 

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

完整代码 

import java.util.LinkedList;
import java.util.Queue;

/**
 * @Author: iiiiiihuang
 */
public class MyStack {
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;
    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }

    /**
     * 入栈操作
     * @param x
     */
    public void push(int x) {
        if(!queue1.isEmpty()){
            queue1.offer(x);
        } else if(!queue2.isEmpty()) {
            queue2.offer(x);
        }else {
            queue1.offer(x);
        }
    }

    /**
     * 出栈
     * @return
     */
    public int pop() {
        //先判断栈空不空
        if(empty()) {
            return -1;
        }
        if(!queue1.isEmpty()) {
            int len = queue1.size() - 1;
            while (len > 0) {
                int tmp = queue1.poll();
                queue2.offer(tmp);
                len--;
            }
            return queue1.poll();
        } else {
            int len = queue2.size() - 1;
            while (len > 0) {
                int tmp = queue2.poll();
                queue1.offer(tmp);
                len--;
            }
            return queue2.poll();
        }
    }

    /**
     * 获取栈顶元素
     * @return
     */
    public int top() {
        int tmp = -1;
        if(empty()) {
            return -1;
        }
        if(!queue1.isEmpty()) {
            int len = queue1.size();
            while (len > 0) {
                tmp = queue1.poll();
                queue2.offer(tmp);
                len--;
            }
            return tmp;
        } else {
            int len = queue2.size();
            while (len > 0) {
                tmp = queue2.poll();
                queue1.offer(tmp);
                len--;
            }
            return tmp;
        }
    }

    public boolean empty() {
        return queue1.isEmpty() && queue2.isEmpty();
    }
}

 2. 用栈实现队列 

232. 用栈实现队列 - 力扣(LeetCode)

思路差不多 

1.两个栈实现,同理 

2.入队的时候 把所有元素 全部放到第一个栈当中

3.出队的时候 把所有的元素 全部倒到第二个栈当中,然后出第二个栈顶元素就行了.(记得判空)

我直接上代码了: 

import java.util.Stack;

/**
 * @Author: iiiiiihuang
 */
public class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    public void push(int x) {
        stack1.push(x);
    }

    public int pop() {
        if(empty()) {
            return -1;
        }
        if(stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    public int peek() {
        if(empty()) {
            return -1;
        }
        if(stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }

    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

 【数据结构篇】线性表2 —— 栈和队列,Java,数据结构

先别急着走,点个关注先,👀👀👀

点赞,评论,收藏,支持一下ヾ(≧▽≦*)oヾ(≧▽≦*)o

【数据结构篇】线性表2 —— 栈和队列,Java,数据结构文章来源地址https://www.toymoban.com/news/detail-697224.html

到了这里,关于【数据结构篇】线性表2 —— 栈和队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java数据结构】线性表-队列

    队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(FirstIn First Out) 入队列:进行插入操作的一端称为 队尾(Tail/Rear) 出队列:进行删除操作的一端称为 队头(Head/Front) 在Java中, Queue是个接口,底层是通过链表实现的。

    2023年04月15日
    浏览(52)
  • 【数据结构】栈和队列(队列篇)

    上期我们已经学习了数据结构中的栈,这期我们开始学习队列。 目录 1.队列的概念及结构 2.队列的实现 队列结构体定义 常用接口函数 初始化队列 队尾入队列 队头出队列 获取队列头部元素、 获取队列队尾元素 获取队列中有效元素个数 检测队列是否为空 销毁队列 3.循环队

    2024年02月13日
    浏览(41)
  • 数据结构---栈和队列

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作

    2024年01月18日
    浏览(40)
  • 数据结构--栈和队列

    栈是一种常见的数据结构,它遵循 后进先出LIFO (Last In First Out)的原则。 进行数据插入和操作的一端称为栈顶,另一端称为栈底 。 压栈 :栈的插入操作被称为压栈/进栈/入栈,入数据在栈顶。 出栈 :栈的删除操作。出数据也在栈顶; 栈可以用 数组 或者是 链表 来实现;

    2024年02月09日
    浏览(39)
  • 数据结构:栈和队列

    朋友们、伙计们,我们又见面了,本期来给大家解读一下栈和队列方面的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结构专栏:数据结构 个 人 主 页 :  stackY、 目录 前言:  1.栈 1.1栈的

    2024年02月06日
    浏览(41)
  • [数据结构】栈和队列

    目录 1.栈 1.1概念 1.2 栈的使用 1.3.栈的模拟实现 2.队列 2.1概念 2.2队列的使用 2.3队列的模拟实现 2.4 循环队列 2.5双端队列   栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素

    2024年02月07日
    浏览(41)
  • 数据结构——栈和队列

    目录  一.前言 二.前文回顾 三.栈 3.1 栈的概念及结构 3.2 栈的实现 3.2.1 初始化函数 3.2.2 销毁函数 3.2.3 入栈函数 3.2.4 出栈函数 3.2.5 计算大小函数 3.2.6 空栈函数 3.2.7 获取栈顶函数  3.2.8 小测试 3.3 全部代码 四.栈的练习 4.1 有效的括号 五.队列 5.1队列的概念及结构 5.2 队列的实

    2024年01月25日
    浏览(46)
  • 数据结构【栈和队列】

    一、栈 1.定义:只允许一端进行插入和删除的线性表,结构与手枪的弹夹差不多,可以作为实现递归函数(调用和返回都是后进先出)调用的一种数据结构; 栈顶:允许插入删除的那端; 栈底:固定的,不允许插入或删除; 空栈:不含元素; 2.特点:后进先出; 3.操作:入

    2024年02月15日
    浏览(47)
  • 数据结构 | 栈和队列

    … 📘📖📃本文已收录至:数据结构 | C语言 更多知识尽在此专栏中! 栈(Stack) 又名堆栈,它是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。 队列(Queue) 也是一种特殊的线性表,特殊之处在于它只允许在表的前端(Front)进行删除操作,而在表的

    2024年01月23日
    浏览(42)
  • 栈和队列【数据结构】

    2024年02月16日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包