本文的源代码和测试代码: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;
下来我们就来分析一下如何对这个复杂链表进行复制:
方法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; }