当前位置: 首页 > news >正文

Java数据结构-List-栈-队列-二叉树-堆

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 1. 前置知识
    • 1.1 yield关键字
    • 1.2 var关键字
    • 1.3 密封类
    • 1.4 接口中的私有方法
    • 1.5 instance
    • 1.5 包装类
    • 1.6 装箱和拆箱
    • 1.7 泛型
  • 2. List
    • 2.1 ArrayList顺序表
      • 2.1.1 ArrayList遍历
    • 2.2 链表
      • 2.2.1 LinkedList的使用
  • 3. 栈
  • 4. 队列
  • 5. 二叉树
  • 6. PriorityQueue优先级队列(堆)
    • 6.1 覆写基类的equals
    • 6.2 基于Comparble接口类的比较
    • 6.3 基于比较器比较
  • 总结


前言

1. 前置知识

1.1 yield关键字

    public static void main(String[] args) {String data = "one";int result = switch (data){case "one": yield 1;case "two": yield 2;default: yield 3;};System.out.println(result);}public static void main2(String[] args) {String data = "one";int result = switch (data){case "one"->1;case "two"->2;default -> 3;};System.out.println(result);}public static void main3(String[] args) {String data = "one";int result = 1;switch (data){case "one": result=1;break;case "two":result=1;break;default : result=1;break;};System.out.println(result);}

1.2 var关键字

    public static void main(String[] args) {var age =10;var salary ="hello";}

自动推导类型

但是var不能用于声明类的字段
声明变量必须要初始化,不能初始化为null
var不能作为返回值类型

1.3 密封类

final class Person {}

Person 这个类不能被继承:密封类

sealed class Person permits GB{}non-sealed class GB extends Person{}

表示Person是一个密封类,不能被继承,但是可以被GB继承
non-sealed 表示这不是一个密封类,可以被继承

继承了密封类,那么自己这个类就要说明一下到底是不是密封类

sealed修饰的类,必须要有子类,这个子类可以为sealed可以为non-seald,但是不能为什么都不说
只有被允许的类,才可以被继承

1.4 接口中的私有方法

interface A{void test();default void test2(){}static void test3(){}private  void test4(){}
}

后面三种方法,实现接口是不用重写这三种方法的,这三种方法也是可以有方法体的
只有第一个不能有方法体

1.5 instance

        if (obj instanceof String){String string = (String) obj;}if(obj instanceof String str){}

这两个是一样的效果

1.5 包装类

指的是基本数据类型对应的类类型

byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

1.6 装箱和拆箱

        int a = 10;Integer ii = a;//装箱,显示装箱Integer iii = Integer.valueOf(a);//自动装箱int b = ii;//自动拆箱int bi = ii.intValue();//手动拆箱
        double c = ii.doubleValue();
        Integer a = 100;Integer b = 100;System.out.println(a == b);Integer c = 200;Integer d = 200;System.out.println(c == d);

在这里插入图片描述
首先这两个都是装箱
都调用了方法valueOf
在这里插入图片描述
可以看出,如果i在一定范围之内,直接返回这个已经创建好的Integer-----》
已经创建好了一个Integer的数组cache
low是-128
high是127
所以i在-128到127之内,就会在cache这个数组里面取到Integer的值
如果不在的话,就创建一个新的Integer返回—》每个类的地址都不一样

        Integer a = 127;Integer b = 127;System.out.println(a == b);Integer c = 128;Integer d = 128;System.out.println(c == d);

在这里插入图片描述

1.7 泛型

泛型:就是适用于许多许多类型
把类型(int,byte)参数化

class MyArray<T>{public Object[] array= new Object[10];public void setValue(int pos, T value){array[pos] = value;}public T getValue(int pos){return (T)array[pos];}
}
        MyArray<Integer> a = new MyArray<Integer>();a.setValue(1,1);a.setValue(2,2);a.setValue(3,3);Integer value = a.getValue(1);System.out.println(value);

在这里插入图片描述

class MyArray<T>{public T[] array= (T[]) new Object[10];public void setValue(int pos, T value){array[pos] = value;}public T getValue(int pos){return (T)array[pos];}
}

也可以这样

T[] ts = new T[5];//是不对的
        MyArray<Integer> a = new MyArray<>();

第二个Integer可以不写,可以推导出实例化需要的类型实参为 Integer

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

尖括号里面只能写类,不能写简单类型

泛型到底是怎么编译的?

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。

那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?
因为java规定的就是,在new数组的时候,就必须是一个确定类型的数组,所以写new T[5]从语法上来说就已经出错了,因为你写new T(),你知道这个类型的构造方法是不带参数的吗

class MyArray<T>{public T[] array= (T[]) new Object[10];public void setValue(int pos, T value){array[pos] = value;}public T getValue(int pos){return (T)array[pos];}public T[] getArray(){return array;}
}
        MyArray<String> myArray = new MyArray<>();String[] strings = myArray.getArray();

在这里插入图片描述
这样直接就报错了,为什么呢,以前可以转换,那是因为,Object是所有类的父类
但是Object[]不会所有数组的父类
所以Object[]不是String[]的父类,是不能进行强转的

泛型的上界:在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束

public class MyArray<E extends Number> {
...
}

只接受 Number 的子类型或者number自己作为 E 的类型实参

public class MyArray<E extends Comparable<E>> {
...
}

E必须是实现了Comparable接口的----》意思就是这个类型E是可以进行比较的
就是E类型对应的对象可以来比较的,一般类型是不能比较的

class ALg<T extends Comparable<T>> {public T findMax(T[] array){T max = array[0];for (int i = 1; i < array.length; i++) {if (array[i].compareTo(max) > 0) {max = array[i];}}return max;}
}

在这里插入图片描述

我们看到MyArray没有实现接口Comparable,所以不能泛型

泛型方法

class ALg2 {public<T extends Comparable<T>> T findMax(T[] array){T max = array[0];for (int i = 1; i < array.length; i++) {if (array[i].compareTo(max) > 0) {max = array[i];}}return max;}
}
        ALg2 aLg2 = new ALg2();Integer[] arr = {1,2,3,4,5,6,7,8,9};Integer max = aLg2.findMax(arr);System.out.println(max);

这里不用指定泛型,因为会自动推导的

class ALg3 {public static <T extends Comparable<T>> T findMax(T[] array){T max = array[0];for (int i = 1; i < array.length; i++) {if (array[i].compareTo(max) > 0) {max = array[i];}}return max;}
}
        Integer max1 = ALg3.findMax(arr);
        Integer max1 = ALg3.<Integer>findMax(arr);

也可以这样

2. List

2.1 ArrayList顺序表

List是一个接口,继承自Collection。
Collection也是一个接口
继承Iterable
在这里插入图片描述

        List<Integer> list = new ArrayList<>();

因为ArrayList实现了ArrayList,所以可以这样定义
ArrayList就是顺序表
List是个接口,并不能直接用来实例化。
如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。

顺序表其实就是一个数组

    List<Integer> list = new ArrayList<>();list.add(1);list.add(2);System.out.println(list);

在这里插入图片描述

    ArrayList<Integer> arrayList = new ArrayList<>();List<Integer> list = new ArrayList<>();

List是一个接口
ArrayList是一个类
list 只能访问list里面的方法
而ArrayList只能访问ArrayList里面的方法,相比来说,ArrayList里面的防范更多

在这里插入图片描述

    List<Integer> list = new ArrayList<>();List<Integer> list2 = new ArrayList<>(list);List<Integer> list3 = new ArrayList<>(3);

这是三种不同的构造方法

容量达到3就进行扩容

boolean add(E e) 尾插 e
void add(int index, E element) 将 e 插入到 index 位置
boolean addAll(Collection<? extends E> 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 是否在线性表中
int indexOf(Object o) 返回第一个 o 所在下标
int lastIndexOf(Object o) 返回最后一个 o 的下标
List subList(int fromIndex, int toIndex) 截取部分 list,没有重新生成一个新的,意思是subList返回的数组和原数组是同一个部分的内容

因为list是Collection的子类,所以可以直接传入list类型的

    list2.addAll(list3);

如果删除10下标元素
remove(10)
如果删除10这个元素
remove(new Integer(10))
remove(Integer.valueOf(10))

2.1.1 ArrayList遍历

第一种就是直接打印

    list3.add(1);list3.add(2);list3.add(3);for (int i = 0; i < list3.size(); i++) {System.out.println(list3.get(i));}
    for (Integer integer : list2) {System.out.println(integer);}

最后一种就是使用迭代器

    Iterator<Integer> it = list2.iterator();while (it.hasNext()) {System.out.println(it.next());}

it迭代器指向的位置是第一位置的前一个位置,也就是-1的位置

只要实现了Iterable,就可以使用迭代器,就是使用foreach

    Iterator<Integer> it2 = list2.listIterator();while (it2.hasNext()) {System.out.println(it.next());}

这个是专门用于list的Iterator
Iterator是listIterator的父类

    ListIterator<Integer> it3 = list2.listIterator(list2.size());while (it3.hasPrevious()) {System.out.println(it3.previous());}

这个就是倒着遍历,传入整型参数表示从哪个迭代器开始
但是只有ListIterator有previous,Iterator是没有这个方法的,所以用ListIterator接收呢

iterator()不能传入整型参数,默认从0开始

  1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。—》链表

这个比较适合查找,根据下标进行查找

链表适合插入和删除

2.2 链表

class ListNode{public int val;public ListNode next;ListNode(int x){val = x;}
}

对象名存储的就是地址

        ListNode listNode1 = new ListNode(1);ListNode listNode2 = new ListNode(2);listNode1.next = listNode2;

new对象的时候,next默认是null的

在这里插入图片描述

        ListNode head = listNode1 ;

可以弄一个head

head = head.next();

这样就可以行走了,就可以从第一个遍历到第二个节点了

        ListNode cur= head;while (cur!=null){System.out.println(cur.val);cur= cur.next;}

2.2.1 LinkedList的使用

LinkedList是java库中的链表,是双向链表

        LinkedList<Integer> list = new LinkedList<>();List<Integer> list2 = new LinkedList<>();

在这里插入图片描述

  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  5. LinkedList比较适合任意位置插入的场景
LinkedList() 无参构造
public LinkedList(Collection<? extends E> c) 使用其他集合容器中元素构造List
            List<Integer> list2 = new LinkedList<>();list2.add(1);list2.add(2);List<Integer> list3 = new LinkedList<>(list2);

extends E表示E或者E的子类,E在这里指的就是Integer
所以构造方法可以传入参数

Collection<Integer>

E就是

            List<Integer> list3 = new LinkedList<>(list2);

中的Integer
而?是

            List<Integer> list2 = new LinkedList<>();

中的Integer
所以可以传,可以这样构造

            ArrayList<Integer> list4 = new ArrayList<>();list4.add(1);List<Integer> ret = new LinkedList<>(list4);

这样也可以,是因为ArrayList也实现了Collection接口,所以可以传
而且ArrayList的?也是Integer所以可以传

boolean add(E e) 尾插 e
void add(int index, E element) 将 e 插入到 index 位置
boolean addAll(Collection<? extends E> 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 是否在线性表中
int indexOf(Object o) 返回第一个 o 所在下标
int lastIndexOf(Object o) 返回最后一个 o 的下标
List subList(int fromIndex, int toIndex) 截取部分 list

        LinkedList<Integer> list = new LinkedList<>();List<Integer> list2 = new LinkedList<>();list2.add(1);list2.add(2);list2.add(1,3);System.out.println(list2);

在这里插入图片描述
在这里插入图片描述
clear就是清空了

        for (Integer integer : list2) {System.out.println(integer);}
        for (int i = 0; i < list2.size(); i++) {System.out.println(list2.get(i));}
        Iterator<Integer> iterator = list2.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}
        Iterator<Integer> iterator2 = list2.listIterator();while (iterator2.hasNext()) {System.out.println(iterator2.next());}

反正和前面的ArrayLis是一样的

在这里插入图片描述

3. 栈

        Stack<Integer> stack = new Stack<>();stack.push(1);stack.push(2);stack.push(3);//入栈,返回值就是入栈元素3stack.pop();//出栈,返回值就是出栈元素3Integer peek = stack.peek();//获取栈顶元素,不删除
        boolean empty = stack.isEmpty();

手动实现的话,就用数组—》顺序栈
用链表实现的话—》链式栈

4. 队列

Queue是个接口,底层是通过链表实现的

Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

        Queue<Integer> queue = new LinkedList<>();queue.offer(1);queue.offer(2);queue.offer(3);//放入队列元素System.out.println(queue.poll());//取出对头元素,System.out.println(queue.peek());//获取对头元素,不删除System.out.println(queue.peek());

在这里插入图片描述

        queue.isEmpty();

offer就是尾插

手动实现的话,就用LinkedList就可以实现了

在这里插入图片描述
或者自己定义节点也可以
两个队列来实现栈
在这里插入图片描述
在这里插入图片描述

两个栈来实现队列

        ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();

这是一个双端队列
Deque也是双端队列,只不过这个是接口

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

在这里插入图片描述
双端队列,就是两边都可以进出

        Deque<Integer> deque = new LinkedList<>();//链式deque.offerFirst(1);Deque<Integer> deque2 = new ArrayDeque<>();//顺序

LinkedList和ArrayDeque都可以当做栈和队列使用

5. 二叉树

class TreeNode{int val;public TreeNode left;public TreeNode right;TreeNode(int x){val = x;}
}

还有前序遍历(根左右),中序遍历(左根右),后序遍历(左右根)

层序遍历

6. PriorityQueue优先级队列(堆)

队列是一种先进先出(FIFO)的数据结构

操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列

PriorityQueue底层使用了堆这种数据结构

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆

堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。

小根堆:根节点的大小,小于孩子节点

在这里插入图片描述
根节点大于左右孩子—》大根堆

将元素存储到数组中后,可以根据二叉树章节的性质对树进行还原。假设i为节点在数组中的下标,则有:
如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子
如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,多线程的情况下使用这个

        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();priorityQueue.offer(1);priorityQueue.offer(34);priorityQueue.offer(3);System.out.println(priorityQueue.peek());//获取第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素

PriorityQueue默认是一个小根堆

在这里插入图片描述
传入比较器就可以控制是大根,还是小根了

. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常

不能插入null对象,否则会抛出NullPointerException
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
5. 插入和删除元素的时间复杂度为
6. PriorityQueue底层使用了堆数据结构
. PriorityQueue默认情况下是小堆—即每次获取到的元素都是最小的元素

        ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(list);priorityQueue.offer(5);priorityQueue.offer(34);priorityQueue.offer(6);System.out.println(priorityQueue.peek());//获取第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素

在这里插入图片描述

boolean offer(E e)
插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时
间复杂度 ,注意:空间不够时候会进行扩容
E peek() 获取优先级最高的元素,如果优先级队列为空,返回null
E poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size() 获取有效元素的个数
void clear() 清空
boolean isEmpty()检测优先级队列是否为空,空返回true

我们自己传入一个Comparator,就可以实现大根堆了
在这里插入图片描述
默认的Integer实现了Comparator,
在这里插入图片描述
但是它的Comparator是小根的形式
所以我们要搞一个大根堆的Comparator

class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}
}

这个就是原来的小根

class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o2.compareTo(o1);}
}

这样就是大根了

        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());priorityQueue.offer(5);priorityQueue.offer(34);priorityQueue.offer(6);System.out.println(priorityQueue.peek());//获取第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素System.out.println(priorityQueue.poll());//删掉第一个元素

在这里插入图片描述
这样就成功了

在这里插入图片描述
在这里插入图片描述
我们发现,堆的扩容是,如果原来容量小于64,就扩大两倍+2
如果大于64,就是扩大50%,就变为原来的150%

在这里插入图片描述

优先级队列的扩容说明:
如果容量小于64时,是按照oldCapacity的2倍方式扩容的
如果容量大于等于64,是按照oldCapacity的1.5倍方式扩容的
如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够
进行比较,为了简单起见,我们只是插入了Integer类型,那优先级队列中能否插入自定义类型对象呢?

在Java中,基本类型的对象可以直接比较大小。

Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。 那为什么==可以比较?

:对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法,但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址,但有些情况下该种比较就不符合题意。

在这里插入图片描述

有些情况下,需要比较的是对象中的内容,比如:向优先级队列中插入某个对象时,需要对按照对象中内容来调整堆,那该如何处理呢?

6.1 覆写基类的equals

class Card{public int rank;@Overridepublic boolean equals(Object o) {if(this == o) return true;//自己和自己比较返回trueif(o==null||!(o instanceof Card)){return false;}Card card = (Card) o;return rank == card.rank;}}

覆写基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。

6.2 基于Comparble接口类的比较

class Card implements Comparable<Card>{public int rank;@Overridepublic boolean equals(Object o) {if(this == o) return true;//自己和自己比较返回trueif(o==null||!(o instanceof Card)){return false;}Card card = (Card) o;return rank == card.rank;}@Overridepublic int compareTo(@NotNull Card o) {return this.rank - o.rank;}
}

这个是从小到大的排序
这样就可以了

        Card card = new Card(1);Card card2 = new Card(2);System.out.println(card.compareTo(card2));

在这里插入图片描述

6.3 基于比较器比较

class RankComparator implements Comparator<Card>{@Overridepublic int compare(Card o1, Card o2) {return o2.rank-o1.rank;}
}
        RankComparator rankComparator = new RankComparator();System.out.println(rankComparator.compare(card, card2));

在这里插入图片描述
Object.equals 因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与否
Comparable.compareTo
需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于
内部顺序----》可以调用Arrays.sort()方法来对数组进行排序了
Comparator.compare
需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性

        Card[] cards = new Card[]{card, card2};Arrays.sort(cards);Arrays.sort(cards, rankComparator);

这两个都是可以的

总结

http://www.dtcms.com/a/618788.html

相关文章:

  • 如何在godaddy空间做手机网站资源wordpress
  • 【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷 5
  • 建立网站需要注册公司吗小制作废品利用
  • thinkphp做直播网站wordpress极验验证注册
  • 世赛网站开发拉新推广
  • SLAM中的非线性优-3D图优化之李群李代数在Opencv-PNP中的应用(四)
  • 做网站什么分类流量多动漫设计与制作学校
  • Vue 项目实战《尚医通》,预约挂号就诊人组件搭建上,笔记40
  • 网站报价方案 模板医疗网站专题怎样做
  • 南京营销型网站商业网站的相关内容
  • 做实验教学视频的网站亚马逊关键词搜索器
  • 差异功能定位解析:C语言与C++(区别在哪里?)
  • 【c++中间件】spdlog日志介绍 二次封装
  • 设计网站中如何设置特效wordpress自定义短码
  • 4.FPGA字符格式
  • 网站服务器有问题怎么办啊南宁手机建站公司
  • 【Java 基础】4 面向对象 - 封装:面向对象三大特征之一
  • vps建设网站需要条件瀑布流资源网站模板
  • 还有做网站的必要吗识图 WordPress
  • 俄语 俄文 俄罗斯语外贸网站建设礼品定制
  • 郑州好的建网站公司wordpress 采集器
  • 轻松设置-系统优化万能工具
  • query加强之深度解析ReDI:通过分解与解释增强query理解的推理方法
  • 观点动力学和回音室
  • 中小学网站建设域名论坛网站
  • 5.网络原理之TCP_IP
  • 全球访问量top100网站建设银行官方网站-云服务
  • 小梦音乐下载 1.0.5 | 提供三条音源,支持多种音质选择和批量下载的音乐下载工具
  • GIS:揭开你神秘的面纱
  • 怎么做网站小图标有的网站域名解析错误