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

常德天恒建设网站手表价格网站

常德天恒建设网站,手表价格网站,CMS源码就可以做网站吗,网站ip地址向谁购买文章目录 一、二叉搜索树概念二、二叉搜索树的操作2.1 二叉搜索树的查找2.2 二叉搜索树的插入2.3 二叉搜索树的删除 三、二叉搜索树的实现3.1 BinarySearchTreeNode#xff08;结点类#xff09;3.2 BinarySearchTree#xff08;二叉搜索树类#xff09;3.2.1 框架3.2.2 in… 文章目录 一、二叉搜索树概念二、二叉搜索树的操作2.1 二叉搜索树的查找2.2 二叉搜索树的插入2.3 二叉搜索树的删除 三、二叉搜索树的实现3.1 BinarySearchTreeNode结点类3.2 BinarySearchTree二叉搜索树类3.2.1 框架3.2.2 insert插入3.2.3 InOrder中序遍历3.2.4 find查找3.2.5 erase删除3.2.6 ~BinarySearchTree析构3.2.7 BinarySearchTree(const Self tree)拷贝构造3.2.8 operator赋值运算符重载 四、二叉搜索树的应用4.1 K模型4.2 KV模型4.2.1 KV 模型手撕 五、二叉搜索树的性能分析六、结语 一、二叉搜索树概念 二叉搜索树又称二插排序树它要么是一个空树要么就是具有以下性质的二叉树 若它的左子树不为空则左子树上所有节点的值都小于大于根节点的值。 若它的右子树不为空则右子树上所有节点的值都大于小于根节点的值。 它的左右子树也分别为二叉搜索树。 二、二叉搜索树的操作 2.1 二叉搜索树的查找 从根开始比较查找比根大则往右边走查找比根小则往左边走查找。 最多查找高度次走到空还没找到说明这个值不存在。 小Tips这里最多查找高度次的时间复杂度并不是 O ( l o g N ) O(logN) O(logN)这是建立在比较理想的情况下即这颗二叉树是一颗满二叉树或者完全二叉树。在极端情况下这棵二叉树只有一条路径此时最多查找高度次的时间复杂度就是 O ( N ) O(N) O(N)。 2.2 二叉搜索树的插入 插入的具体过程如下 树为空则直接新增节点赋值给 root 指针。 树不为空先按二叉搜索树的性质寻找插入位置插入新节点。 2.3 二叉搜索树的删除 首先查找元素是否在二叉搜索树中如果不存在则返回否则要删除的结点可能分下面四种情况: 要删除的结点没有孩子结点。 要删除的结点只有左孩子结点。 要删除的结点只有右孩子结点。 要删除的结点有左、右孩子节点。 虽然看起来删除一个结点有 4 中情况但实际上情况1可以和情况2或者情况3合并起来因此真正的删除过程如下 情况一要删除的结点只有左孩子删除该节点且使被删除节点的双亲结点指向被删除结点的左孩子结点----直接删除。 情况二要删除的结点只有右孩子删除该结点且使被删除结点的双亲结点指向被删除结点的右孩子结点-----直接删除。 情况三要删除的结点有左、右孩子在它的左子树中寻找出关键码最大的结点用它的值填补到被删除结点中再来处理该结点的删除问题----替换法删除。 三、二叉搜索树的实现 二插搜索树只是一种结构它本质上是由一个个结点链接而成因此我们首先需要定义一个结点类这个结点用来存储数据。有了结点类之后就需要定义一个二叉搜索树的类这个类主要是用来维护结构的实现增删查改等功能因为它是维护结构的因此这个类里面的成员变量只需要一个根节点即可有了这个根节点就能对整个数的结构进行维护管理。 3.1 BinarySearchTreeNode结点类 template class K struct BinarySearchTreeNode {typedef BinarySearchTreeNodeK TNode;BinarySearchTreeNode(const K val K()):_val(val),_left(nullptr),_right(nullptr){}K _val;TNode* _left;TNode* _right; };3.2 BinarySearchTree二叉搜索树类 3.2.1 框架 template class K class BinarySearchTree {typedef BinarySearchTreeNodeK BSTNode;typedef BinarySearchTreeK Self; public:BinarySearckTree():_root(nullptr){} private:BSTNode* _root; };3.2.2 insert插入 非递归版 bool insert(const K val) {if (_root nullptr){_root new BSTNode(val);return true;}BSTNode* newnode new BSTNode(val);BSTNode* cur _root;BSTNode* parent nullptr;while (cur){if (val cur-_val){parent cur;cur cur-_left;}else if (val cur-_val){parent cur;cur cur-_right;}else{return false;//相等就说明树中已经有了就应该插入失败}}//if (parent-_left cur)//左右都是空每次就走上面这个了if(val parent-_val){parent-_left newnode;}else{parent-_right newnode;}return true; }小Tips需要单独考虑根节点为空的情况。用 cur 找到该结点应该要插入的位置用 parent 指向该位置的双亲结点以实现链接关系。最后还需要判断插入到双亲结点的左侧还是右侧。我们实现的这个二叉搜索树要求存储相同值的结点在一个二叉搜索树中只能出现一次因此当插入一个值 val 的时候如果检测到树中已经有一个结点存的是 val那么就应该返回 false表明插入失败。 递归版 //插入(递归---版本一) private:bool _InsertR(BSTNode* root, BSTNode* parent, const K key){if (root nullptr)//为空说明就是在该位置插入{BSTNode* newnode new BSTNode(key);if (parent ! nullptr){if (key parent-_val){parent-_left newnode;}else{parent-_right newnode;}}else{root newnode;}return true;}//root不为空说明还没有找到待插入的位置还得继续找if (key root-_val){return _InsertR(root-_left, root, key);}else if (key root-_val){return _InsertR(root-_right, root, key);}else{return false;}} public://插入(递归)bool InsertR(const K key){return _InsertR(_root, _root, key);}//插入(递归---版本二) private:bool _InsertR(BSTNode* root, const K key){if (root nullptr)//为空说明就是在该位置插入{root new BSTNode(key);return true;}//root不为空说明还没有找到待插入的位置还得继续找if (key root-_val){return _InsertR(root-_left, key);}else if (key root-_val){return _InsertR(root-_right, key);}else{return false;}} public://插入(递归)bool InsertR(const K key){return _InsertR(_root, key);}小Tips在空树的时候执行插入是需要改变根节点 _root 的即需要对指针进行修改因此这里需要使用引用或者二级指针。 3.2.3 InOrder中序遍历 private:void _InOrder(BSTNode* root) const{if (root nullptr){return;}_InOrder(root-_left);cout root-_val ;_InOrder(root-_right);} public:void InOrder(){_InOrder(_root);cout endl;}小Tips这里的中序遍历用的是递归的方式来实现的但是递归函数一定是需要一个参数的要中序遍历整个二叉树用户一定是要把根节点 _root 传给这个函数但是根节点 _root 是私有的成员变量用户是访问不到的因此我们不能直接提供中序遍历函数给用户。正确的做法是虽然用户访问不到根结点但是类里面可以访问呀所以我们可以在类里面实现一个中序遍历的子函数 _InOrder在这个子函数中实现中序遍历的逻辑然后我们再去给用户提供一个中序遍历的函数接口 InOrder由它去调用 _InOrder。这样以来用户就可以正常去使用中序遍历啦。 3.2.4 find查找 非递归版 bool find(const K key) {BSTNode* cur _root;while (cur){if (key cur-_val){cur cur-_left;}else if (key cur-_val){cur cur-_right;}else{return true;}}return false; }递归版 private:bool _FindR(BSTNode* root, const K key){if (root nullptr){return false;}if (key root-_val){return _FindR(root-_left, key);}else if (key root-_val){return _FindR(root-_right, key);}else{return true;}} public:bool FindR(const K key){return _FindR(_root, key);}3.2.5 erase删除 非递归版 bool erase(const K key) {BSTNode* cur _root;BSTNode* parent nullptr;//先找需要删除的结点while (cur){if (key cur-_val){parent cur;cur cur-_left;}else if (key cur-_val){parent cur;cur cur-_right;}else{//到这里说明cur就是待删除的节点if (cur-_left nullptr)//如果cur只有一个孩子(只有右孩子)直接托孤{if (parent nullptr)//说明删除的是根结点{_root _root-_right;}else if (cur parent-_left)//判断cur是左孩子还是右孩子{parent-_left cur-_right;}else if(cur parent-_right){parent-_right cur-_right;}}else if(cur-_right nullptr)//如果cur只有一个孩子(只有左孩子){if (parent nullptr)//说明删除的是根结点{_root _root-_left;}else if (cur parent-_left)//判断cur是左孩子还是右孩子{parent-_left cur-_left;}else if (cur parent-_right){parent-_right cur-_left;}}else//到这里说明cur有两个孩子{BSTNode* parent cur;BSTNode* leftmax cur-_left;//找到左孩子中最大的那个while (leftmax-_right){parent leftmax;leftmax leftmax-_right;}swap(cur-_val, leftmax-_val);cur leftmax;//有一种极端情况就是左边只有一条路径if (leftmax parent-_left){parent-_left leftmax-_left;}else{parent-_right leftmax-_left;}}delete cur;return true;}}return false; }小Tips在上面的代码中我们始终让 cur 指向待删除节点parent 指向待删除结点的双亲也就是 cur 的双亲。删除大体上就分为2. 3小节中提到的三种情况。但是里面任然有一些细节需要我们注意比如删除根结点的情况即 parent nullptr 的时候。在情况一和情况二中我们还需要判断待删除结点 cur 是其双亲结点 parent 的左孩子还是右孩子以保证让 cur 的孩子和 parent 建立正确的链接关系。情况三待删除的结点有两个孩子我们这里的做法是找出 cur 左子树中最大的那个节点 leftmax让它来替换 cur帮助 cur 带“孩子”。找到左子树中值最大的结点很容易从 cur 的左孩子开始一路往右即可。找到后交换 cur 和 leftmax 中存储的值。交换后 leftmax 就变成了要删除的结点所以所以此时需要让 cur 重新指向 leftmax 这个结点。由于要删除 leftmax 结点为了方便后面修改链接关系这里我们还需要找到 leftmax 的双亲结点因此在这个局部域中我们重新定义了一个 parent它和外面那个 parent 并不冲突优先使用局部的但是注意里面这个 parent 表示的意义和外面 parent 的意义是有所不同的前者表示 cur 左树中最大节点的双亲结点后者表示 cur 的双亲结点。最后我们需要通过修改链接关系来实现 cur 结点的删除这里的链接关系有以下两种情形 情形一 小TipsStep2 中的交换是交换节点中的值并不是交换两个结点。最终 leftmax 和 cur 指向同一个结点。 情形二 小Tips情形二与情形一最大的不同点体现在两个地方第一情形二中的 parent 就是 cur只说明我们在定义 parent 赋初值的时候不能让 parent nullptr应该让 parent cur否则后面修改链接关系会出现访问空指针的问题。第二点不同在于修改链接关系情形二是让 parent 的左孩子指向 leftmax 的左孩子情形一是让 parent 的右孩子指向 leftmax 的左孩子。因此在修改链接关系的时候要进行判断看是哪种情形。在第二点不同里面又有一个相同点即无论是 parent 的左孩子还是 parent 的右孩子最终都指向了 leftmax 的左孩子这是为什么呢原因其实很简单leftmax 的右孩子一定为空而左孩子则不一定为空。为什么可以肯定右孩子一等为空因为 leftmax 是左子树中最大的那个结点如果它的右孩子不为空说明当前这个 leftmax 一定不是最大的那个结点。因此在修改链接关系的时候要让 parent 与 leftmax 的左孩子建立连接。最后需要注意交换完之后只能通过修改链接关系去删除 cur 结点不能通过递归调用去删除因为这个函数每次都是从根节点开始查找的交换后这棵树暂时不满足二叉搜索树的结构以情形一为例它就找不到存储8的结点。 递归版 private: //删除递归版bool _eraseR(BSTNode* root, const K key){if (root nullptr){return false;}if (key root-_val){return _eraseR(root-_left, key);}else if (key root-_val){return _eraseR(root-_right, key);}else{//相等了需要进行删除了BSTNode* del root;if (root-_left nullptr)//左为空{root root-_right;}else if (root-_right nullptr)//右为空{root root-_left;}else//左右都不为空{BSTNode* parent root;BSTNode* leftmax root-_left;//找到左孩子中最大的那个while (leftmax-_right){parent leftmax;leftmax leftmax-_right;}swap(root-_val, leftmax-_val);return _eraseR(root-_left, key);}delete del;del nullptr;return true;}} public://删除递归版bool eraseR(const K key){return _eraseR(_root, key);}小Tips在交换后虽然整棵树可能不满足二叉搜索树的结构但是 root 结点的左子树一定是满足二叉搜索树的因为我们交换的是 root 结点的 _val 和左子树中最大的那个 _val而 root 结点的 _val 一定是比左子树中最大的那个 _val 还要大的所以交换完之后 root 的左子树任然满足二叉搜索树的结构此时我们就可以通过递归调用去 root 的左子树中找要删除的结点并且交换后待删除的结点一定变成了情况一或者情况二中的一种。递归版中对情况一和情况二的处理变简单了许多因为 root 是一个引用如果发现 root 的一个孩子为空直接把 root 的另一个孩子赋值给它即可在赋值之前记得保存一下 root 的值这个值指向的结点就是要删除的结点把这个值保存下来后面才能去 delete否则赋值后就没有指针指向该结点那就没办法释放这个结点的空间资源就会造成内存泄漏。非递归中即使用了引用也不能这样搞因为非递归中一个引用始终是在一个函数栈帧里面而引用是不能改变指向的。但是递归就不一样了每一次递归调用都会开辟新的函数栈帧每一个函数栈帧中 root 都是不同结点的别名。 3.2.6 ~BinarySearchTree析构 private://析构子函数void Destruction(BSTNode* root){if (root nullptr){return;}//先去释放左孩子和右孩子的空间资源Destruction(root-_left);Destruction(root-_right);//再去释放root自己的空间资源delete root;root nullptr;//形参root如果不加引用这里置空是没有任何意义的因为不加引用这里仅仅是一份拷贝return;} public://析构函数~BinarySearckTree(){Destruction(_root);}3.2.7 BinarySearchTree(const Self tree)拷贝构造 注意拷贝构造不能直接去调用 insert因为数据插入的顺序不同这棵树最终的结构也是不同的虽然最终也符合二叉树的结构但是还是和被拷贝的树有所不同。正确做法是走一个前序遍历遍历到 tree 的一个结点时去 new 一个结点存储同样的值。 写法一 //拷贝构造函数的子函数 private:void Construct(BSTNode* root, BSTNode* copy){if (copy nullptr){root nullptr;return;}root new BSTNode(copy-_val);//通过引用直接来实现链接关系Construct(root-_left, copy-_left);Construct(root-_right, copy-_right);} public://拷贝构造BinarySearchTree(const Self tree):_root(nullptr){Construct(_root, tree._root);}写法二 private: //拷贝构造子函数(写法二)BSTNode* Construct(BSTNode* root){if (root nullptr){return nullptr;}BSTNode* newnode new BSTNode(root-_val);newnode-_left Construct(root-_left);//通过返回值来实现链接关系newnode-_right Construct(root-_right);return newnode;} public://拷贝构造(写法二)BinarySearchTree(const Self tree){_root Construct(tree._root);}小Tips上面两种写法的不同点在于方法一是通过引用去实现链接关系方法二则是通过返回值的方式来实现链接关系。 3.2.8 operator赋值运算符重载 public: //赋值运算符重载(现代写法)Self operator(Self tree){swap(_root, tree._root);//交换两颗搜索二叉树就是交换它们里面维护的根节点return *this;}四、二叉搜索树的应用 4.1 K模型 K模型即只有一个 Key 作为关键码结构中只需要存储 Key 即可关键码即为需要搜索到的值。比如给一个单词 word判断该单词是否拼写正确具体方式如下 以词库中所有单词集合中的每个单词作为 Key构建一颗二叉搜索树。 在二叉搜索树中检索该单词是否存在存在则拼写正确不存在则拼写错误。 我们上面手搓的这可二叉搜索树就是 Key 模型因为这颗树的结点里面只能存储一个值这个值就是 Key。 4.2 KV模型 KV 模型即每一个关键码 Key都有与之对应的的值 Value即 KeyValue 的键值对。这种方式在现实生活中十分常见 比如英汉词典就是英文与中文的对应关系通过英文可以快速找到与其对应的中文英文单词与其对应的中文 wordChinese 就构成一种键值对。 再比如统计单词次数统计成功后给定单词就可以快速找到其出现的次数单词与其出现次数就是 wordcount 就构成一种键值对。 4.2.1 KV 模型手撕 #pragma oncenamespace K_V {template class K, class Vstruct BinarySearchTreeNode{typedef BinarySearchTreeNodeK, V TNode;BinarySearchTreeNode(const K key K(), const V val V()):_key(key), _val(val), _left(nullptr), _right(nullptr){}K _key;V _val;TNode* _left;TNode* _right;};template class K, class Vclass BinarySearchTree{typedef BinarySearchTreeNodeK, V BSTNode;typedef BinarySearchTreeK, V Self;private:void _InOrder(BSTNode* root) const{if (root nullptr){return;}_InOrder(root-_left);cout root-_key -- root-_val endl;_InOrder(root-_right);}BSTNode* _FindR(BSTNode* root, const K key)//KV模型中的Key不能被修改但是Val可以被修改{if (root nullptr){return nullptr;}if (key root-_key){return _FindR(root-_left, key);}else if (key root-_key){return _FindR(root-_right, key);}else{return root;}}//插入(递归---版本一)//bool _InsertR(BSTNode* root, BSTNode* parent, const K key)//{// if (root nullptr)//为空说明就是在该位置插入// {// BSTNode* newnode new BSTNode(key);// if (parent ! nullptr)// {// if (key parent-_key)// {// parent-_left newnode;// }// else// {// parent-_right newnode;// }// }// else// {// root newnode;// }// return true;// }// //root不为空说明还没有找到待插入的位置还得继续找// if (key root-_key)// {// return _InsertR(root-_left, root, key);// }// else if (key root-_key)// {// return _InsertR(root-_right, root, key);// }// else// {// return false;// }//}//插入(递归---版本二)bool _InsertR(BSTNode* root, const K key, const V val){if (root nullptr)//为空说明就是在该位置插入{root new BSTNode(key, val);return true;}//root不为空说明还没有找到待插入的位置还得继续找if (key root-_key){return _InsertR(root-_left, key, val);}else if (key root-_key){return _InsertR(root-_right, key, val);}else{return false;}}//删除递归版bool _eraseR(BSTNode* root, const K key){if (root nullptr){return false;}if (key root-_key){return _eraseR(root-_left, key);}else if (key root-_key){return _eraseR(root-_right, key);}else{//相等了需要进行删除了BSTNode* del root;if (root-_left nullptr)//左为空{root root-_right;}else if (root-_right nullptr)//右为空{root root-_left;}else//左右都不为空{BSTNode* parent root;BSTNode* leftmax root-_left;//找到左孩子中最大的那个while (leftmax-_right){parent leftmax;leftmax leftmax-_right;}std::swap(root-_key, leftmax-_key);return _eraseR(root-_left, key);}delete del;del nullptr;return true;}}//析构子函数void Destruction(BSTNode* root){if (root nullptr){return;}//先去释放左孩子和右孩子的空间资源Destruction(root-_left);Destruction(root-_right);//再去释放root自己的空间资源delete root;root nullptr;//形参root如果不加引用这里置空是没有任何意义的因为不加引用这里仅仅是一份拷贝return;}//拷贝构造函数的子函数(写法一)void Construct(BSTNode* root, BSTNode* copy){if (copy nullptr){root nullptr;return;}root new BSTNode(copy-_key);Construct(root-_left, copy-_left);Construct(root-_right, copy-_right);}//拷贝构造子函数(写法二)BSTNode* Construct(BSTNode* root){if (root nullptr){return nullptr;}BSTNode* newnode new BSTNode(root-_key);newnode-_left Construct(root-_left);newnode-_right Construct(root-_right);return newnode;}public:BinarySearchTree():_root(nullptr){}//拷贝构造(写法一)/*BinarySearchTree(const Self tree):_root(nullptr){Construct(_root, tree._root);}*///拷贝构造(写法二)BinarySearchTree(const Self tree){_root Construct(tree._root);}//赋值运算符重载(现代写法)Self operator(Self tree){swap(_root, tree._root);//交换两颗搜索二叉树就是交换它们里面维护的根节点return *this;}//插入(非递归)bool insert(const K key, const V val){if (_root nullptr){_root new BSTNode(key, val);return true;}BSTNode* newnode new BSTNode(key, val);BSTNode* cur _root;BSTNode* parent nullptr;while (cur){if (key cur-_key){parent cur;cur cur-_left;}else if (key cur-_key){parent cur;cur cur-_right;}else{return false;//相等就说明树中已经有了就应该插入失败}}//if (parent-_left cur)//左右都是空每次就走上面这个了if (key parent-_key){parent-_left newnode;}else{parent-_right newnode;}return true;}//插入(递归)bool InsertR(const K key, const V val){return _InsertR(_root, key, val);}//中序遍历void InOrder(){_InOrder(_root);cout endl;}//查找(非递归)BSTNode* find(const K key){BSTNode* cur _root;while (cur){if (key cur-_key){cur cur-_left;}else if (key cur-_key){cur cur-_right;}else{return cur;}}return nullptr;}//查找(递归)BSTNode* FindR(const K key){return _FindR(_root, key);}//删除(非递归)bool erase(const K key){BSTNode* cur _root;BSTNode* parent nullptr;//先找需要删除的结点while (cur){if (key cur-_key){parent cur;cur cur-_left;}else if (key cur-_key){parent cur;cur cur-_right;}else{//到这里说明cur就是待删除的节点if (cur-_left nullptr)//如果cur只有一个孩子(只有右孩子)直接托孤{if (parent nullptr){_root _root-_right;}else if (cur parent-_left)//判断cur是左孩子还是右孩子{parent-_left cur-_right;}else if (cur parent-_right){parent-_right cur-_right;}}else if (cur-_right nullptr)//如果cur只有一个孩子(只有左孩子){if (parent nullptr){_root _root-_left;}else if (cur parent-_left)//判断cur是左孩子还是右孩子{parent-_left cur-_left;}else if (cur parent-_right){parent-_right cur-_left;}}else//到这里说明cur有两个孩子{BSTNode* parent cur;BSTNode* leftmax cur-_left;//找到左孩子中最大的那个while (leftmax-_right){parent leftmax;leftmax leftmax-_right;}std::swap(cur-_key, leftmax-_key);cur leftmax;//有一种极端情况就是左边只有一条路径if (leftmax parent-_left){parent-_left leftmax-_left;}else{parent-_right leftmax-_left;}}delete cur;return true;}}return false;}//删除递归版bool eraseR(const K key){return _eraseR(_root, key);}//析构函数~BinarySearchTree(){Destruction(_root);}private:BSTNode* _root nullptr;}; }void TestBSTree4() {// 统计水果出现的次数string arr[] { 苹果, 西瓜, 苹果, 西瓜, 苹果, 苹果, 西瓜,苹果, 香蕉, 苹果, 香蕉 };K_V::BinarySearchTreestring, int countTree;for (const auto str : arr){// 先查找水果在不在搜索树中// 1、不在说明水果第一次出现则插入水果, 1// 2、在则查找到的节点中水果对应的次数//BSTreeNodestring, int* ret countTree.Find(str);auto ret countTree.FindR(str);if (ret NULL){countTree.insert(str, 1);}else{ret-_val;}}countTree.InOrder(); }小Tips虽然变成了 KV 模型但它仍然是一颗二叉搜索树因此整棵树的结构没有发生任何变化。唯一的变化在于树的结点对与 KV 模型来说树中的结点不仅要存 Key还要存 Value这就进一步导致在插入时不仅要插入 Key还要插入一个与该 Key 对应的 Value。其次对 KV 模型来说Key 不允许被修改Value 可以被修改因此对 KV 模型来说在 Find 的时候应该返回结点的指针这样方便后续进行一些操作。 五、二叉搜索树的性能分析 插入和删除操作都必须先查找查找效率代表了二叉搜索树中各个操作的性能。对有 n 个结点的二叉搜索树若每个元素查找的概率相等则二叉搜索树平均查找长度是结点在二插搜索树的深度的函数即结点越深则比较次数越多。但对于同一个关键码集合如果各关键码插入的次序不同可能得到不同结构的二叉搜索树。 最优情况下二叉搜索树为完全二叉树或者接近完全二叉树其平均比较次数为 l o g 2 n log2^n log2n。 最差情况下二叉搜索树退化为单支树或者类似单支其平均比较次数为 N 2 \frac{N}{2} 2N​。如果退化成了单支树那么二叉搜索树的性能就失去了。此时就需要用到即将登场的 AVL 树和红黑树了。 六、结语 今天的分享到这里就结束啦如果觉得文章还不错的话可以三连支持一下春人的主页还有很多有趣的文章欢迎小伙伴们前去点评您的支持就是春人前进的动力
文章转载自:
http://www.morning.llsrg.cn.gov.cn.llsrg.cn
http://www.morning.tzpqc.cn.gov.cn.tzpqc.cn
http://www.morning.pdwzr.cn.gov.cn.pdwzr.cn
http://www.morning.lhxdq.cn.gov.cn.lhxdq.cn
http://www.morning.hwbf.cn.gov.cn.hwbf.cn
http://www.morning.sxhdzyw.com.gov.cn.sxhdzyw.com
http://www.morning.qcygd.cn.gov.cn.qcygd.cn
http://www.morning.nyzmm.cn.gov.cn.nyzmm.cn
http://www.morning.ptmch.com.gov.cn.ptmch.com
http://www.morning.rrcxs.cn.gov.cn.rrcxs.cn
http://www.morning.phjyb.cn.gov.cn.phjyb.cn
http://www.morning.rxwnc.cn.gov.cn.rxwnc.cn
http://www.morning.3jiax.cn.gov.cn.3jiax.cn
http://www.morning.hbtarq.com.gov.cn.hbtarq.com
http://www.morning.zgdnd.cn.gov.cn.zgdnd.cn
http://www.morning.jlxqx.cn.gov.cn.jlxqx.cn
http://www.morning.gtdf.cn.gov.cn.gtdf.cn
http://www.morning.ie-comm.com.gov.cn.ie-comm.com
http://www.morning.bloao.com.gov.cn.bloao.com
http://www.morning.zkpwk.cn.gov.cn.zkpwk.cn
http://www.morning.rrcrs.cn.gov.cn.rrcrs.cn
http://www.morning.dtpqw.cn.gov.cn.dtpqw.cn
http://www.morning.fqpgf.cn.gov.cn.fqpgf.cn
http://www.morning.skqfx.cn.gov.cn.skqfx.cn
http://www.morning.jxrpn.cn.gov.cn.jxrpn.cn
http://www.morning.rtmqy.cn.gov.cn.rtmqy.cn
http://www.morning.drcnf.cn.gov.cn.drcnf.cn
http://www.morning.jbmbj.cn.gov.cn.jbmbj.cn
http://www.morning.rbcw.cn.gov.cn.rbcw.cn
http://www.morning.lpgw.cn.gov.cn.lpgw.cn
http://www.morning.frsbf.cn.gov.cn.frsbf.cn
http://www.morning.bxbkq.cn.gov.cn.bxbkq.cn
http://www.morning.csgwd.cn.gov.cn.csgwd.cn
http://www.morning.zlfxp.cn.gov.cn.zlfxp.cn
http://www.morning.spsqr.cn.gov.cn.spsqr.cn
http://www.morning.hrpmt.cn.gov.cn.hrpmt.cn
http://www.morning.kxmyj.cn.gov.cn.kxmyj.cn
http://www.morning.cpqqf.cn.gov.cn.cpqqf.cn
http://www.morning.yongkangyiyuan-pfk.com.gov.cn.yongkangyiyuan-pfk.com
http://www.morning.xwbld.cn.gov.cn.xwbld.cn
http://www.morning.mhxlb.cn.gov.cn.mhxlb.cn
http://www.morning.glxmf.cn.gov.cn.glxmf.cn
http://www.morning.mgkcz.cn.gov.cn.mgkcz.cn
http://www.morning.qhydkj.com.gov.cn.qhydkj.com
http://www.morning.txhls.cn.gov.cn.txhls.cn
http://www.morning.ydzly.cn.gov.cn.ydzly.cn
http://www.morning.cnbdn.cn.gov.cn.cnbdn.cn
http://www.morning.darwallet.cn.gov.cn.darwallet.cn
http://www.morning.qcwrm.cn.gov.cn.qcwrm.cn
http://www.morning.zcmpk.cn.gov.cn.zcmpk.cn
http://www.morning.fcpjq.cn.gov.cn.fcpjq.cn
http://www.morning.jfxth.cn.gov.cn.jfxth.cn
http://www.morning.trfh.cn.gov.cn.trfh.cn
http://www.morning.qflcb.cn.gov.cn.qflcb.cn
http://www.morning.jthjr.cn.gov.cn.jthjr.cn
http://www.morning.sbkb.cn.gov.cn.sbkb.cn
http://www.morning.ttdxn.cn.gov.cn.ttdxn.cn
http://www.morning.wanjia-sd.com.gov.cn.wanjia-sd.com
http://www.morning.yhrfg.cn.gov.cn.yhrfg.cn
http://www.morning.hymmq.cn.gov.cn.hymmq.cn
http://www.morning.kwwkm.cn.gov.cn.kwwkm.cn
http://www.morning.lbbrw.cn.gov.cn.lbbrw.cn
http://www.morning.kyctc.cn.gov.cn.kyctc.cn
http://www.morning.blfll.cn.gov.cn.blfll.cn
http://www.morning.ylyzk.cn.gov.cn.ylyzk.cn
http://www.morning.yqpck.cn.gov.cn.yqpck.cn
http://www.morning.khcpx.cn.gov.cn.khcpx.cn
http://www.morning.qjfkz.cn.gov.cn.qjfkz.cn
http://www.morning.chtnr.cn.gov.cn.chtnr.cn
http://www.morning.sltfk.cn.gov.cn.sltfk.cn
http://www.morning.tdfyj.cn.gov.cn.tdfyj.cn
http://www.morning.glnfn.cn.gov.cn.glnfn.cn
http://www.morning.supera.com.cn.gov.cn.supera.com.cn
http://www.morning.gwdnl.cn.gov.cn.gwdnl.cn
http://www.morning.gxtfk.cn.gov.cn.gxtfk.cn
http://www.morning.ksgjy.cn.gov.cn.ksgjy.cn
http://www.morning.mxhcf.cn.gov.cn.mxhcf.cn
http://www.morning.crkmm.cn.gov.cn.crkmm.cn
http://www.morning.knqzd.cn.gov.cn.knqzd.cn
http://www.morning.ydryk.cn.gov.cn.ydryk.cn
http://www.tj-hxxt.cn/news/237744.html

相关文章:

  • 如何对网站做实证分析免费刷推广链接的网站
  • net网站开发参考文献专做国际时事评论网站
  • 做网站怎么云存储oppo游戏中心官网
  • 网站建设公司的前景查公司名称是否已经被注册
  • 无锡网站关键词优化h5企业网站源码
  • 西宁网站建设优化案例西安商城网站建设制作
  • 网站 攻击 刷流量广州市筑正工程建设有限公司网站
  • 网站建设收费标准如何房产咨询律师免费咨询
  • 华企立方网站企业为什么要管理
  • 公司做手机网站建设网站301跳转
  • 宿迁网站建设案例那个网站做外贸好
  • 网站建设摊销几年数据分析师培训机构
  • 建设网站团队深圳家装网站建设多少钱
  • phpcms 视频网站模板用ps做网站页面的大小
  • 个人网站相册怎么做铭讯网站建设
  • 做网站程序看什么书北京网络教育
  • 上海网站开发外包织梦大气绿色大气农业能源化工机械产品企业网站源码模版
  • 现在网站如何做优化微分销商城系统
  • 上海 做网站网站工信部实名认证中心
  • 不懂代码怎么做网站基于jsp的网站开发的文献
  • 做企业网站用什么程序企业如何申请网站
  • 做网站时图片的分辨率是多少百度搜索页
  • 高质量的南昌网站建设下载微信app
  • 网站建设扬州html5高端酒水饮料企业网站模版
  • 如何建手机网站网站开发公司售后服务
  • 免费网站模板代码怎么制作网站店铺
  • 苏州网站建设如何选择中文搜索引擎有哪些平台
  • 网站建设几个要素广东短视频运营推广
  • 前端网站优化国外网站模板欣赏
  • 做的网站是怎么被收录nofollow外链对于网站有提升吗