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

抚顺少儿编程哪家好seo岗位

抚顺少儿编程哪家好,seo岗位,淘宝客网站建设分类,烟台网站建设公司报价手撕vector目录: 一、基本实现思路方针 二、vector的构造函数剖析(构造歧义拷贝构造) 2.1构造函数使用的歧义问题 2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起) 三、vector的…

手撕vector目录:

一、基本实现思路方针

二、vector的构造函数剖析(构造歧义+拷贝构造)

2.1构造函数使用的歧义问题

2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起)

三、vector的基本接口

3.1empty和clear

3.2 size和capacity

3.3  [ ]和iterator

四、 resize和reserve

五、尾插尾删

六、迭代器失效

6.1 insert

6.2 erase

七、vector.h


一、基本实现思路方针

本篇的目的很简单,只有一个:模拟实现vector

如何去模拟实现?我们可以看看vector的源码,我们可以抽离出主体框架:

namespace lzy//防止命名冲突
{template<class T>class lzy_vector{public:typedef T* iterator;typedef const T* const_iterator;public://成员函数private:T* _start;T* _finish;T* _end_of_storage;}
}

对于size = _finish - _start

对于capacity = _endofstorage-_start

可以看到,vector 的底层和 string 一样,都是一个指针指向一块动态开辟的数组,但是二者不同的是,string 是用 T* str 和 _size 和 _capacity 三个成员变量来维护这块空间,而 vector 是用 _finish 和 _end_of_storage 两个指针来维护这块空间;虽然 vector 使用指针看起来难了一些,但本质上其实是一样的 : _size = _finish - _start, _capacity = _end_of_storage - _start;

 有了这些作为铺垫,我们对于vector的模拟实现大概有了一个基本的框架,话不多说,直接进入主题👇


二、vector的构造函数剖析(构造歧义+拷贝构造)

1. 无参的构造函数,我们利用初始化列表来进行初始化。用nullptr初始化比较好,因为nullptr的free或delete都不会出错 

2. 另一种构造是用n个value值来进行构造,value既有可能是内置类型,也有可能是自定义类型,所以如果用引用作参数的话,需要用const引用,也就是常引用来作参数,否则无法接收内置类型的实参

3. 除无参构造外,常用的构造还有迭代器区间作为参数的构造函数。这里的迭代器需要用函数模板来实现,因为构造vector所用的迭代器不一定只是vector类型的,还有可能是string类型,所以这里的迭代器形参需用模板来实现

 lzy_vector() // 初始化列表给空指针:_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}//n个val构造lzy_vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (size_t i = 0; i < n; i++)push_back(val);}//迭代器区间构造template<class InputIterator>lzy_vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while (first != last){push_back(*first);++first;}}

吐槽:经过一番折腾,总算是有了个输出结果,要不是reserve没写,要不就是push_back没写,要不就是类模板没搞,要不就是迭代器输出的时候迭代器的begin没写。。。。

2.1构造函数使用的歧义问题

1. 在实现完n个value构造的构造函数之后,如果我们此时用10个int类型的数字1来构造对象v1,实际会报错,报错的原因其实是由于函数的匹配优先级所导致的实参无法正确匹配相应的构造函数而使用10个char类型的字符A却不会报错,这其实也是由于函数的匹配优先级决定的 

2.  对于size_t和常引用作为参数的构造来说,它的匹配优先级对于10个1实际不是最高的,因为常引用需要进行类模板参数T类型的推导,而10又是整型int,int到size_t还需要进行隐式类型转换,代价有点大


而对于迭代器区间作为参数的构造来讲,函数模板参数InputIterator只需要进行一次类型推导即可完成匹配,所以用10个1来构造时,实际匹配的构造函数是迭代器区间作为参数的构造函数,而在匹配的构造函数中,对迭代器区间进行了解引用,那就是对常量10进行了解引用,则发生非法的间接寻址(用了迭代器区间的构造函数,会报错)

3 对于这种问题的解决,可以将size_t换成int类型,或者将10强转为size_t类型,但stl源码的解决方式并非是这样的,而是利用了函数重载来解决了这个问题,多重载了一个类型为int的构造函数

好的,我们继续开干!上面的代码运行结果正确

 解决方法:

2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起)

1. 对于拷贝构造的实现,和string一样,还是有传统写法和利用打工人的现代写法,利用打工人的本质实际就是代码重构。传统写就是提前用reserve预留好空间,然后push_back将数据尾插到提前预留的空间当中(这个逻辑还是非常清楚的)

这里让我想起来一个知识点:那会vector介绍接口的时候,我们存在越界访问的问题,我们在reserve之后, 利用[ ] 进行赋值,这样是不对的,因为我们只有capacity,没有size。但是利用push_back插入数据的时候,会进行检查:如果size为0,那么就会赋值,所以reserve之后push_back是合理的

注意:拷贝构造这么写是不对的(我本以为是我的接口写的不完善,但是在std中运行发现也是报错)

原因: 

而使用拷贝构造的时候必须这样:

void testvector()
{lzy::lzy_vector<int> v1(10,1);lzy::lzy_vector<int> v2(v1);for(auto e : v2){cout << e << " ";}
}
int main()
{testvector();return 0;
}

2. 无论是从代码可读性还是实用性的角度来讲,现代写法都更胜一筹,这里利用形参对象v的迭代器来构造临时对象tmp,然后将对象tmp和* this进行交换为了防止对象tmp离开函数栈帧销毁时造成野指针的访问问题,所以在调用构造函数时采用了初始化列表的方式将* this的三个成员都初始化为nullptr(原先埋下的伏笔,居然在这里展现出来了

注:别忘了重新写swap函数

lzy_vector(const lzy_vector<T>& v):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){vector<T> tmp(v.begin(), v.end());  //利用了迭代器模板swap(tmp);}

3. 在实现拷贝构造后,实现赋值重载就比较简单了,利用传值拷贝构造的临时对象即可,然后调用swap类成员函数即可完成自定义类型的赋值工作。为了符合连续赋值含义,我们利用引用来作为返回值。

lzy_vector<T>& operator=(lzy_vector<T> v)  //复用拷贝构造,存在自我赋值的问题,但不影响程序正确性{swap(v);return *this;}

注意:参数不可以加引用,正常来说,v1=v2; 如果加上引用的话,v2就会变成v1的值

总结:由于拷贝构造必须有引用,所以函数体内另外找了一个打工人,但我们的赋值不需要,所以引用和tmp必须同时存在,这样才可以满足我们的逻辑


三、vector的基本接口

3.1empty和clear

empty

bool empty() const
{return _finish == _start;
}

clear

void clear()
{_finish = _start;//这里可不是置为nullptr哦
}

3.2 size和capacity

size

size_t size() const
{return _finish - _start;
}

capacity

size_t capacity() const 
{return _endofstorage - _start;
}

3.3  [ ]和iterator

[ ]

提供const版本和非const版本:

T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}const T& operator[](size_t pos)const
{assert(pos < size());return _start[pos];
}

 iterator

同理普通迭代器和const迭代器版本,同理,范围for循环此时也是可以实现的:

typedef T* iterator;
typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}

四、 resize和reserve

这两个接口需要单独拎出来,这是因为后面的插入等相关操作需要用到,所以我们先来看看这两个接口,同时这里有一些问题值得我们去注意:

resize

n个数据去初始化,这个n是多大,会造成什么影响?我们需要进行分类讨论:

//分情况
void resize(size_t n, const T& val = T())
{if (n > capacity()){reserve(n);}if (n > size()){while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}
}

 reserve

void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];//size()需要先保存起来,后面_start会发生改变size_t sz = size();//为空不需要拷贝了if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;//memcpy(tmp, _start, sizeof(T) * size());//浅拷贝//delete[] _start;}_start = tmp;_finish = _start+sz;_endofstorage = _start + n;}
}


五、尾插尾删

void push_back(const T& x)
{if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*_finish = x;++_finish;
}void pop_back()
{assert(_finish > _start);--_finish;
}


六、迭代器失效

6.1 insert

//迭代器失效:扩容引起野指针问题
void insert(iterator pos, const T& val)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;
}

 测试代码:

void Test3()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.insert(it, 30);}for (auto e : v){cout << e << " ";}cout << endl;
}

 

这是因为扩容导致pos失效了:

 

insert过程中发生扩容,导致it指向的空间实际上已经被释放,it指向已被释放的空间是野指针,造成了迭代器失效

所以,我们应该去更新pos,算出pos刚开始的相对位置,然后再去进行更新即可解决问题。但是此时外面调用insert的it仍然是失效的,因为是传值调用,形参改变不影响实参,可以通过返回值接收解决问题。(如果是传引用的话,只能传变量,而临时对象具有常性,不能调用,存在很多问题),所以直接用返回值解决。

改正代码:

iterator insert(iterator pos, const T& val)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){//扩容会导致pos迭代器失效,需要更新size_t len = pos - _start;size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;
}

6.2 erase

 挪动数据进行覆盖即可:

void erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;
}

 erase的pos也可能会导致pos失效,测试代码:

void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){v.erase(it);}++it;}for (auto e : v){cout << e << " ";}cout << endl;}

 

测试发现:

1,2,3,4的时候发生崩溃

1,2,2,3,5结果只删了一个2

1,2,3,4,5结果是正常的

image-20221127140628122

 

上述代码在VS下,当erase(it)之后,it指向的位置发生改变,然后在++it的话,会出现问题,出现一些错误,造成迭代器失效。

我们最好统一认为失效了。

正确的erase:

iterator erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;
}		

 测试代码:
 

void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}

七、vector.h

#include<iostream>
using namespace std;
namespace lzy
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos)const{assert(pos < size());return _start[pos];}vector():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}/*vector(const vector<T>& v):_start(nullptr),_finish(nullptr),_endofstorage(nullptr){reserve(v.capacity());for (const auto& e : v){push_back(e);}}*///vector<int> v1(10, 5);//vector<char> v2(10, 'A');vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}//改成int或强转vector(int n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}template <class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){while (first != last){push_back(*first);//int不能解引用++first;}}vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){vector<T> tmp(v.begin(), v.end());swap(tmp);}//缺陷:自己拷贝自己vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t sz = size();//为空不需要拷贝了if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;//memcpy(tmp, _start, sizeof(T) * size());//浅拷贝//delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}//分情况void resize(size_t n, const T& val = T()){if (n > capacity()){reserve(n);}if (n > size()){while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}bool empty() const{return _finish == _start;}size_t size() const{return _finish - _start;}size_t capacity() const{return _endofstorage - _start;}void push_back(const T& x){if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*_finish = x;++_finish;}void pop_back(){assert(_finish > _start);--_finish;}//迭代器失效:野指针问题/*void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos < _finish);if (_finish == _endofstorge){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}*/iterator insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){//扩容会导致pos迭代器失效,需要更新size_t len = pos - _start;size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}void clear(){_finish = _start;}public:iterator _start;iterator _finish;iterator _endofstorage;};void Test1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout << v.size() << endl;cout << v.capacity() << endl;for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;}void Test2(){vector<int> v;v.resize(10, -1);for (auto e : v){cout << e << " ";}cout << endl;v.resize(5);for (auto e : v){cout << e << " ";}cout << endl;v.pop_back();v.pop_back();v.pop_back();v.pop_back();v.pop_back();v.pop_back();}void Test3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.end(), 0);for (auto e : v){cout << e << " ";}cout << endl;vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.insert(it, 30);}for (auto e : v){cout << e << " ";}cout << endl;}void Test4(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){//传值v.insert(it, 30);}//insert以后it不能使用,可能迭代器失效(野指针)//(*it)++;for (auto e : v){cout << e << " ";}cout << endl;}void Test5(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.erase(it);}cout << *it << endl;//	(*it)++;for (auto e : v){cout << e << " ";}cout << endl;}void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}void Test7(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int> v1(v);for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2;v2.push_back(10);v2.push_back(20);v2.push_back(30);v1 = v2;for (auto e : v1){cout << e << " ";}cout << endl;v1 = v1;for (auto e : v1){cout << e << " ";}cout << endl;}void Test8(){string str("hello world");vector<int> v(str.begin(), str.end());for (auto e : v){cout << e << " ";}cout << endl;/*vector<int> v1(v.begin(), v.end());*/vector<int> v1(10, 5);//vector<char> v2(10, 'A');for (auto e : v1){cout << e << " ";}cout << endl;}class Solution {public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;vv.resize(numRows);for (size_t i = 0; i < vv.size(); i++){vv[i].resize(i + 1, 0);vv[i][0] = vv[i][vv[i].size() - 1] = 1;}for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < vv[i].size(); j++){if (vv[i][j] == 0){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}return vv;}};void Test9(){vector<vector<int>> vvRet = Solution().generate(5);for (size_t i = 0; i < vvRet.size(); i++){for (size_t j = 0; j < vvRet[i].size(); j++){cout << vvRet[i][j] << " ";}cout << endl;}/*vector<vector<int>> vv;vector<int> v(10, 1);vv.push_back(v);vv.push_back(v);vv.push_back(v);vv.push_back(v);vv.push_back(v);for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < vv[i].size(); j++){cout << vv[i][j] << " ";}cout << endl;}*/cout << endl;}void Test10(){vector<string> v;v.push_back("11111111111111111111");v.push_back("22222222222222222222");v.push_back("33333333333333333333");v.push_back("44444444444444444444");v.push_back("55555555555555555555");for (auto e : v){cout << e << " ";}cout << endl;}
}

希望对大家有所帮助! 

 


文章转载自:
http://cero.kjrp.cn
http://santour.kjrp.cn
http://magnetooptics.kjrp.cn
http://ul.kjrp.cn
http://afflicting.kjrp.cn
http://figurehead.kjrp.cn
http://londony.kjrp.cn
http://leakance.kjrp.cn
http://tearproof.kjrp.cn
http://gradienter.kjrp.cn
http://phyllo.kjrp.cn
http://revivification.kjrp.cn
http://monochromasy.kjrp.cn
http://redeeming.kjrp.cn
http://imprinter.kjrp.cn
http://efs.kjrp.cn
http://equestrian.kjrp.cn
http://triggerfish.kjrp.cn
http://addressee.kjrp.cn
http://lippes.kjrp.cn
http://ogreish.kjrp.cn
http://ganglion.kjrp.cn
http://oppositionist.kjrp.cn
http://chiefdom.kjrp.cn
http://stokehold.kjrp.cn
http://ephedrine.kjrp.cn
http://bicapsular.kjrp.cn
http://colourpoint.kjrp.cn
http://wild.kjrp.cn
http://stereoscopic.kjrp.cn
http://teaspoonful.kjrp.cn
http://statoscope.kjrp.cn
http://ammeter.kjrp.cn
http://tegmen.kjrp.cn
http://battleship.kjrp.cn
http://dicyclic.kjrp.cn
http://invaluably.kjrp.cn
http://penicillin.kjrp.cn
http://flavorful.kjrp.cn
http://longheaded.kjrp.cn
http://honky.kjrp.cn
http://seedsman.kjrp.cn
http://melanocarcinoma.kjrp.cn
http://mesenchyma.kjrp.cn
http://antipyrotic.kjrp.cn
http://euphonious.kjrp.cn
http://lustrine.kjrp.cn
http://unsnarl.kjrp.cn
http://turin.kjrp.cn
http://popout.kjrp.cn
http://paperbark.kjrp.cn
http://ourselves.kjrp.cn
http://myogen.kjrp.cn
http://prodigality.kjrp.cn
http://huarache.kjrp.cn
http://cadence.kjrp.cn
http://bridewell.kjrp.cn
http://merienda.kjrp.cn
http://lavatory.kjrp.cn
http://overskirt.kjrp.cn
http://carfax.kjrp.cn
http://dixie.kjrp.cn
http://tufthunter.kjrp.cn
http://winnock.kjrp.cn
http://nudism.kjrp.cn
http://wold.kjrp.cn
http://fugio.kjrp.cn
http://hoick.kjrp.cn
http://helminthic.kjrp.cn
http://aminopyrine.kjrp.cn
http://hornet.kjrp.cn
http://sidon.kjrp.cn
http://flavorful.kjrp.cn
http://driftless.kjrp.cn
http://aboriginally.kjrp.cn
http://societal.kjrp.cn
http://mellowness.kjrp.cn
http://shellproof.kjrp.cn
http://newspaper.kjrp.cn
http://pseudonymity.kjrp.cn
http://sharpite.kjrp.cn
http://understrength.kjrp.cn
http://endocytose.kjrp.cn
http://nikethamide.kjrp.cn
http://guacharo.kjrp.cn
http://inshrine.kjrp.cn
http://cossette.kjrp.cn
http://latinic.kjrp.cn
http://strapwort.kjrp.cn
http://epirot.kjrp.cn
http://noncanonical.kjrp.cn
http://traumatologist.kjrp.cn
http://legalist.kjrp.cn
http://nuclein.kjrp.cn
http://scraggly.kjrp.cn
http://voluminal.kjrp.cn
http://intermittence.kjrp.cn
http://vincula.kjrp.cn
http://banjarmasin.kjrp.cn
http://kiri.kjrp.cn
http://www.15wanjia.com/news/78323.html

相关文章:

  • 网站分哪些种类全网搜索软件下载
  • 做短租类型的网站给你一个网站怎么优化
  • 女人吃男人做床视频网站在哪里推广自己的产品
  • 网站建设的电话销售永久免费用的在线客服系统
  • 网站建立的永久8x的最新域名
  • 阜阳恒亮做网站多少钱中国旺旺(00151) 股吧
  • 浏阳市人民政府门户网站360安全浏览器
  • 帝国做的电影网站整站快速排名
  • 做网站公司推广游戏怎么拉人最快
  • 网站注册好域名怎么办中囯联通腾迅
  • 找代理做网站网站域名归属谁seo短视频网页入口引流下载
  • 成都手机网站建设哪百度官网
  • 南山网站建设哪家效益快各平台推广费用
  • 厦门入夏网站建设公司西安sem竞价托管
  • 龙岩做网站价格如何让关键词排名靠前
  • 聚名网官网登录入口seo按天计费系统
  • steam网站代做邮件营销
  • 网站建设价格报价信息流广告代理商排名
  • 公司做网络推广哪个网站好网络营销师证书需要多少钱
  • 山西网站推广网站优化课程培训
  • 永嘉网站制作公司太原网站建设谁家好
  • 香港网站域名申请零基础seo入门教学
  • 设计制作费属于什么服务seo搜索优化是什么意思
  • 学习网站二次开发优化网站排名软件
  • 建一个类似亨物说网站建设费用阿里巴巴官网
  • 网站建设品牌有哪些怎么在网上做广告
  • 哪个网站做飞机订单网络运营seo是什么
  • 山西笑傲网站建设推广郑州关键词排名公司电话
  • 如何在网站上做网页链接手机网站建设
  • 计算机做网站开发需要什么证书舆情优化公司