题目描述:请实现函数ComplexListNode *Clone(ComplexListNode *pHead); 复制一个复杂链表。在复杂链表中,每个节点除了有一个m_Next指针指向下一个节点外,还有一个s_Sibling指向链表中的任意节点或者NULL。
复杂链表节点定义如下:
//复杂链表的定义
struct ComplexListNode{
int m_value; //节点存储的值
ComplexListNode *m_next; //节点指针
ComplexListNode *m_Sibling; //兄弟节点
void show(); //打印所有节点值
};
解题思路:
A.空间换时间
- 复制原始链表上的每个节点N,创建N’,然后把这些创建出来的节点用m_Next链接起来。同时我们把(N, N’)的配对信息放到一个哈希表中。
- 设置复制链表上每个结点的m_Sibling。如果在原始链表中节点N的m_Sibling指向节点S, 那么在复制链表中,对应的N’应该指向S’。由于有了哈希表。我们可以用O(1)的时间根据S找到S’。
B.不适用辅助空间
- 在原始链表的每个节点N创建对应N’,然后把N’链接在N的后面。
- 设置复制出来的节点的m_Sibling。假设原始链表上的N的m_Silbling指向节点S,那么对应复制出来的N’是N的m_Next指向的节点,同样S’也是S的m_Next指向的节点。 即原始链表上的节点N的m_Sibling指向S,则它对应的复制节点N’的m_Sibling指向S的下一节点S’。
- 把这个长链表分成两个链表:把奇数位置的节点用m_Next链接起来就是原始链表。把偶数位置的节点用m_Next链接起来就是复制出来的链表。
测试用例:
int main(){
//m_next: 1->2->3->4->5->NULL; m_Sibling: 1->3、2->5、4->2
ComplexListNode *p1 = new ComplexListNode;
p1 = NULL;
addToTail(&p1, 1);
addToTail(&p1, 2); //末尾加入2
addToTail(&p1, 3); //末尾加入3
addToTail(&p1, 4); //末尾加入4
addToTail(&p1, 5); //末尾加入5
addToTail(&p1, 6); //末尾加入6
// p1->show(); //Output:1,2,3,4,5,6
// std::cout << std::endl;
// std::cout << p1->m_value << std::endl; //Output: 1
p1->m_Sibling = p1->m_next->m_next;
// std::cout << p1->m_Sibling->m_value << std::endl; //Output: 3
p1->m_next->m_Sibling = p1->m_next->m_next->m_next->m_next;
// std::cout << p1->m_next->m_Sibling->m_value <<std::endl; //Output: 5
p1->m_next->m_next->m_next->m_next->m_Sibling = p1->m_next;
// std::cout << p1->m_next->m_next->m_next->m_next->m_Sibling->m_value << std::endl; //Output: 2
//复制复杂链表
ComplexListNode *clone = new ComplexListNode;
clone = Clone(p1);
//检查结果
p1->show(); //Output:1,2,3,4,5,6
std::cout << std::endl;
std::cout << p1->m_value << std::endl; //Output: 1
std::cout << p1->m_Sibling->m_value << std::endl; //Output: 3
std::cout << p1->m_next->m_Sibling->m_value <<std::endl; //Output: 5
std::cout << p1->m_next->m_next->m_next->m_next->m_Sibling->m_value << std::endl; //Output: 2
return 0;
}
函数实现:(B方法,不使用辅助空间)
//实现链表m_next节点的复制,并以此将N'接到N节点的后面
void CloneNodes(ComplexListNode *pHead){
//副本节点
ComplexListNode *pNode = pHead;
while(pNode != NULL){
//克隆节点
ComplexListNode *pClone = new ComplexListNode;
pClone->m_value = pNode->m_value;
pClone->m_next = pNode->m_next;
pClone->m_Sibling = NULL; //第一步先全部初始化为NULL
//把pClone接到原链表的后面
pNode->m_next = pClone;
//更新节点
pNode = pClone->m_next;
}
}
//复制m_Sibling节点
void ConnectSiblingNodes(ComplexListNode *pHead){
//副本
ComplexListNode *pNode = pHead;
while(pNode != NULL){
//当前克隆的链表节点已经是2合1的链表
ComplexListNode *pClone = pNode->m_next;
//如果原链表节点有m_Sibling
if(pNode->m_Sibling != NULL){
//在2合1链表中sibling的位置就是
pClone->m_Sibling = pNode->m_Sibling->m_next;
}
//更新pNode,pClone的下一节点就是原m_next节点
pNode = pClone->m_next;
}
}
//将2合1的链表拆开,奇数位置是原链表,偶数位置是克隆的链表
ComplexListNode* ReconnectNodes(ComplexListNode *pHead){
//副本
ComplexListNode *pNode = pHead;
//克隆头
ComplexListNode *cloneHead = new ComplexListNode;
cloneHead = NULL;
//存储克隆节点
ComplexListNode *cloneNode = new ComplexListNode;
cloneNode = NULL;
if(pNode != NULL){
//克隆偶数位置
cloneHead = cloneNode = pNode->m_next;
//更新pNode
pNode->m_next = cloneNode->m_next;
pNode = pNode->m_next;
}
while(pNode != NULL){
cloneNode->m_next = pNode->m_next;
cloneNode = cloneNode->m_next;
pNode->m_next = cloneNode->m_next;
pNode = pNode->m_next;
}
return cloneHead;
}
// 函数实现
ComplexListNode* Clone(ComplexListNode *pHead){
//第一步,复制原有m_next节点
CloneNodes(pHead);
//第二部,复制m_Sibling节点,将两个链表链在一起实现
ConnectSiblingNodes(pHead);
//第三步,分解链表。奇数位置为原节点,偶数位置为克隆的节点
return ReconnectNodes(pHead);
}
其他函数实现:
void ComplexListNode::show(){
ComplexListNode *temp = this;
while(temp != NULL){
std::cout << temp->m_value << " ";
temp = temp->m_next;
}
}
//在一个链表的末尾添加一个节点
void addToTail(ComplexListNode **head, int value){//由于会改动链表指针,所以必须把head参数设为指向指针的指针。否则出了这个函数作用域,改动便无效。
//1.首先创建要插入的节点
ComplexListNode *pNew = new ComplexListNode;
pNew->m_value = value; //指定值
pNew->m_next = NULL; //!!!切记指定下一节点为NULL
//2.如果传入的节点为空,可直接创键头节点
if(*head == NULL)
*head = pNew;
else{//否则3.
//定义一个临时节点
ComplexListNode *temp = *head;
while(temp->m_next != NULL) //循环指向末尾节点, !!!切记必须指向下一节点
temp = temp->m_next;
//对末尾的下一个节点赋值,取代之(末尾)
temp->m_next = pNew;
}
}