剑指Offer___关于复杂链表的复制算法剖析

来源:互联网 发布:linux 70秒漏洞 编辑:程序博客网 时间:2024/06/05 01:51

本文的源代码和测试代码:https://github.com/clearoff/learngit/blob/master/ComplexLinklist.c

1、复杂链表的定义:

      一般的,我们把只有一个数据于和一个指针的节点所组成的链表叫做单链表,由单链表我们引出了复杂链表的定义,如下图:


【复杂链表在C语言中的定义】:

typedef struct ComplexLinkNode{Datatype data;struct ComplexLinkNode *p_Next;    //指向下一个节点的指针struct ComplexLinkNode *p_sibling;  //指向任意一个节点或者空}ComplexLinkNode;

由图可知,复杂链表不光含有单链表中的指向下一个元素的指针,还含有一个指针可以指向任意一个节点或者NULL!

下来我们就来分析一下如何对这个复杂链表进行复制:

方法1:首先我们可以拷贝复杂链表中的单链表部分,并且让拷贝出来的链表所有节点的p_Sibling都指向NULL,

随后我们就要明确所拷贝链表中每一个p_Sibling指针的指向,我们可以先遍历源链表,用两个变量分别记录从头节点到p_Sibling指针不为NULL的节点和p_Sibling所指向节点的步数,然后从所拷贝的链表中找到相应的节点,并进行连接。

【相应C语言代码】:

ComplexLinkNode* Clone_Nodes(ComplexLinkNode* list)      //时间复杂度为O(n*n)的方法{assert(list);ComplexLinkNode* list2 = NULL;ComplexLinkNode* cur1  = list;ComplexLinkNode* tmp   = NULL;int count1 = 0;             //记录原链表找到指针的步数int count2 = 0;             //记录找到指针所指向节点的步数while (cur1)       //先拷贝复杂链表中的单链表部分{ComplexLinkNode* New  = NULL;New = (ComplexLinkNode*)malloc(sizeof(ComplexLinkNode)* 1);     //开辟一个新节点if (New == NULL){printf("Out of memory!\n");exit(EXIT_FAILURE);}New->data = cur1->data;New->p_Next = NULL;New->p_sibling = NULL;if (list2 == NULL){list2 = New;tmp = list2;}else{tmp->p_Next = New;tmp = New;}cur1 = cur1->p_Next;}cur1 = list;while (cur1){ComplexLinkNode *pos1 = NULL;ComplexLinkNode *pos2 = NULL;count1 = 0;count2 = 0;if (cur1->p_sibling != NULL){ComplexLinkNode *pcur1 = list;ComplexLinkNode *pcur2 = list;pos1 = cur1;pos2 = cur1->p_sibling;while (pcur1 != pos1){count1++;pcur1 = pcur1->p_Next;}while (pcur2 != pos2){count2++;pcur2 = pcur2->p_Next;}pcur1 = list2;pcur2 = list2;while ((pcur1 != NULL)&&count1){count1--;pcur1 = pcur1->p_Next;}while ((pcur2 != NULL) && count2){count2--;pcur2 = pcur2->p_Next;}pcur1->p_sibling = pcur2;}cur1 = cur1->p_Next;}printf("复杂链表复制成功!\n");return list2;}
由于这种算法需要两次遍历原链表,所以时间复杂度很高,为了减少时间复杂度,我们来参考一下第二种方法:


方法二:在克隆复杂链表中的单链表时,我们不重新建立头节点,而是直接把N节点的拷贝节点链在N节点的后面,

如下图:


【该步骤的C语言代码】:

ComplexLinkNode* CloneNodes(ComplexLinkNode *list)              //复制复杂链表的pNext部分!{assert(list);ComplexLinkNode *pNode = list;while (pNode){ComplexLinkNode *pClone = (ComplexLinkNode*)malloc(sizeof(ComplexLinkNode)* 1);if (pClone == NULL){printf("Out of memory!\n");exit(EXIT_FAILURE);}pClone->data = pNode->data;pClone->p_Next = pNode->p_Next;pClone->p_sibling = NULL;pNode->p_Next = pClone;pNode = pClone->p_Next;}return list;}
随后,我们在明确经过上面一个人步骤后链表中每一个节点的指向,找到了N节点p_Sibling指针不为NULL的节点后,我们只需要把N节点的下一个节点指向N节点p_Sibling所指向的节点的下一个节点就可以了。

【该步骤的C语言代码】:

ComplexLinkNode* ConnectSiblingNodes(ComplexLinkNode* head)       //复制出来结点的p_sibling指针{assert(head);ComplexLinkNode* pNode = head;while (pNode){ComplexLinkNode* pClone = pNode->p_Next;if (pNode->p_sibling != NULL){pClone->p_sibling = pNode->p_sibling->p_Next;}pNode = pClone->p_Next;}return head;}

最后一步:切断原链表和拷贝出来的链表

【C语言代码】:

ComplexLinkNode* CutList(ComplexLinkNode* head){assert(head);ComplexLinkNode* head2 = NULL;ComplexLinkNode* pNode = head;ComplexLinkNode* pClone = NULL;if (pNode)                             //将克隆出来的节点连接头节点{head2 = pNode->p_Next;pClone = pNode->p_Next;pNode->p_Next = pClone->p_Next;pNode = pNode->p_Next;}while (pNode){pClone->p_Next = pNode->p_Next;pClone = pNode->p_Next;pNode->p_Next = pClone->p_Next;pNode = pNode->p_Next;}return head2;}


如果本文有问题,希望大家能提些意见!!!


1 0
原创粉丝点击