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

wordpress gfw图片优化是什么意思

wordpress gfw,图片优化是什么意思,沈阳做网站多少钱,做cpa的博客网站类型版本说明 当前版本号[20231004]。 版本修改说明20231004初版 目录 文章目录 版本说明目录二. 基础数据结构2.1 数组1) 概述2) 动态数组1)插入addlast 方法测试: addlast 方法 add 方法测试:add方法 addlast 方法与 add 方法合并版get 方法测试&#x…

版本说明

当前版本号[20231004]。

版本修改说明
20231004初版

目录

文章目录

  • 版本说明
  • 目录
  • 二. 基础数据结构
    • 2.1 数组
      • 1) 概述
      • 2) 动态数组
        • 1)插入
          • addlast 方法
            • 测试: addlast 方法
          • add 方法
            • 测试:add方法
          • addlast 方法与 add 方法合并版
          • get 方法
            • 测试:get 方法
        • 2) 遍历
          • 遍历方法1:consumer 遍历
            • 测试:consumer 遍历
          • 遍历方法2:迭代器遍历
            • 测试:迭代器遍历
          • 遍历方法3:stream 遍历
            • 测试:stream 遍历
        • 插入与遍历方法汇总
        • 插入与遍历测试类汇总
        • 3)删除
          • 测试:删除方法
        • 4)扩容
        • 5)插入或删除性能
      • 3) 二维数组
        • **测试**
      • 4) 局部性原理
        • **对效率的影响**

二. 基础数据结构

2.1 数组

1) 概述

定义

在计算机科学中,数组是由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识

因为数组内的元素是连续存储的,所以数组中元素的地址,可以通过其索引计算出来,例如:

int[] array = {1,2,3,4,5}

知道了数组的数据起始地址 B a s e A d d r e s s BaseAddress BaseAddress,就可以由公式 B a s e A d d r e s s + i ∗ s i z e BaseAddress + i * size BaseAddress+isize 计算出索引 i i i 元素的地址

  • i i i 即索引,在 Java、C 等语言都是从 0 开始
  • s i z e size size 是每个元素占用字节,例如 i n t int int 4 4 4 d o u b l e double double 8 8 8

小测试

byte[] array = {1,2,3,4,5}

已知 array 的数据的起始地址是 0x7138f94c8,那么元素 3 的地址是什么?

答:0x7138f94c8 + 2 * 1 = 0x7138f94ca

空间占用

Java 中数组结构为

  • 8 字节 markword
  • 4 字节 class 指针(压缩 class 指针的情况)
  • 4 字节 数组大小(决定了数组最大容量是 2 32 2^{32} 232
  • 数组元素 + 对齐字节(java 中所有对象大小都是 8 字节的整数倍[^12],不足的要用对齐字节补足)

例如

int[] array = {1, 2, 3, 4, 5};

的大小为 40 个字节,组成如下

8 + 4 + 4 + 5*4 + 4(alignment)

随机访问性能

即根据索引查找元素,时间复杂度是 O ( 1 ) O(1) O(1)

2) 动态数组

1)插入
addlast 方法

意在把新增的元素加入到最后一个到动态数组里。

public class 动态数组
{private int size = 0;//逻辑大小private int capacity = 8;//所创建数组的数组容量private int[] array = new int[capacity];/*** 向最后位置 [size] 添加元素** @param element 待添加元素*/public void addlast(int element){array[size] = element;size++;}
}

这个类具有以下特点:

  • size变量表示当前数组中已存储的元素数量。
  • capacity变量表示数组的容量,即可以容纳的最大元素数量。
  • array是一个整型数组,用于存储元素。
  • addlast(int element)方法用于在数组的末尾添加一个元素,并将size增加1。
测试: addlast 方法

​ 这段代码作为一个JUnit测试类,在测试方法test1中,首先创建了一个动态数组对象,然后向数组中添加了5个元素,最后遍历数组并打印出每个元素的值。

package SuanFa.test;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import SuanFa.初始算法.第一章数组.动态数组;
import java.util.Arrays;public class 动态数组Test {@Testpublic void test1(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.addlast(5);for(int i = 0; i < 5; i++){System.out.println(dynamicarray.get(i));}}
}

测试结果如下:

image-20231004104127182

注:接下来的所有方法中将只保留最主要的代码。

add 方法

意在向某一个索引里加入新值。

     /*** 向 [0 .. size] 位置添加元素** @param index   索引位置* @param element 待添加元素*/public void add(int index, int element){if(index >=0 && index < size){System.arraycopy(array, index, array, index+1, size - index);array[index] = element;size++;}}

这个类具有以下特点:

  • size变量表示当前数组中已存储的元素数量。
  • capacity变量表示数组的容量,即可以容纳的最大元素数量。
  • array是一个整型数组,用于存储元素。
  • add(int index, int element)方法用于在指定索引位置插入到指定索引位置,并确保索引在合法范围内(大于等于0且小于当前数组大小)。
  • 如果索引合法,使用System.arraycopy()方法将原数组中从指定索引位置开始的元素向后移动一个位置,腾出空间来插入新元素。(复制 array 数组中从下标为 index 的元素复制到 array 数组的下标为 index+1 的元素上,并且只复制 size - index 的元素)
  • 将新元素赋值给指定索引位置。
  • 增加size变量的值,表示数组中已存储的元素数量增加了1。
  • 如果索引不合法,该方法不会执行任何操作。
测试:add方法

​ 这段代码作为一个JUnit测试类,在测试方法test1中,首先创建了一个动态数组对象,然后向数组中添加了4个元素,接着使用add方法在索引为2的位置插入了一个值为9的元素。最后遍历数组并打印出每个元素的值。

    @Testpublic void test2(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);//dynamicarray.addlast(5);dynamicarray.add(2, 9);for(int i = 0; i < 5; i++){System.out.println(dynamicarray.get(i));}}
}

测试结果如下:

image-20231004104452737

addlast 方法与 add 方法合并版

由于addlast与add方法中,都有 array[下标] = element; size++; 这两段代码,于是也可以对他们进行优化,放在一起

     /*** 向 [0 .. size] 位置添加元素** @param index   索引位置* @param element 待添加元素*/public void add(int index, int element){// 添加逻辑if(index >=0 && index < size){// 向后挪动, 空出待插入位置System.arraycopy(array, index,array, index+1, size - index);}array[index] = element;size++;}/*** 向最后位置 [size] 添加元素** @param element 待添加元素*/public void addlast(int element){add(size, element);}

这个类具有以下特点:

  • size变量表示当前数组中已存储的元素数量。
  • capacity变量表示数组的容量,即可以容纳的最大元素数量。
  • array是一个整型数组,用于存储元素。
  • add(int index, int element)方法用于在指定索引位置插入一个元素。
  • addlast(int element)方法用于在数组的末尾添加一个元素。
  • add(int index, int element)方法将传入的元素插入到指定索引位置,并确保索引在合法范围内(大于等于0且小于当前数组大小)。
  • 如果索引合法,使用System.arraycopy()方法将原数组中从指定索引位置开始的元素向后移动一个位置,腾出空间来插入新元素。
  • 将新元素赋值给指定索引位置。
  • 增加size变量的值,表示数组中已存储的元素数量增加了1。
  • 如果索引不合法,该方法不会执行任何操作。
  • addlast(int element)方法调用add(int index, int element)方法,将元素添加到数组的末尾
  • 数组会自动调整大小以适应新元素的添加。
get 方法

意在接收一个整数参数 index ,返回数组中下标为 index 的元素

        /*** 查询元素** @param index 索引位置, 在 [0..size) 区间内* @return 该索引位置的元素*/public int get(int index){return array[index];}

这个类具有以下特点:

  • size变量表示当前数组中已存储的元素数量。
  • capacity变量表示数组的容量,即可以容纳的最大元素数量。
  • array是一个整型数组,用于存储元素。
  • 查询方法get接收一个整数参数 index ,返回数组中下标为 index 的元素
测试:get 方法

与测试:addlast 方法相同

    @Testpublic void test1(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.addlast(5);for(int i = 0; i < 5; i++){System.out.println(dynamicarray.get(i));}}
2) 遍历
遍历方法1:consumer 遍历

​ 这段代码定义了一个名为 foreach 的方法,该方法接收一个 Consumer 类型的参数consumer。在方法内部,使用for循环遍历数组array,**对于每个元素,调用consumer的accept方法执行传入的操作。**最后,forEach方法没有返回值(void)。

    /*** 遍历方法1** @param consumer 遍历要执行的操作, 入参: 每个元素*/public void foreach(Consumer<Integer> consumer){for(int i = 0; i<size ; i++)// 提供 array[i]// 返回 void{consumer.accept(array[i]);}}
测试:consumer 遍历

​ 在该测试方法中,首先创建了一个动态数组对象dynamicarray,并向其中添加了5个元素。然后调用forEach方法遍历数组,对于每个元素,使用Lambda表达式打印出该元素的值。

public class 动态数组Test {@Testpublic void test3(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.forEach((element->{System.out.println(element);}));}
}

测试结果如下:

image-20231004163648866

遍历方法2:迭代器遍历

​ 该动态数组类实现了Iterable接口,并重写了iterator方法

在类中重写了Iterable接口的iterator方法,返回一个Iterator对象,该对象实现了Iterator接口的方法hasNext和next。其中,hasNext方法用于判断是否还有下一个元素,next方法用于**返回当前元素并将指针移动到下一个元素。**由于没有给出数组元素的添加和删除操作,因此该类的迭代器只能从头到尾遍历一遍数组。

public class 动态数组 implements Iterable<Integer>
{private int size = 0;//逻辑大小private int capacity = 8;//容量private int[] array = new int[capacity];/*** 遍历方法2 - 迭代器遍历*/@Overridepublic Iterator<Integer> iterator(){return new Iterator<Integer>() {int i = 0;@Overridepublic boolean hasNext() { // 有没有下一个元素return i < size;}@Overridepublic Integer next() { // 返回当前元素,并移动到下一个元素return array[i++];}};
}
测试:迭代器遍历

​ 使用增强for循环遍历数组,对于每个元素,打印出该元素的值。

@Testpublic void test4(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);for(Integer element: dynamicarray){System.out.println(element);}}

测试结果如下:

image-20231004112314866

遍历方法3:stream 遍历

​ 这段代码定义了一个名为stream的公共方法,该方法返回一个IntStream类型的对象。在方法内部,使用IntStream.of()方法创建一个包含数组array中前size个元素的IntStream流并返回该流。

    /*** 遍历方法3 - stream 遍历** @return stream 流*/
public IntStream stream(){return IntStream.of(Arrays.copyOfRange(array,0,size));}
测试:stream 遍历
 @Testpublic void test5(){动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(7);dynamicarray.addlast(2);dynamicarray.addlast(4);dynamicarray.addlast(1);dynamicarray.stream().forEach(element->{System.out.println(element);});}

测试结果如下:

image-20231004164731217

插入与遍历方法汇总

​ 以下这段代码定义了一个名为动态数组的类,汇总了所有方法,实现了Iterable接口。该类方法分别有:

  1. add(int index, int element):向指定索引位置添加元素的方法。如果索引有效(即大于等于0且小于当前大小),则将该位置及之后的元素向后移动一位,然后将新元素放置在指定索引位置上,并将大小加1。
  2. addlast(int element):向数组末尾添加元素的方法。调用add(size, element)实现。
  3. get(int index):获取指定索引位置的元素的方法。
  4. foreach(Consumer<Integer> consumer):遍历数组并对每个元素执行给定的消费者操作。
  5. stream():返回一个IntStream流,其中包含数组中的所有元素。使用Arrays.copyOfRange(array, 0, size)创建一个包含数组元素的新数组,并将其转换为IntStream流。
package SuanFa.初始算法.第一章数组;import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;public class 动态数组 implements Iterable<Integer> {private int size = 0;//逻辑大小private int capacity = 8;//容量private int[] array = new int[capacity];@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {int i = 0;@Overridepublic boolean hasNext() { // 有没有下一个元素return i < size;}@Overridepublic Integer next() { // 返回当前元素,并移动到下一个元素return array[i++];}};}public void add(int index, int element) {if (index >= 0 && index < size) {System.arraycopy(array, index,array, index + 1, size - index);}array[index] = element;size++;}public void addlast(int element) {add(size, element);}public int get(int index) {return array[index];}public void foreach(Consumer<Integer> consumer) {for (int i = 0; i < size; i++) {consumer.accept(array[i]);}}public IntStream stream() {return IntStream.of(Arrays.copyOfRange(array, 0, size));}
}
插入与遍历测试类汇总

该类包含了5个测试方法:

  1. test1():测试了向动态数组末尾添加元素的功能。首先创建了一个空的动态数组对象dynamicarray,然后连续调用addlast()方法向数组末尾添加了5个元素(1到5)。最后使用循环遍历数组并打印每个元素的值。
  2. test2():测试了在指定位置插入元素的功能。首先创建了一个空的动态数组对象dynamicarray,然后连续调用addlast()方法向数组末尾添加了5个元素(1到5)。接着调用add()方法在索引为2的位置插入了一个新元素9。最后使用循环遍历数组并打印每个元素的值。
  3. test3():测试了使用IntStream流遍历动态数组的功能。首先创建了一个空的动态数组对象dynamicarray,然后连续调用addlast()方法向数组末尾添加了5个元素(1到5)。接着调用stream()方法获取一个包含数组元素的IntStream流,并使用forEach()方法对每个元素执行打印操作。
  4. test4():测试了使用for-each循环遍历动态数组的功能。首先创建了一个空的动态数组对象dynamicarray,然后连续调用addlast()方法向数组末尾添加了5个元素(1到5)。接着使用for-each循环遍历数组,并在每次迭代中打印当前元素的值。
  5. test5():测试了在动态数组中间插入元素的功能。首先创建了一个空的动态数组对象dynamicarray,然后连续调用addlast()方法向数组末尾添加了4个元素(7、2、4、1)。最后使用流
package SuanFa.test;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;import SuanFa.初始算法.第一章数组.动态数组;import java.lang.annotation.ElementType;
import java.util.Arrays;public class 动态数组Test {@Testpublic void test1() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.addlast(5);for (int i = 0; i < 5; i++) {System.out.println(dynamicarray.get(i));}}@Testpublic void test2() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.add(2, 9);for (int i = 0; i < 5; i++) {System.out.println(dynamicarray.get(i));}}@Testpublic void test3() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.stream().forEach(element -> {System.out.println(element);});}@Testpublic void test4() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);for (Integer element : dynamicarray) {System.out.println(element);}}@Testpublic void test5() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(7);dynamicarray.addlast(2);dynamicarray.addlast(4);dynamicarray.addlast(1);dynamicarray.stream().forEach(element -> {System.out.println(element);});}
}
3)删除

​ 该方法接受一个整数参数 index,表示要删除元素的索引位置。

​ 首先,它将要删除的元素保存在变量 removed 中。然后,使用 System.arraycopy() 方法将索引位置后的元素向前移动一位,覆盖掉要删除的元素。

​ 接下来,通过将数组的大小减一来更新数组的大小。

​ 最后,返回被删除的元素。

/*** 从 [0 .. size) 范围删除元素** @param index 索引位置* @return 被删除元素*/
public int remove(int index){// 保存要删除的元素int removed = array[index];// 将索引位置后的元素向前移动一位System.arraycopy(array, index + 1, array, index, size - index - 1);// 更新数组的大小size--;// 返回被删除的元素return removed;
}
测试:删除方法

​ 这是一个J用于测试动态数组的测试类。首先创建一个dynamicarray的动态数组对象,然后使用addlast方法向数组中添加元素1、2、3、4和5。接着**调用remove方法移除索引为2的元素,并将其值赋给变量removed。**最后,使用stream方法和forEach遍历打印数组中的所有元素。

@Testpublic void test6() {动态数组 dynamicarray = new 动态数组();dynamicarray.addlast(1);dynamicarray.addlast(2);dynamicarray.addlast(3);dynamicarray.addlast(4);dynamicarray.addlast(5);int removed = dynamicarray.remove(2);System.out.println(removed);System.out.println("-----");dynamicarray.stream().forEach(element -> {System.out.println(element);});}

测试结果如下:

image-20231004201626597

4)扩容
  • ​ 该方法首先进行容量检查。
  • ​ 如果当前数组的大小为0,即数组为空,那么将创建一个新的数组,其容量为capacity
  • ​ 如果当前数组的大小等于容量,即数组已满,那么将通过将容量增加至原来的两倍来扩展数组。
  • ​ 然后,创建一个新的数组newArray,其容量为新的容量值。
  • ​ 接下来,使用System.arraycopy()方法将原数组中的元素复制到新数组中。
  • ​ 最后,将新数组赋值给原数组,完成数组的扩展操作。
  • ​ 这个方法通常用于动态数组的管理,以确保数组在插入元素时能够自动调整其容量大小,以适应不断增长的数据量。
  private void checkAndGrow() {// 容量检查if (size == 0) {array = new int[capacity];} else if (size == capacity) {capacity += capacity >> 1;int[] newArray = new int[capacity];System.arraycopy(array, 0,newArray, 0, size);array = newArray;}}
5)插入或删除性能

部位置,时间复杂度是 O ( n ) O(n) O(n)

间位置,时间复杂度是 O ( n ) O(n) O(n)

部位置,时间复杂度是 O ( 1 ) O(1) O(1)(均摊来说)

3) 二维数组

int[][] array = {{11, 12, 13, 14, 15},{21, 22, 23, 24, 25},{31, 32, 33, 34, 35},
};
  • 二维数组占 32 个字节,其中 array[0],array[1],array[2] 三个元素分别保存了指向三个一维数组的引用

  • 三个一维数组各占 40 个字节

  • 它们在内层布局上是连续

更一般的,对一个二维数组 A r r a y [ m ] [ n ] Array[m][n] Array[m][n]

  • m m m 是外层数组的长度,可以看作 row 行
  • n n n 是内层数组的长度,可以看作 column 列
  • 当访问 A r r a y [ i ] [ j ] Array[i][j] Array[i][j] 0 ≤ i < m , 0 ≤ j < n 0\leq i \lt m, 0\leq j \lt n 0i<m,0j<n时,就相当于
    • 先找到第 i i i 个内层数组(行)
    • 再找到此内层数组中第 j j j 个元素(列)
测试

Java 环境下(不考虑类指针和引用压缩,此为默认情况),有下面的二维数组

byte[][] array = {{11, 12, 13, 14, 15},{21, 22, 23, 24, 25},{31, 32, 33, 34, 35},
};

已知 array 对象起始地址是 0x1000,那么 23 这个元素的地址是什么?

答:

  • 起始地址 0x1000
  • 外层数组大小:16字节对象头 + 3元素 * 每个引用4字节 + 4 对齐字节 = 32 = 0x20
  • 第一个内层数组大小:16字节对象头 + 5元素 * 每个byte1字节 + 3 对齐字节 = 24 = 0x18
  • 第二个内层数组,16字节对象头 = 0x10,待查找元素索引为 2
  • 最后结果 = 0x1000 + 0x20 + 0x18 + 0x10 + 2*1 = 0x104a

4) 局部性原理

这里只讨论空间局部性

  • cpu 读取内存(速度慢)数据后,会将其放入高速缓存(速度快)当中,如果后来的计算再用到此数据,在缓存中能读到的话,就不必读内存了
  • 缓存的最小存储单位是缓存行(cache line),一般是 64 bytes,一次读的数据少了不划算啊,因此最少读 64 bytes 填满一个缓存行,因此读入某个数据时也会读取其临近的数据,这就是所谓空间局部性
对效率的影响

比较下面 ij 和 ji 两个方法的执行效率

int rows = 1000000;
int columns = 14;
int[][] a = new int[rows][columns];StopWatch sw = new StopWatch();
sw.start("ij");
ij(a, rows, columns);
sw.stop();
sw.start("ji");
ji(a, rows, columns);
sw.stop();
System.out.println(sw.prettyPrint());

ij 方法

public static void ij(int[][] a, int rows, int columns) {long sum = 0L;for (int i = 0; i < rows; i++) {for (int j = 0; j < columns; j++) {sum += a[i][j];}}System.out.println(sum);
}

ji 方法

public static void ji(int[][] a, int rows, int columns) {long sum = 0L;for (int j = 0; j < columns; j++) {for (int i = 0; i < rows; i++) {sum += a[i][j];}}System.out.println(sum);
}

执行结果

0
0
StopWatch '': running time = 96283300 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
016196200  017%  ij
080087100  083%  ji

可以看到 ij 的效率比 ji 快很多,为什么呢?

  • 缓存是有限的,当新数据来了后,一些旧的缓存行数据就会被覆盖
  • 如果不能充分利用缓存的数据,就会造成效率低下

以 ji 执行为例,第一次内循环要读入 [ 0 , 0 ] [0,0] [0,0] 这条数据,由于局部性原理,读入 [ 0 , 0 ] [0,0] [0,0] 的同时也读入了 [ 0 , 1 ] . . . [ 0 , 13 ] [0,1] ... [0,13] [0,1]...[0,13],如图所示

image-20221104164329026

但很遗憾,第二次内循环要的是 [ 1 , 0 ] [1,0] [1,0] 这条数据,缓存中没有,于是再读入了下图的数据

image-20221104164716282

这显然是一种浪费,因为 [ 0 , 1 ] . . . [ 0 , 13 ] [0,1] ... [0,13] [0,1]...[0,13] 包括 [ 1 , 1 ] . . . [ 1 , 13 ] [1,1] ... [1,13] [1,1]...[1,13] 这些数据虽然读入了缓存,却没有及时用上,而缓存的大小是有限的,等执行到第九次内循环时

image-20221104164947154

缓存的第一行数据已经被新的数据 [ 8 , 0 ] . . . [ 8 , 13 ] [8,0] ... [8,13] [8,0]...[8,13] 覆盖掉了,以后如果再想读,比如 [ 0 , 1 ] [0,1] [0,1],又得到内存去读了

http://www.15wanjia.com/news/53875.html

相关文章:

  • 网站建设一般一年多少费用宁波优化网站哪家好
  • 中文网站建设制作英文网站建设
  • 如何免费自己做个网站谷歌seo一个月费用需要2万吗
  • 微信网站需要一个域名要怎么做新浪微指数
  • 东莞手机网站站定制开发app地推接单平台
  • 青岛网站建设服务公司近三天发生的重要新闻
  • 购买主机可以做网站吗郑州seo优化外包顾问
  • 杭州鼎易做的网站郑州网站优化顾问
  • 做电商网站需要会些什么条件郑州今日头条
  • 网站开发软件技术开发公司百度2019旧版本下载
  • 世界500强企业招聘网站今日头条十大热点
  • 做线下极限运动的网站百度灰色关键词排名
  • 显示电脑没有安装wordpress东莞seo
  • 网站怎么做动态图片电商代运营一般收多少服务费
  • 网站建设什么意思中国做网站的公司排名
  • 郴州网站建设推广方案百度人工客服电话24小时
  • 腾讯企业服务账号是多少seo排名优化推广
  • 可以做问卷的网站有哪些管理培训班
  • 全国住房建设部网站百度快速排名点击器
  • 海南在线人才网招聘建站seo推广
  • 郑州知名网站建设南通百度网站快速优化
  • 低价网站建设怎么样怎么在百度做网站推广
  • 龙口建网站公司价格广州seo技术优化网站seo
  • 网站开发摊销郑州seo线上推广技术
  • 个人网站推广搜索引擎
  • 做网站和做app哪个难营销是什么
  • 中英文网站建设价格全网营销推广公司
  • 佛山营销网站建设服务公司产品推广方法
  • 做企业平台的网站台州关键词优化平台
  • 海南一家天涯社区seo是什么意思 职业