上海电子商务网站制作,做装修网站价格,wordpress店铺模板制作教程,wordpress轮播图代码系列文章目录 速通数据结构与算法系列 1 速通数据结构与算法第一站 复杂度 http://t.csdnimg.cn/sxEGF 2 速通数据结构与算法第二站 顺序表 http://t.csdnimg.cn/WVyDb 3 速通数据结构与算法第三站 单链表 http://t.csdnimg.cn/cDpcC 感谢佬们…系列文章目录 速通数据结构与算法系列 1 速通数据结构与算法第一站 复杂度 http://t.csdnimg.cn/sxEGF 2 速通数据结构与算法第二站 顺序表 http://t.csdnimg.cn/WVyDb 3 速通数据结构与算法第三站 单链表 http://t.csdnimg.cn/cDpcC 感谢佬们支持 目录
系列文章目录
前言一、双链表 0 结构体 1 接口声明 2 增加节点 3 初始化 4 打印 5 尾插 6 尾删 7 头插 8 头删 9 find 10 insert 11 erase 12 销毁 13 完整代码二、OJ题 1 环形链表1 2 环形链表2 3 复杂链表的复制三、链表和顺序表的对比补充deque总结 前言
上篇博客我们探讨的是单链表这篇博客将为大家带来双链表和3个更值得探讨的OJ题
双链表看似更复杂了其实不然代码写起来比单链表爽的多 我们要写的就是带头双向循环链表 这也是STLSGI版中list相同的结构 一、双链表
我们还是先来搞一个结构体
结构体
typedef int LTDataType;typedef struct ListNode
{LTDataType data;struct ListNode* prev;struct ListNode* next;
}LTNode;
其中data表示数据prev表示指向前一个结点next表示指向后一个节点 接口声明
//增加节点
LTNode* BuyListNode(LTDataType x);//初始化
//void LTInit(LTNode**phead);
LTNode* LTInit();//打印
void LTPrint(LTNode* phead);//判空
bool LTEmpty(LTNode* plist);//销毁
void LTDestroy(LTNode* phead);//尾插
void LTNodePushBack(LTNode* phead, LTDataType x);//尾删
void LTNodePopBack(LTNode* phead);//头插
void LTNodePushFront(LTNode* phead, LTDataType x);//头删
void LTNodePopFront(LTNode* phead);//find
LTNode* LTNodeFind(LTNode* phead, LTDataType x);//pos前插
void LTNodeInsert(LTNode* pos, LTDataType x);//删pos
void LTNodeErase(LTNode* pos);增加节点
增加节点的逻辑简单这里不再赘述
//创建节点
LTNode* BuyListNode(LTDataType x)
{LTNode* newnode (LTNode*)malloc(sizeof(LTNode));newnode-data x;newnode-next NULL;newnode-prev NULL;return newnode;
} 初始化
显然在双链表这里我们的初始化是有事做的而不像单链表在使用时给个空就行
我们要创建哨兵位的头节点还要让他的next和prev都指向自己毕竟是个循环链表 按理说这样修改头节点我们是要传二级指针的但是后面的接口实际上都传一级指针就行毕竟有了头节点之后的修改都不涉及整个链表。
如果用了二级指针的写法会是这样…… void LTInit(LTNode* *phead)
{//哨兵位*phead BuyListNode(-1);(*phead)-next *phead;(*phead)-prev *phead;}
用起来就是这样……
LTNode* plist NULL;LTInit(plist);
为了接口的一致性我们也可以用传一级指针只要用返回值带出来即可
//初始化
LTNode* LTInit()
{//哨兵位LTNode*phead BuyListNode(-1);phead-next phead;phead-prev phead;return phead;//返回头节点
}
用起来就是这样 LTNode* plist LTInit();下来我们再写一下打印
打印
打印很简单但是我们要控制好循环的逻辑毕竟他是个循环链表一不小心就会死循环
我可以定义一个cur指向phead-next,cur直到等于phead停下来
//打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){printf(%d , cur-data);cur cur-next;}
} 尾插
双链表的尾插相比于单链表轻松很多首先它不用找尾phead的prev就是尾拿到尾以后我们只需改4个指针即可
如图所示 而且好消息是我们通过画图发现如果链表为空上述逻辑依然成立所以我们不用特判链表为空的情况
直接上代码
//尾插
void LTNodePushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode BuyListNode(x);LTNode* tail phead-prev;//连接关系tail-next newnode;newnode-prev tail;newnode-next phead;phead-prev newnode;//空链表尾插不用单独处理。奈斯} 尾删
尾删只需考虑链表是否为空的情况即可即我们不能删哨兵位的头节点
依然是改4个指针的问题 //尾删
void LTNodePopBack(LTNode* phead)
{assert(phead);//链表为空就不能再删assert(!LTEmpty(phead));LTNode* tail phead-prev;LTNode* newtail tail-prev;phead-prev newtail;newtail-next phead;free(tail);tail NULL;} 头插
头插同样是改4个指针的逻辑
直接上代码
//头插
void LTNodePushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode BuyListNode(x);LTNode* head phead-next;phead-next newnode;newnode-prev phead;newnode-next head;head newnode;}头删
头删同理我们只需额外判断链表是否为空就行
//头删
void LTNodePopFront(LTNode* phead)
{assert(phead);//链表为空就不能再删assert(!LTEmpty(phead));LTNode* head phead-next;LTNode* newhead head-next;newhead-prev phead;phead-next newhead;free(head);head NULL;}
我们简单的做一波测试
LTNode* plist LTInit();LTNodePushBack(plist, 1);LTNodePushBack(plist, 1);LTNodePushBack(plist, 4);LTNodePushBack(plist, 2);//LTNodePopBack(plist);LTNodePopBack(plist);LTNodePushBack(plist, 1);LTNodePushFront(plist, 3);LTPrint(plist);LTDestroy(plist);
没有问题 这里我们发现双链表的头插头删尾插尾删都是O1确实挺不错的 find
find的原理不用多说了直接上代码
//寻找
LTNode* LTNodeFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){if (cur-data x){return cur;}cur cur-next;}//找不见return NULL;
}insert
我们要写的pos位置前插在写了前面的之后写这个就是砍瓜切菜啦~
只需额外判断pos是否合法即可
//pos位置前插入
void LTNodeInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode BuyListNode(x);LTNode* prev pos-prev;newnode-next pos;pos-prev newnode;newnode-prev prev;prev-next newnode;
}erase
/删pos位置
void LTNodeErase(LTNode* pos)
{assert(pos);assert(!LTEmpty(pos));LTNode* next pos-next;LTNode* prev pos-prev;prev-next next;next-prev prev;free(pos);pos NULL;
}
写了erase和insert之后我们前面的代码就都不用写了直接复用这个即可
尾插会是这样
//复用版本//LTNodeInsert(phead,x);
尾删
//复用版本//LTNodeErase(phead-prev);
头插
//复用版本//LTNodeInsert(phead-next,x);
头删
//复用版本//LTNodeErase(phead-next);
这样如果面试官让你20min写一个链表你直接写一个insert和erase就可以轻松搞定了 销毁
最后我们来搞定一下销毁就好啦
//销毁
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){LTNode* next cur-next;free(cur);cur next;}free(phead);//由于传的是一级指针记得要在外面手动置空
} 完整代码
完整代码是这样的…
list.h
#pragma once#includestdio.h
#includestdlib.h
#includeassert.h
#includestdbool.htypedef int LTDataType;typedef struct ListNode
{LTDataType data;struct ListNode* prev;struct ListNode* next;
}LTNode;//增加节点
LTNode* BuyListNode(LTDataType x);//初始化
//void LTInit(LTNode**phead);
LTNode* LTInit();//打印
void LTPrint(LTNode* phead);//判空
bool LTEmpty(LTNode* plist);//销毁
void LTDestroy(LTNode* phead);//尾插
void LTNodePushBack(LTNode* phead, LTDataType x);//尾删
void LTNodePopBack(LTNode* phead);//头插
void LTNodePushFront(LTNode* phead, LTDataType x);//头删
void LTNodePopFront(LTNode* phead);//find
LTNode* LTNodeFind(LTNode* phead, LTDataType x);//pos前插
void LTNodeInsert(LTNode* pos, LTDataType x);//删pos
void LTNodeErase(LTNode* pos);list.c
#includeList.h//创建节点
LTNode* BuyListNode(LTDataType x)
{LTNode* newnode (LTNode*)malloc(sizeof(LTNode));newnode-data x;newnode-next NULL;newnode-prev NULL;return newnode;
}#if 0
//初始化(二级指针z)
void LTInit(LTNode* *phead)
{//哨兵位*phead BuyListNode(-1);(*phead)-next *phead;(*phead)-prev *phead;//return phead;//返回头节点}
#endif//初始化
LTNode* LTInit()
{//哨兵位LTNode*phead BuyListNode(-1);phead-next phead;phead-prev phead;return phead;//返回头节点
}
//打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){printf(%d , cur-data);cur cur-next;}
}//判空
bool LTEmpty(LTNode* phead)
{return phead-next phead;
}//销毁
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){LTNode* next cur-next;free(cur);cur next;}free(phead);//由于传的是一级指针记得要在外面手动置空
}//尾插
void LTNodePushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode BuyListNode(x);LTNode* tail phead-prev;//连接关系tail-next newnode;newnode-prev tail;newnode-next phead;phead-prev newnode;//空链表尾插不用单独处理。奈斯//复用版本//LTNodeInsert(phead,x);
}//尾删
void LTNodePopBack(LTNode* phead)
{assert(phead);//链表为空就不能再删assert(!LTEmpty(phead));LTNode* tail phead-prev;LTNode* newtail tail-prev;phead-prev newtail;newtail-next phead;free(tail);tail NULL;//复用版本//LTNodeErase(phead-prev);
}//头插
void LTNodePushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode BuyListNode(x);LTNode* head phead-next;phead-next newnode;newnode-prev phead;newnode-next head;head newnode;//复用版本//LTNodeInsert(phead-next,x);
}//头删
void LTNodePopFront(LTNode* phead)
{assert(phead);//链表为空就不能再删assert(!LTEmpty(phead));LTNode* head phead-next;LTNode* newhead head-next;newhead-prev phead;phead-next newhead;free(head);head NULL;//复用版本//LTNodeErase(phead-next);
}//寻找
LTNode* LTNodeFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur phead-next;while (cur ! phead){if (cur-data x){return cur;}cur cur-next;}//找不见return NULL;
}//pos位置前插入
void LTNodeInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode BuyListNode(x);LTNode* prev pos-prev;newnode-next pos;pos-prev newnode;newnode-prev prev;prev-next newnode;
}//删pos位置
void LTNodeErase(LTNode* pos)
{assert(pos);assert(!LTEmpty(pos));LTNode* next pos-next;LTNode* prev pos-prev;prev-next next;next-prev prev;free(pos);pos NULL;
}
test.c
#includeList.hvoid test1()
{//LTNode* plist NULL;// LTInit(plist);LTNode* plist LTInit();LTNodePushBack(plist, 1);LTNodePushBack(plist, 1);LTNodePushBack(plist, 4);LTNodePushBack(plist, 1);LTNodePushBack(plist, 2);//LTNodePopBack(plist);//LTNodePopBack(plist);LTNodePushFront(plist, 3);LTNode* ret LTNodeFind(plist, 4);LTNodeErase(ret);LTPrint(plist);LTDestroy(plist);plist NULL;
}void test2()
{LTNode* plist LTInit();LTNodePushBack(plist, 1);LTNodePushBack(plist, 1);LTNodePushBack(plist, 4);LTNodePushBack(plist, 2);//LTNodePopBack(plist);LTNodePopBack(plist);LTNodePushBack(plist, 1);LTNodePushFront(plist, 3);LTPrint(plist);LTDestroy(plist);
}int main()
{test2();return 0;
} 二、OJ题
这次我们来看几道相对较难的OJ题 1 环形链表1 题目链接 . - 力扣LeetCode 首先 这个题最好不要遍历不然会很容易死循环
最简单的方法是快慢指针让slow一次走一步fast一次走两步如果他们最终相遇
说明有环
为什么呢 1 显然slow和fast的相对速度是1步1个节点由物理学知识我们知道如果有环他们最终一定相遇不会错过 2 如果fast一次走3步呢相对速度就会是2步suppose slow进环后fast开始追击。如果他们之间的距离是偶数他们就会相遇如果是奇数便会错过。以此类推。 代码还是简单的我们很轻松就能写出来啦~
bool hasCycle(struct ListNode* head)
{//快慢指针追击相遇struct ListNode* fast head;struct ListNode* slow head;//fast一次两步slow一次一步while (fast fast-next)//如果不断言fast测试用例会有空链表,如果不想断言fast可以加上面的那个判断{slow slow-next;fast fast-next-next;if (slow fast){return true;}}return false;
} 2 环形链表2 题目链接 . - 力扣LeetCode 下来恶心的是环形链表2它建立在环形链表1的基础上 我们需要在有环的基础上找到环的入口节点
先说结论再证明在环形链表1中我们可以得到最后slow和fast的相遇点如果有环的话
现在是这样我们再给两个指针一个从链表开始走另一个从相遇点走他们最后相遇的节点
就是我们要的入口节点。
证明 suppose入口点到环的起点距离为N环的长度为C入口点至相遇点的距离为x
也就是这样…… 首先在相遇时slow走的距离为NX
fast走的距离为NXn*Cn为fast走的圈数
由于fast的距离slow的两倍
即2*NXNXn*C
化简一下就会得到
NXn*C
Nn*C-X
由此便得此时再用两个指针一个从链表开始走另一个从相遇点走他们最后相遇的节点
就是我们要的入口节点。
代码如下……
bool hasCycle(struct ListNode* head)
{//快慢指针追击相遇struct ListNode* fast head;struct ListNode* slow head;//fast一次两步slow一次一步while (fast fast-next)//如果不断言fast测试用例会有空链表,如果不想断言fast可以加上面的那个判断{slow slow-next;fast fast-next-next;if (slow fast){return true;}}return false;
}struct ListNode* detectCycle(struct ListNode* head)
{if (hasCycle(head) NULL){return NULL;}else{//一个从相遇点开始走一个从头走它们会在环的入口相遇struct ListNode* meet hasCycle(head);while (meet ! head){meet meet-next;head head-next;}return meet;}
} 我们还有第二种思路
在相遇点处断开我们会得到两条链表如图 我们可以求这两条链表的相交节点具体相交链表的逻辑请大家移步我的上一篇博客 http://t.csdnimg.cn/cDpcC
//链表相交
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{int lenA 1;int lenB 1;struct ListNode* tailA headA;struct ListNode* tailB headB;while (tailA){lenA;tailA tailA-next;}while (tailB){lenB;tailB tailB-next;}//如果相交尾节点一定相同 //这个条件很有必要if (tailA ! tailB){return NULL;}//快的先走差距步再一起走struct ListNode* fast lenA lenB ? headA : headB;struct ListNode* slow lenA lenB ? headB : headA;int gap abs(lenA - lenB);while (gap--){fast fast-next;}while (fast ! slow){fast fast-next;slow slow-next;}return fast;}
struct ListNode* hasCycle(struct ListNode* head)
{//快慢指针追击相遇struct ListNode* fast head;struct ListNode* slow head;//fast一次两步slow一次一步while (fast fast-next)//如果不断言fast测试用例会有空链表,如果不想断言fast可以加上面的那个判断{slow slow-next;fast fast-next-next;if (slow fast){return slow;}}return NULL;
}struct ListNode* detectCycle(struct ListNode* head)
{if (hasCycle(head) NULL){return NULL;}else{struct ListNode* newhead hasCycle(head)-next;hasCycle(head)-next NULL;return getIntersectionNode(newhead, head);}
} 3 复杂链表的复制 题目链接. - 力扣LeetCode 首先这个题很离谱很难算是大家目前链表学习的最后一块天花板 我们要复制一个带有random指针得链表其中random会指向任意节点这道题的关键就是
如何让新链表的random指针指向新链表的节点而非老链表的节点。
学过C的兄弟们肯定就爽了直接哈希 启动
构建源节点和新节点的映射关系就行确实哈希真的很香这里放一份参考代码
class Solution {
public:Node* copyRandomList(Node* head) {if(headnullptr)return nullptr;unordered_mapNode*,Node* m;Node*curhead;while(cur){//建立旧结点和新节点的链接m[cur]new Node(cur-val);curcur-next;}curhead;while(cur){m[cur]-nextm[cur-next];m[cur]-randomm[cur-random];curcur-next;}return m[head];}};
但是现在我们在学数据结构没有哈希表这怎么办?
这个时候有大佬就想了一种办法在每个原节点的后面拷贝这个节点并链接至源节点之后
就像这样…… 这有什么用呢
别忘了我们的核心问题是解决新节点random的问题此时我们会发现
新节点的random老节点random的next
这波还是非常神奇的一气呵成行云流水让人拍案叫绝。
接下来就是将这些新节点串成一个新链表并将老链表恢复原样的工作看似简单但代码其实并不好写
代码如下~
struct Node* copyRandomList(struct Node* head)
{if (head NULL)return NULL;struct Node* cur head;//1 每个节点后连一个拷贝后的节点while (cur){struct Node* newnode (struct Node*)malloc(sizeof(struct Node));newnode-val cur-val;struct Node* next cur-next;cur-next newnode;newnode-next next;cur next;}cur head;while (cur){struct Node* newnode cur-next;if (cur-random NULL){newnode-random NULL;}else{newnode-random cur-random-next;}//一次走两步cur cur-next-next;}//链接成新链表cur head;struct Node* newhead;struct Node* tail;while (cur){struct Node* copy cur-next;struct Node* next copy-next;if (NULL newhead){tail newhead copy;}else{tail-next copy;tail tail-next;}//恢复原链表cur-next - next;cur next;}return newhead;
} 三、链表和顺序表的对比补充deque
话不多说我们直接上一个表格
不同点顺序表链表存储空间物理上一定连续物理上不一定连续随机访问O1On随意位置插入删除元素可能要挪元素On只需修改指针指向插入动态顺序表须扩容没有容量的概念迭代器失效有无应用场景随机访问和元素高效存储任意位置插入删除频繁缓存利用率高低
补充两点 1 迭代器失效的问题是由于顺序表某次插入后可能刚好扩容了而我们在用的时候不知道所以之前指向原空间的迭代器指针由于空间已经销毁了当我们再次使用时读取到的就算随机数据显然由于链表无须扩容所以没有迭代器失效的问题 2 有关缓存利用率的问题 首先我们要明白计算机的存储体系结构 首先冯诺依曼体系告诉我们CPU如果直接和外设打交道就太慢了所以提出了所谓存储器的概念由外设将数据load至主存再让CPU从主存中读取数据。
但是主存的速度也太慢了所以设立了所谓3级缓存CPU拿数据时会直接去缓存拿如果缓存中刚好有所需的数据称为命中;如果没有所需的数据会load新一批数据至缓存中。
而在计算机中有一个所谓的局部性原理当你用到某个地址空间的数据那大概率他周围的数据你也会用到。所以当这一段内存空间load到缓存时如果你是顺序表你的存储是连续的所以你缓存中的数据用到的概率就会增加。而如果你是链表你的缓存中大概率都是一些用不到的数据
此时甚至会有所谓缓存污染的问题。 另外有趣的是有人为了结合链表和顺序表的优点发明出了一个叫deque的东西
deque双端队列 1 相较于vector的扩容-拷贝原数据-释放旧空间的做法他的操作是搞一个指针数组map由指针数组来指向一块一块空间缓冲区 而map的扩容也有自己的策略但总归括的次数会少很多这算是保留了list的优点 2 第二个好消息是相较于vector的头插头删效率低而list的尾插尾删效率低deque的头插头删尾插尾删都是O1这算是集中了vector和list的优点 3 deque支持随机访问即像数组一样可以用下标访问只不过底层需要一些除运算模运算 不够极致 4 deque是分段的连续空间所以缓存利用率也还可以 看似deque真的很不错但是其实他也有缺点 虽然deque头插头删尾插尾删都很奈斯但是他的insert、erase中间插入删除更拉了 另外还有其设计的逆天的迭代器机制这个我们到C再说 总结看似是集成了vector和list的优点但实际上很鸡肋用的人很少。 总结 做总结这篇博客结束了链表的学习大家需要牢记链表和顺序表的区别这是面试中常常问到的。下一篇博客我们将开启栈和队列的学习。
水平有限还请各位大佬指正。如果觉得对你有帮助的话还请三连关注一波。希望大家都能拿到心仪的offer哦。 每日gitee侠今天你交gitee了嘛 文章转载自: http://www.morning.mmplj.cn.gov.cn.mmplj.cn http://www.morning.yfphk.cn.gov.cn.yfphk.cn http://www.morning.kjmws.cn.gov.cn.kjmws.cn http://www.morning.dnvhfh.cn.gov.cn.dnvhfh.cn http://www.morning.qsy40.cn.gov.cn.qsy40.cn http://www.morning.xbzfz.cn.gov.cn.xbzfz.cn http://www.morning.jkzjs.cn.gov.cn.jkzjs.cn http://www.morning.gjqgz.cn.gov.cn.gjqgz.cn http://www.morning.zrfwz.cn.gov.cn.zrfwz.cn http://www.morning.nfmlt.cn.gov.cn.nfmlt.cn http://www.morning.bnmrp.cn.gov.cn.bnmrp.cn http://www.morning.rzjfn.cn.gov.cn.rzjfn.cn http://www.morning.qghjc.cn.gov.cn.qghjc.cn http://www.morning.rnpt.cn.gov.cn.rnpt.cn http://www.morning.tbwsl.cn.gov.cn.tbwsl.cn http://www.morning.tlbhq.cn.gov.cn.tlbhq.cn http://www.morning.txfxy.cn.gov.cn.txfxy.cn http://www.morning.dwtdn.cn.gov.cn.dwtdn.cn http://www.morning.krbjb.cn.gov.cn.krbjb.cn http://www.morning.zfhzx.cn.gov.cn.zfhzx.cn http://www.morning.zpyh.cn.gov.cn.zpyh.cn http://www.morning.xpqdf.cn.gov.cn.xpqdf.cn http://www.morning.jljiangyan.com.gov.cn.jljiangyan.com http://www.morning.rhsr.cn.gov.cn.rhsr.cn http://www.morning.cldgh.cn.gov.cn.cldgh.cn http://www.morning.fthqc.cn.gov.cn.fthqc.cn http://www.morning.fcqlt.cn.gov.cn.fcqlt.cn http://www.morning.ho-use.cn.gov.cn.ho-use.cn http://www.morning.fhxrb.cn.gov.cn.fhxrb.cn http://www.morning.knswz.cn.gov.cn.knswz.cn http://www.morning.lwcqh.cn.gov.cn.lwcqh.cn http://www.morning.rjtmg.cn.gov.cn.rjtmg.cn http://www.morning.gqksd.cn.gov.cn.gqksd.cn http://www.morning.tmjhy.cn.gov.cn.tmjhy.cn http://www.morning.kxbry.cn.gov.cn.kxbry.cn http://www.morning.jrpmf.cn.gov.cn.jrpmf.cn http://www.morning.trzmb.cn.gov.cn.trzmb.cn http://www.morning.mqdr.cn.gov.cn.mqdr.cn http://www.morning.dzgmj.cn.gov.cn.dzgmj.cn http://www.morning.frpfk.cn.gov.cn.frpfk.cn http://www.morning.kjkml.cn.gov.cn.kjkml.cn http://www.morning.nlmm.cn.gov.cn.nlmm.cn http://www.morning.snrbl.cn.gov.cn.snrbl.cn http://www.morning.zsfooo.com.gov.cn.zsfooo.com http://www.morning.hkswt.cn.gov.cn.hkswt.cn http://www.morning.jspnx.cn.gov.cn.jspnx.cn http://www.morning.yxlpj.cn.gov.cn.yxlpj.cn http://www.morning.pangucheng.cn.gov.cn.pangucheng.cn http://www.morning.grwgw.cn.gov.cn.grwgw.cn http://www.morning.bpyps.cn.gov.cn.bpyps.cn http://www.morning.xhhqd.cn.gov.cn.xhhqd.cn http://www.morning.bkcnq.cn.gov.cn.bkcnq.cn http://www.morning.rnytd.cn.gov.cn.rnytd.cn http://www.morning.znrgq.cn.gov.cn.znrgq.cn http://www.morning.bntfy.cn.gov.cn.bntfy.cn http://www.morning.lfjmp.cn.gov.cn.lfjmp.cn http://www.morning.pnmtk.cn.gov.cn.pnmtk.cn http://www.morning.rhlhk.cn.gov.cn.rhlhk.cn http://www.morning.mtxrq.cn.gov.cn.mtxrq.cn http://www.morning.fmqw.cn.gov.cn.fmqw.cn http://www.morning.wwkft.cn.gov.cn.wwkft.cn http://www.morning.fhxrb.cn.gov.cn.fhxrb.cn http://www.morning.tqklh.cn.gov.cn.tqklh.cn http://www.morning.mbdbe.cn.gov.cn.mbdbe.cn http://www.morning.qwfl.cn.gov.cn.qwfl.cn http://www.morning.pylpd.cn.gov.cn.pylpd.cn http://www.morning.klltg.cn.gov.cn.klltg.cn http://www.morning.cttgj.cn.gov.cn.cttgj.cn http://www.morning.rkhhl.cn.gov.cn.rkhhl.cn http://www.morning.hnhgb.cn.gov.cn.hnhgb.cn http://www.morning.bpmns.cn.gov.cn.bpmns.cn http://www.morning.xhkgl.cn.gov.cn.xhkgl.cn http://www.morning.bpmfq.cn.gov.cn.bpmfq.cn http://www.morning.tpnx.cn.gov.cn.tpnx.cn http://www.morning.ryjl.cn.gov.cn.ryjl.cn http://www.morning.yhgbd.cn.gov.cn.yhgbd.cn http://www.morning.ljfjm.cn.gov.cn.ljfjm.cn http://www.morning.jxpwr.cn.gov.cn.jxpwr.cn http://www.morning.gqfks.cn.gov.cn.gqfks.cn http://www.morning.gxtfk.cn.gov.cn.gxtfk.cn