版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/82588247
面试题35:复杂链表的复制
书上有图,不再画了。
请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling 指向链表中的任意结点或者nullptr。
复杂链表比普通的单链表多了一个Sibling域,可以指向任意的一个结点。如何将Sibling域高效地拷贝是复杂链表复制的难点。
在原链表上,每个结点后面夹上拷贝它的结点,形成一个合并链表,因为拷贝结点总是跟在原结点后面,所以Sibling域也就是原结点Sibling域的下一结点。
ComplexList.h
#pragma once
//复杂链表的结点
struct ComplexListNode {
//普通链表就有的值和next域
int m_nValue;
ComplexListNode* m_pNext;
//复杂链表还多一个指向任意结点的域
ComplexListNode* m_pSibling;
};
//建立指定Value的新结点
ComplexListNode* CreateNode(int nValue);
//建立结点关系
void BuildNodes(ComplexListNode* pNode, ComplexListNode* pNext, ComplexListNode* pSibling);
//输出复杂链表
void PrintList(ComplexListNode* pHead);
ComplexList.cpp
#include <cstdio>
#include "ComplexList.h"
//建立指定Value的结点:创建结点,设定值,返回
ComplexListNode* CreateNode(int nValue) {
ComplexListNode* pNode = new ComplexListNode();
pNode->m_nValue = nValue;
pNode->m_pNext = nullptr;
pNode->m_pSibling = nullptr;
return pNode;
}
//建立结点关系
void BuildNodes(ComplexListNode* pNode, ComplexListNode* pNext, ComplexListNode* pSibling) {
if(pNode != nullptr) {//检查要设置关系的结点非空
pNode->m_pNext = pNext;
pNode->m_pSibling = pSibling;
}
}
//输出复杂链表
void PrintList(ComplexListNode* pHead) {
ComplexListNode* pNode = pHead;
while(pNode != nullptr) {
printf("The value of this node is: %d.\n", pNode->m_nValue);
//在输出时把它独有的域也输出,next域不用输出
if(pNode->m_pSibling != nullptr)
printf("The value of its sibling is: %d.\n", pNode->m_pSibling->m_nValue);
else
printf("This node does not have a sibling.\n");
printf("\n");
//因为输出链表时候还是从前向后按next这条路走
pNode = pNode->m_pNext;
}
}
复制复杂链表
#include<bits/stdc++.h>
#include "../Utilities/ComplexList.h"
using namespace std;
void CloneNodes(ComplexListNode* pHead);
void ConnectSiblingNodes(ComplexListNode* pHead);
ComplexListNode* ReconnectNodes(ComplexListNode* pHead);
//[总的函数]复制一个复杂链表,传入原型链表头,返回复制后链表的头
ComplexListNode* Clone(ComplexListNode* pHead) {
CloneNodes(pHead);//第一遍O(n)扫描,做克隆合并
ConnectSiblingNodes(pHead);//第二版O(n)扫描,给出Sibling域
//为什么不能一遍扫描?因为第一遍扫的时候后面的结点还没克隆创好
//如果Sibling域指向后面的结点,那没法给出Sibling域
return ReconnectNodes(pHead);//第三遍O(n)扫描,拆开搞成2个链表
}
//[克隆合并]对复杂链表的每个结点克隆,将其夹在原结点之next、原next之前
void CloneNodes(ComplexListNode* pHead) {
ComplexListNode* pNode = pHead;//从头结点开始
//沿着next走
while(pNode != nullptr) {
//复制当前结点
ComplexListNode* pCloned = new ComplexListNode();
pCloned->m_nValue = pNode->m_nValue;
pCloned->m_pNext = pNode->m_pNext;//注意其next也指向当前的next
pCloned->m_pSibling = nullptr;//唯有这个特殊指针暂时置空
//将原结点的next指向新克隆的结点,所以克隆的结点在next链上是被夹杂其中
pNode->m_pNext = pCloned;
//沿着next走
pNode = pCloned->m_pNext;
}
}
//连接Sibling域,传入[克隆合并]后的链表(next链已经变成两倍长了)
void ConnectSiblingNodes(ComplexListNode* pHead) {
ComplexListNode* pNode = pHead;//从头结点开始
//一直沿着next链走
while(pNode != nullptr) {
//克隆的结点总是在原结点的后面一个
ComplexListNode* pCloned = pNode->m_pNext;
//现在要克隆其Sibling域,只要原结点的Sibling域非空
if(pNode->m_pSibling != nullptr) {
//那么Sibling域所指的那个结点的后一个结点也就是其克隆结点
//所以本结点的克隆结点的Sibling域将指向原结点的Sibling域的next
pCloned->m_pSibling = pNode->m_pSibling->m_pNext;
}
//一直沿着next链走
pNode = pCloned->m_pNext;
}
}
//将这个大链表拆开,把之前的原链表建回来
//并把新的克隆的链表也维护好,然后返回之
ComplexListNode* ReconnectNodes(ComplexListNode* pHead) {
ComplexListNode* pNode = pHead;//原链表上的游标指针,从[合并链表]头开始
ComplexListNode* pClonedHead = nullptr;//克隆链表的头
ComplexListNode* pClonedNode = nullptr;//克隆链表上的游标指针
if(pNode != nullptr) {//这里是防止空指针异常
//克隆链表头和其上的游标都初始化为[合并链表]的第二个结点
pClonedHead = pClonedNode = pNode->m_pNext;
//原链表的next,是[合并链表]上其克隆结点的next
pNode->m_pNext = pClonedNode->m_pNext;
//原链表指针向后走
pNode = pNode->m_pNext;
}
//至此,[原链表指针]比[克隆链表指针]领先一个身位
//即这个[原链表指针]其实是对应当前[克隆链表指针]所指元素的下一个元素
//并且[原链表指针]和后面一个身位的[克隆链表指针]都挂在[合并链表上]
//只要[原链表指针]没到空,也即没有遍历完
while(pNode != nullptr) {
//[克隆链表指针]的next也就是它前面的[原链表指针]的next
pClonedNode->m_pNext = pNode->m_pNext;
//[克隆链表指针]向后走
pClonedNode = pClonedNode->m_pNext;
//现在,[克隆链表指针]又和[原链表指针]指向的元素相对应了
//并且[克隆链表指针]还挂在[合并链表上]
//[原链表指针]要维护next域(并向下走),要依赖这个[克隆链表指针]
//[原链表指针]的next域就是[克隆链表指针]的下一个
pNode->m_pNext = pClonedNode->m_pNext;
//[原链表指针]向下走
pNode = pNode->m_pNext;
}
return pClonedHead;//最终返回[克隆链表头]
}
// -----------------
// \|/ |
// 1-------2-------3-------4-------5
// | | /|\ /|\
// --------+-------- |
// -------------------------
int main() {
ComplexListNode* pNode1 = CreateNode(1);
ComplexListNode* pNode2 = CreateNode(2);
ComplexListNode* pNode3 = CreateNode(3);
ComplexListNode* pNode4 = CreateNode(4);
ComplexListNode* pNode5 = CreateNode(5);
BuildNodes(pNode1, pNode2, pNode3);
BuildNodes(pNode2, pNode3, pNode5);
BuildNodes(pNode3, pNode4, nullptr);
BuildNodes(pNode4, pNode5, pNode2);
ComplexListNode* newNode=Clone(pNode1);
PrintList(newNode);
return 0;
}