标签:复杂链表的复制
何为复杂链表呢?
在复杂链表中,每个结点除了有一个_next指针指向下一个结点,还有一个_random指向链表中的任意结点或者NULL。结点定义如下:
template <class T> struct ComplexNode { public: ComplexNode(const T&d) :_data(d) ,_next(NULL) ,_random(NULL) {} public: T _data;//数据 ComplexNode* _next;//指向下一个节点 ComplexNode* _random;//指向随机节点或者NULL };
如图是一个含有5个结点的复杂链表。实线箭头为_next指针,虚线为_random指针。
看到此问题时,首先会想到把复制过程分成两部分:第一步是复制原始链表上的每一个节点,并用_next连接起来;第二步是设置每个节点的_random指针。假设原始链表中的节点N的_random指向节点S,由于S节点的位置可能在N的前面,也有可能在N的后面。所以要定位S的位置需要从头开始查找。如果从开始链表的头结点开始沿着_next经过n步找到节点S,那么在复制链表中节点N‘的_random离复制链表的头结点的距离也是n步。若有n个节点,为每个节点查找_random时,都需要从头结点开始查找。因此此方法的时间复杂度度为O(n^2)。
由于上面一种方法的时间主要花费在查找节点的_random上面。可以从这方面去优化。
第一步:根据原始链表的每一个节点N创建对应的N’,并连接在N后。(如图所示)
第二步:设置复制出来节点的_random。假设原始链表上的节点N的_random指向节点S,由图可以看出,N‘的_random是N的_random的_next指向的节点。(红线所示)第三步:拆分链表。把奇数位上的节点用_next连接起来就是原始链表,把偶数位上的节点用_next连接起来即为复制后的节点。
由此看来,时间复杂度为O(n)。
接下来,实现第二种思路。
第一步:复制节点
template <class T> void CopyNode(ComplexNode<T>* pHead) //复制节点 { ComplexNode<T>* cur = pHead; while(cur) { ComplexNode<T>* pClone = new ComplexNode<T>(cur->_data);//创建新的节点 pClone->_next = cur->_next; pClone->_random = NULL; cur->_next = pClone; cur = pClone->_next; } }
第二步:设置复制出来的节点的_random
template <class T> void RandomNode(ComplexNode<T>* pHead)//找_random { ComplexNode<T>* cur = pHead; ComplexNode<T>* pClone = pHead->_next; while(pClone->_next) { if(cur->_random != NULL) { pClone->_random = cur->_random->_next;//复制节点的_random为原始节点的_random指针的_next } cur = pClone->_next; pClone = cur->_next; } }
第三步:拆分链表
template <class T> ComplexNode<T>* ConnectNode(ComplexNode<T>* pHead)//拆分链表 { ComplexNode<T>* cur = pHead;//奇数位 ComplexNode<T>* pCloneNode = pHead->_next;//偶数位 ComplexNode<T>* pCloneHead = pHead->_next; while(pCloneNode->_next) { cur->_next = pCloneNode->_next;//原始节点链接 cur = cur->_next; pCloneNode->_next = cur->_next;//复制后节点的链接 pCloneNode = pCloneNode->_next; } return pCloneHead; }
创建复制链表:
template <class T> ComplexNode<T>* CreatNode(ComplexNode<T>* pHead)//构造复杂链表 { ComplexNode<T>* Node1 = new ComplexNode<T>(1); ComplexNode<T>* Node2 = new ComplexNode<T>(2); ComplexNode<T>* Node3 = new ComplexNode<T>(3); ComplexNode<T>* Node4 = new ComplexNode<T>(4); ComplexNode<T>* Node5 = new ComplexNode<T>(5); pHead = Node1; Node1->_next = Node2; Node2->_next = Node3; Node3->_next = Node4; Node4->_next = Node5; Node1->_random = Node3; Node2->_random = Node5; Node4->_random = Node2; return pHead; }
打印链表:
template <class T> void PrintNode(ComplexNode<T>* pHead)//打印 { ComplexNode<T>* cur = pHead; while(cur) { cout<<cur->_data<<" "; if(cur->_random)//若_random不为空 { cout<<cur->_random->_data; } cout<<"->"; cur = cur->_next; } cout<<endl; }
主函数实现:
int main() { ComplexNode<int>* head = NULL; ComplexNode<int>* ret = CreatNode(head);//创建复杂链表 cout<<"原来的链表:"<<endl; PrintNode(ret); CopyNode(ret);//复制节点 RandomNode(ret);//链接复制后节点的_random ComplexNode<int>* tmp = ConnectNode(ret);//拆分节点 cout<<"复制后的链表:"<<endl; PrintNode(tmp); return 0; }
测试结果:
本文出自 “一起去看星星” 博客,转载请与作者联系!
标签:复杂链表的复制
原文地址:http://10810429.blog.51cto.com/10800429/1764455