Java语言----动态顺序表(ArrayList)

这篇具有很好参考价值的文章主要介绍了Java语言----动态顺序表(ArrayList)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一.顺序表

二.顺序表的手动实现

    2.1顺序表的创建

    2.2.基本功能的实现

2.2.1扩容顺序表

 2.2.2 判断顺序表是否为满

 2.2.3 判断顺序表是否为空

 2.2.4打印顺序表

 2.2.5清空顺序表

 2.3四大功能的实现

         2.3.1增加元素

         2.3.2删除元素

         2.3.3查找元素

         2.3.4更改数据  

总代码 

     📝MyArraysList.java

 📝Test.java

一.ArrayList 讲解


😽个人主页: tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主
 🌈梦的目标:努力学习,向Java进发,拼搏一切,让自己的未来不会有遗憾。
 🎁欢迎各位→点赞👍 + 收藏⭐ + 评论📝+关注✨
  本章讲解内容:顺序表的讲解

Java语言----动态顺序表(ArrayList)

   使用编译器:IDEA 

一.顺序表

Java语言----动态顺序表(ArrayList)

顺序表(ArrayList):用一段物理地址连续的存储单元依次存储数据元素的线性结构,通常采用数组存储。在数组上完成数据的增删查改

二.顺序表的手动实现

    2.1顺序表的创建

import java.util.Arrays;
 
public class MyArraysList {
    private int[] elem;
    private int usedSize; // 默认值是0
    private static final int DEFAULT_SIZE = 4; // 定义为常量,更加安全
 
    // 初始化顺序表
    public MyArraysList() {
        this.elem = new int[DEFAULT_SIZE];
    }
   
}

  这边是创建顺序表的类,不仅要创建出来,我们还需要学会使用,例如增、删、查、改

    2.2.基本功能的实现

2.2.1扩容顺序表

// 对顺序表进行扩容
    public void expand() {
        this.elem = Arrays.copyOf(this.elem, this.usedSize * 2);
        System.out.println("已经成功扩容至原来的两倍"); // 给用户提醒
    }

 注:     在进行增加元素的操作时,当数组满了,则需要扩容,才能容纳下一个元素

   

  2.2.2 判断顺序表是否为满

    /**
     * 判断当前顺序表是不是满了
     * @return true->满了,false->还没满
     */
    public boolean isFull() {
        if (this.usedSize == this.elem.length) return true;
        else return false;
    }

注:扩容前得判断是否数组满了,只有满了,才需要扩容

   

2.2.3 判断顺序表是否为空

     /**
     * 判断当前顺序表是否为空
     * @return true->空的,false->还没空
     */
    public boolean isempty() {
        if (this.usedSize == 0) {
            return true;
        }
        else return false;
    }

注:如果需要删除顺序表的元素,得判断顺序表是否为空,毕竟空的顺序表无法删除元素。

2.2.4打印顺序表

// 打印顺序表
    public void display() {
        for (int i = 0; i < this.elem.length; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }
}

注:顺序表存放了数据,得显示出来,展示你存放的数据

2.2.5清空顺序表

 // 清空顺序表
    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0; // 注意有效数组长度也要清零
    }

 注:当代码结束之后,需要释放顺序表内存。


2.3四大功能的实现

2.3.1增加元素

 头插法:

 // 新增元素,在数组最前面新增
    public void addHead(int data) {
        if (isFull()) {
            System.out.println("数组满了,需要扩容");
            expand();
        }
        else {
            // 从usedSize下标开始,不会数组越界(此时的elem.length > usedSize)
            for (int i = this.usedSize; i > 0; --i) {
                this.elem[i] = this.elem[i - 1]; // 从后往前挪动数据,为的是给顺序表的表头腾出来
            }
            this.elem[0] = data; // 在顺序表开头插入
            this.usedSize++;    // 数组有效长度加一
        }

注:每次增加的元素,都放在顺序表的第一位。

尾插法:

//在数组最后新增
    public void addTail(int data) {
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else this.elem[this.usedSize++] = data;
    }

注:每次插入元素,直接放在顺序表的最后一位。

指定下标值插入:

 // 在 pos 位置新增元素
    public void addPos(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            System.out.println("pos位置不合法"); return;
        }
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else {
            // 如果插入位置在顺序表的中间,要注意挪动元素,从后向前挪动,这样不会造成元素值的覆盖
            for (int i = this.usedSize - 1; i >= pos; --i) {
                this.elem[i + 1] = this.elem[i];
            }
            this.elem[pos] = data; // 挪动完毕,可以赋值插入
            this.usedSize++;      // 当前元素数加一
        }
    }

若在对应下标插入元素,则下标值后面的所有元素整体向后移一位。

注意:需要判断数组是否满了、插入位置在元素下标范围内。


2.3.2删除元素

头删:

 // 删除表头元素
    public void removeHead() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        // 从第一个元素开始,用后面元素的值覆盖掉前面的值,遍历整个数组就相当于把第一个元素用覆盖的方式抹去了
        for (int i = 1; i < this.usedSize; i++) {
            this.elem[i - 1] = this.elem[i];
        }
        this.elem[this.usedSize - 1] = 0; // 减少了一个元素,所以之前最后一个元素置0
        this.usedSize--; // 不要忘记改变有效数组的长度
    }

注:从第二个元素开始,每一个元素覆盖前面一个,再将最后一个元素清零。

尾删:

    // 删除表尾元素
    public void removeTail() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        this.elem[this.usedSize - 1] = 0; // 直接将最后一个元素置0就完成了尾删
        this.usedSize--; // 不要忘记改变有效数组的长度
    }

注:直接删除末尾元素,将最后一个元素置0

指定下标元素的删除:

 // 指定下标元素的删除
    public void removePos(int pos) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos下标不合法");
        }
        else {
            for (int i = pos; i < this.usedSize - 1; ++i) {
                this.elem[i] = this.elem[i + 1]; // 从要删除的下标开始,用后边元素的值覆盖掉前面的值,就完成了删除
            }
            this.elem[this.usedSize - 1] = 0; // 最后一个元素置0
            this.usedSize--;// 删除后更改顺序表的有效长度
        }
    }

  注:与头删法相似。

删除首次出现的元素:

 //删除第一次出现的关键字key
    public void removeKey(int toRemove) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toRemove) {
                // 注意是this.usedSize - 1,将此时 i 之后的元素统一往前搬移一个位置
                for (int j = i; j < this.usedSize - 1; ++j) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
                this.usedSize--; // 删除后不要忘记更改顺序表的有效长度
                return; // 只删除第一次出现的
            }
        }
    }

注:找到对应下标值,然后再进行覆盖,在删除的后面全体元素向前挪一位


2.3.3查找元素

获取指定位置元素:

 // 获取 pos 位置的元素
    public int getPos(int pos) {
        if (pos < 0 || pos >= this.usedSize) { // 注意这里当pos==this.usedSize也是不合法的,因为此时的pos下标所要获取的是顺序表中第usedSize+1个元素
            System.out.println("pos的位置不合法");
            return -1;
        }
        else {
            return this.elem[pos];
        }
    }

注:考虑要获取的位置是否合法、返回指定位置的元素

获取指定元素所在的位置:

 // 查找某个元素所对应顺序表中的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        System.out.println("在数组中没有找到该元素");
        return -1;
    }

注:返回下标值


2.3.4更改数据

在对应下标值,进行修改:

// 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (pos == this.usedSize) { // 对这种情况要单独处理,此时相等于增加元素
            this.elem[pos] = value;
            this.usedSize++;
        }
        else {
            this.elem[pos] = value;
        }
 
    }

几乎是查找的步骤上,对其修改。


总代码 

📝MyArraysList.java

   MyArraysList.java用于顺序表的实现

import java.util.Arrays;
 
public class MyArraysList {
    private int[] elem;
    private int usedSize; // 默认值是0
    private static final int DEFAULT_SIZE = 4; // 定义为常量,更加安全
    // 初始化顺序表
    public MyArraysList() {
        this.elem = new int[4];
    }
    // 对顺序表进行扩容
    public void expand() {
        this.elem = Arrays.copyOf(this.elem, this.usedSize * 2);
        System.out.println("已经成功扩容至原来的两倍"); // 给用户提醒
    }
 
    /**
     * 判断当前顺序表是否为空
     * @return true->空的,false->还没空
     */
    public boolean isempty() {
        if (this.usedSize == 0) {
            return true;
        }
        else return false;
    }
    /**
     * 判断当前顺序表是不是满了
     * @return true->满了,false->还没满
     */
    public boolean isFull() {
        if (this.usedSize == this.elem.length) return true;
        else return false;
    }
    // 打印顺序表
    public void display() {
        for (int i = 0; i < this.elem.length; i++) {
            System.out.print(this.elem[i] + " ");
        }
        // System.out.println(Arrays.toString(this.elem));或者用Arrays.toString打印也行
        System.out.println();
    }
 
    // 新增元素,默认在数组最后新增
    public void addTail(int data) {
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else this.elem[this.usedSize++] = data;
    }
    // 新增元素,在数组最前面新增
    public void addHead(int data) {
        if (isFull()) {
            System.out.println("数组满了,需要扩容");
            expand();
        }
        else {
            // 从usedSize下标开始,不会数组越界(此时的elem.length > usedSize)
            for (int i = this.usedSize; i > 0; --i) {
                this.elem[i] = this.elem[i - 1]; // 从后往前挪动数据,为的是给顺序表的表头腾出来
            }
            this.elem[0] = data; // 在顺序表开头插入
            this.usedSize++;    // 数组有效长度加一
        }
    }
    // 1、判断pos位置是否合法(在顺序表中,数据是连续的,中间不能有空缺)
    // 2、判断顺序表是否满了,如果满了,需要扩容
    // 3、插入数据(可能需要挪作元素)
    // 在 pos 位置新增元素
    public void addPos(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            System.out.println("pos位置不合法"); return;
        }
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else {
            // 如果插入位置在顺序表的中间,要注意挪动元素,从后向前挪动,这样不会造成元素值的覆盖
            for (int i = this.usedSize - 1; i >= pos; --i) {
                this.elem[i + 1] = this.elem[i];
            }
            this.elem[pos] = data; // 挪动完毕,可以赋值插入
            this.usedSize++;      // 当前元素数加一
        }
    }
 
    // 删除表头元素
    public void removeHead() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        // 从第一个元素开始,用后面元素的值覆盖掉前面的值,遍历整个数组就相当于把第一个元素用覆盖的方式抹去了
        for (int i = 1; i < this.usedSize; i++) {
            this.elem[i - 1] = this.elem[i];
        }
        this.elem[this.usedSize - 1] = 0; // 现在的最后一个元素是原来的倒数第二个元素, 所以原来的最后一个有效元素要置0
        this.usedSize--; // 不要忘记改变有效数组的长度
    }
    // 删除表尾元素
    public void removeTail() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        this.elem[this.usedSize - 1] = 0; // 直接将最后一个元素置0就完成了尾删
        this.usedSize--; // 不要忘记改变有效数组的长度
    }
    // 指定下标元素的删除
    public void removePos(int pos) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos下标不合法");
        }
        else {
            for (int i = pos; i < this.usedSize - 1; ++i) {
                this.elem[i] = this.elem[i + 1]; // 从要删除的下标开始,用后边元素的值覆盖掉前面的值,就完成了删除
            }
            this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
            this.usedSize--;// 删除后不要忘记更改顺序表的有效长度
        }
    }
    //删除第一次出现的关键字key
    public void removeKey(int toRemove) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toRemove) {
                // 注意是this.usedSize - 1,将此时 i 之后的元素统一往前搬移一个位置
                for (int j = i; j < this.usedSize - 1; ++j) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
                this.usedSize--; // 删除后不要忘记更改顺序表的有效长度
                return; // 只删除第一次出现的
            }
        }
    }
 
    /**
     * /判定是否包含某个元素
     * @param toFind 要查找的元素
     * @return true->包含, false->不包含
     */
    public boolean contains(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind)  return true;
        }
        return false;
    }
    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        System.out.println("在数组中没有找到该元素");
        return -1;
    }
    // 获取 pos 位置的元素
    public int getPos(int pos) {
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos的位置不合法");
            return -1;
        }
        else {
            return this.elem[pos];
        }
    }
    // 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (pos == this.usedSize) { // 对这种情况要单独处理,此时相等于增加元素
            this.elem[pos] = value;
            this.usedSize++;
        }
        else {
            this.elem[pos] = value;
        }
 
    }
 
    // 获取顺序表长度
    public int size() {
        return this.usedSize;
    }
    // 清空顺序表
    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0; // 注意有效数组长度也要清零
    }
 
}

 📝Test.java

Test.java用于顺序表的各个接口的测试

/**
 * 对顺序表进行测试的代码
 */
public class Test {
    public static void main(String[] args) {
        MyArraysList myArraysList = new MyArraysList();
        // 尾插四个数字
        myArraysList.addTail(12);
        myArraysList.addTail(32);
        myArraysList.addTail(17);
        myArraysList.addTail(32);
        // 进行扩容
        myArraysList.expand();
        // 指定在pos位置新增元素
        myArraysList.addPos(1, 777);
        // 打印当前的顺序表
        System.out.print("第一次测试的顺序表为:");
        myArraysList.display();
 
        // 删除顺序表中首次出现的元素32
        myArraysList.removeKey(32);
        // 获取顺序表中 1下标的元素值
        int tmp = myArraysList.getPos(1);
        System.out.println("顺序表中下标为1的元素的值为:" + tmp);
        // 给顺序表中1下标的元素设为value
        myArraysList.setPos(1, 100);
        // 打印此时的顺序表
        System.out.print("修改后第二次测试的顺序表为:"); // 此时1下标的值为100
        myArraysList.display();
 
        // 顺序表此时的有效长度
        System.out.println("顺序表的有效长度为:" + myArraysList.size());
        // 清空顺序表
        myArraysList.clear();
        System.out.print("第三次测试的顺序表为:");
        myArraysList.display();
        System.out.println("清空顺序表后,顺序表的有效长度为:" + myArraysList.size());
 
    }
 
}

三.ArrayList 讲解

        实现了List接口,底层为动态类型顺序表,也就是说在Java中,已经写好了顺序表,我们可以在了解顺序表的基础原理之后,我们就可以更好的使用该类。

代码实现:

public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}

ArrayList使用的方法

        方法         解释
boolean add(E e) 尾插e
void add(int index,E element) 将e插入index的位置
boolean addAII(Collection <?extendsE>c 尾插c中的元素
E remove(int index) 删除index位置元素
boolean remove(Object o) 删除遇见的第一个 o
E get(int index) 获取下标index 位置元素
E set(int index,E element) 将下标index 位置元素设置为element
void clear() 清空
boolean contains(Object o) 判断o是否在线性表内

代码实现:

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("JavaSE");
    list.add("JavaWeb");
    list.add("JavaEE");
    list.add("JVM");
    list.add("测试课程");
    System.out.println(list);
// 获取list中有效元素个数
System.out.println(list.size());
// 获取和设置index位置上的元素,注意index必须介于[0, size)间
System.out.println(list.get(1));
list.set(1, "JavaWEB");
System.out.println(list.get(1));
// 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置
list.add(1, "Java数据结构");
System.out.println(list);
// 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置
list.remove("JVM");
System.out.println(list);
// 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常
list.remove(list.size()-1);
System.out.println(list);
// 检测list中是否包含指定元素,包含返回true,否则返回false
if(list.contains("测试课程")){
list.add("测试课程");
} 
}

四.总结

       数据结构是一门单独的学科,千位千位不要理解为只有Java才有,C语言等其他语言也能够实现此物理逻辑,C语言实现顺序表:C语言的顺序表构建文章来源地址https://www.toymoban.com/news/detail-446665.html

到了这里,关于Java语言----动态顺序表(ArrayList)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Java动态数组实现----聊聊ArrayList

    作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共同成长。请大家以开放的心态阅读,相信

    2024年01月17日
    浏览(40)
  • 探秘ArrayList源码:Java动态数组的背后实现

    读者需先对源码的成员变量阅览一遍,看个眼熟,有助于后面源码的理解 以无参数构造方法创建 ArrayList时,实际上初始化赋值的是一个空数组。此时并没有为它创建对象,当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为

    2024年02月16日
    浏览(33)
  • 深入源码解析ArrayList:探秘Java动态数组的机制与性能

    1.1 介绍ArrayList的基本概念和作用 在Java中,ArrayList是一个实现了List接口的动态数组。它可以根据需要自动增加大小,因此可以存储任意数量的元素。 基本概念: ArrayList是Java中常用的集合类之一,它可以存储对象,并且可以根据索引访问和操作这些对象。 ArrayList是基于数组

    2024年02月04日
    浏览(39)
  • 【JavaSE专栏48】Java集合类ArrayList解析,这个动态数组数据结构你了解吗?

    作者主页 :Designer 小郑 作者简介 :3年JAVA全栈开发经验,专注JAVA技术、系统定制、远程指导,致力于企业数字化转型,CSDN学院、蓝桥云课认证讲师。 主打方向 :Vue、SpringBoot、微信小程序 本文讲解了 Java 中集合类 ArrayList 的语法、使用说明和应用场景,并给出了样例代码。

    2024年02月16日
    浏览(59)
  • C语言数据结构-----顺序表(多功能动态顺序表的代码实现)

    本篇讲述了顺序表的相关知识,以及动态顺序表的代码实现。 顺序表和链表一般情况下都会叫他们线性表。 线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性

    2024年02月07日
    浏览(45)
  • 06.ArrayList与顺序表

    线性表 ( linear list ) 是 n个具有相同特性的数据元素的有限序列 。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列... 线性表在 逻辑上是 线性 结构 ,也就说是连续的一条直线。但是在 物理结构上并不一定是连续的 ,线性表在物理上

    2023年04月09日
    浏览(30)
  • ArrayList与顺序表

    顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用 数组 存储。在数组上完成数据的增删查改。 在集合框架中,ArrayList是一个普通的类,实现了List接口,它有以下几个特点: ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动

    2024年02月11日
    浏览(37)
  • 第五章 ArrayList与顺序表

    线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结 构,常见的线性表:顺序表、链表、栈、队列… 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物 理上存储时,

    2024年02月06日
    浏览(31)
  • 【数据结构与算法】1、学习动态数组数据结构(基本模拟实现 Java 的 ArrayList 实现增删改查)

    🍃 数据结构是 计算机 存储 、 组织 数据的方式 🎉 线性 结构 线性表(数组、链表、栈、队列、哈希表) 🎉 树形 结构 二叉树 AVL 树 红黑树 B 树 堆 Trie 哈夫曼树 并查集 🎉 图形 结构 邻接矩阵 邻接表 🎁 线性表是具有 n 个 相同类型元素 的有限 序列 (n = 0) a1 是首节点

    2024年02月10日
    浏览(75)
  • 模拟ArrayList(顺序表)的底层实现

    2024年02月16日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包