输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
struct RandomListNode* Clone(struct RandomListNode* pHead ) {
if(pHead == NULL){
return NULL;
}
struct RandomListNode* head = malloc(sizeof(struct RandomListNode));
struct RandomListNode* right = head; //right 用来指向head进行遍历
struct RandomListNode* pRight = pHead; //pRight 用来指向pHead进行遍历
while(pRight != NULL){
struct RandomListNode* temp = malloc(sizeof(struct RandomListNode));
right->label = pRight->label;
if(pRight->next == NULL){
right->next = NULL;
break;
}
right->next = temp;
right = right->next;
pRight = pRight->next;
}
//上述代码构造出了主链,还剩下random指针没有复制
right = head;
pRight = pHead;
struct RandomListNode *mark, *pMark, *ppHead, *rrhead;
while(pRight != NULL){
pMark = pRight->random;
if(pMark == NULL){
right->random = NULL;
pRight = pRight->next;
right = right->next;
continue;
}
ppHead = pHead;
rrhead = head;
while(ppHead != pMark){
//由于新构造的链表地址与原链表不相同,因此单纯复制地址是不行的
//需要找到对于与开头的相对位置
ppHead = ppHead->next;
rrhead = rrhead->next;
}
//此时找到了新链表的地址,然后进行赋值
right->random = rrhead;
pRight = pRight->next;
right = right->next;
}
return head;
}
分析:
总体思路为先构造主链表,然后构造random指针。其中指针不能直接赋值,需要遍历寻找相对于首节点的位置。
剑指offer给了一种更好的思路,见书188页