单链表的简单操作已经在前面的几篇文章里有写,在这里就不再赘述,下面就是一些常见的笔试面试题
1.逆置/反转链表
void LinkListReverse(LinkNode** phead)
{
if(phead == NULL)
{
return;
}
if(*phead == NULL)
{
return;
}
if((*phead)->next==NULL)
{
//只有一个元素
return;
}
LinkNode* pos = *phead;
while(pos->next != NULL)
{
LinkNode* cur = pos->next;
pos->next = cur->next;
cur->next = *phead;
*phead = cur;
}
return;
}
void TestReverse()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListReverse(&head);
LinkListPrintChar(head,"逆置链表");
}
void LinkListReverse2(LinkNode** phead)
{
if(phead == NULL)
{
return;
}
if(*phead == NULL)
{
return;
}
if((*phead)->next == NULL)
{
return;
}
LinkNode* cur = (*phead)->next;
LinkNode* pre = *phead;
pre->next = NULL;
while(cur != NULL)
{
LinkNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
*phead = pre;
return;
}
void TestReverse2()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListReverse2(&head);
LinkListPrintChar(head,"逆置链表");
}
2.单链表排序(冒泡排序)
有2种方法,第一种参数是LinkNode** ----两个结构体交换位置,交换链表节点
第二种参数是LinkNode* ----交换结构体内的值
在这里我们采用的是第二种方法较为简单
void Swap(LinkNodeType* a,LinkNodeType* b)
{
LinkNodeType tmp = *a;
*a = *b;
*b = tmp;
return;
}
void LinkListBubbleSort(LinkNode* phead)
{
if(phead == NULL)
{
return;
}
LinkNode* tail = NULL;
LinkNode* count = phead;
for(;count != NULL;count=count->next)
{
LinkNode* cur = phead;
for(;cur->next != tail;cur = cur->next)
{
if(cur->data > cur->next->data)
{
Swap(&cur->data,&cur->next->data);
}
}
tail = cur;
}
return;
}
void TestBubbleSort()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'b');
LinkListBubbleSort(head);
LinkListPrintChar(head,"冒泡排序");
}
3.合并两个有序链表,合并后依然有序
LinkNode* LinkListMerge(LinkNode* phead1,LinkNode* phead2)
{
if(phead1 == NULL)//如果第一个链表为空所以直接返回第二个链表
{
return phead2;
}
if(phead2 == NULL)//如果第二个链表为空则返回第一个链表
{
return phead1;
}
LinkNode* cur1 = phead1;
LinkNode* cur2 = phead2;
LinkNode* new_head = NULL;
LinkNode* new_tail = NULL;
while((cur1 != NULL )&& (cur2 != NULL))//任意一方为空就停止循环
{
if(cur1->data < cur2->data)
{
if(new_tail == NULL)
{
new_tail = new_head = cur1;
}
else
{
new_tail->next = cur1;
new_tail =new_tail->next;
}
cur1 = cur1->next;
}
else
{
if(new_tail == NULL)
{
new_tail = new_head = cur2;
}
else
{
new_tail->next = cur2;
new_tail =new_tail->next;
}
cur2 = cur2->next;
}
}
//有一方先到尾部另一方追加到新链表尾部
if(cur1 != NULL)
{
new_tail->next = cur1;
}
if(cur2 != NULL)
{
new_tail->next = cur2;
}
return new_head;
}
void TestMerge()
{
TEST_HEADER;
LinkNode* head1;
LinkNode* head2;
LinkNode* head3;
LinkNodeInit(&head1);
LinkNodeInit(&head2);
LinkNodeInit(&head3);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'e');
LinkListPushBack(&head1,'g');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'d');
LinkListPushBack(&head2,'f');
LinkListPushBack(&head2,'h');
head3 = LinkListMerge(head1,head2);
LinkListPrintChar(head3,"将已经有序的链表合并成一个有序的链表");
}
4.查找单链表的中间节点,要求只能遍历一次链表
LinkNode* LinkListFindMidNode(LinkNode* phead)
{
if(phead == NULL)
{
return;
}
LinkNode* fast = phead;//定义两个指针一个快指针一个慢指针
LinkNode* slow = phead;
while((fast != NULL) && (fast->next != NULL))
{
//当快指针走到尾部时慢指针正好走到一半
fast = fast->next->next;//快指针一次走两步
slow = slow->next;//慢指针一次走一步
}
return slow;
}
void TestFindMidNode()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkNode* p = LinkListFindMidNode(head);
LinkListPrintChar(head,"查找链表的中间元素");
printf("mid expect c,actual %c\n",*p);
}
5.查找单链表的倒数第k个节点,要求只能遍历一次链表
LinkNode* LinkListFindLastKNode(LinkNode* phead,int K)
{
if(phead == NULL)
{
return NULL;
}
LinkNode* fast = phead;
LinkNode* slow = phead;
int i = 0;
for(;i<K;++i)
{
fast = fast->next;//快指针先走K步然后一起走,fast走到NULL,slow指向倒数第K个
if(fast == NULL)//如果一共有5个元素,想找倒数第10个那肯定找不到,所以要给fast作判空处理
{
break;
}
}
if(i != K)//没走完,K超过链表长度
{
return NULL;
}
while(fast != NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
void TestFindLastKNode()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkNode* p = LinkListFindLastKNode(head,2);
LinkListPrintChar(head,"查找倒数第二个元素");
printf("mid expect d,actual %c\n",*p);
}
6.删除链表的倒数第k个节点
void LinkListEraseLastKNode(LinkNode** phead,int K)
{
if(phead == NULL)
{
return;
}
if(*phead == NULL)
{
return;
}
int len = LinkListSize(*phead);
if(K > len)
{
return;
}
if(K == len)
{
//要删除的元素为第一个所以用头删的方法
LinkNode* to_erase = *phead;
*phead = (*phead)->next;
DestroyNode(to_erase);
}
LinkNode* pre = *phead;
int i = 0;
for(;i < len-1-K;++i)
{
pre = pre->next;
}
//循环结束pre指向K-1
LinkNode* to_delete = pre->next;
pre->next = to_delete->next;
DestroyNode(to_delete);
return;
}
void TestEraseLastKNode()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkListEraseLastKNode(&head,2);
LinkListPrintChar(head,"删除倒数第二个元素");
}
7.判断链表是否带环?若带环,求环长度?求环的入口?并计算每个算法的时间复杂度和空间复杂度
(1)判断是否带环
没环返回NULL,有环返回快慢指针相遇的地方
LinkNode* LinkListHasCycle(LinkNode* phead)
{
if(phead == NULL)
{
return NULL;
}
LinkNode* fast = phead;
LinkNode* slow = phead;
while((fast != NULL)&&(fast->next != NULL))
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
return slow;
}
}
return NULL;
}
void TestHasCycle()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkNode* pow_e = LinkListFind(head,'e');
pow_e->next = head->next->next;
LinkNode* p = LinkListHasCycle(head);
printf("%c\n",*);
}
时间复杂度:O(n) 空间复杂度:O(1)
以上的这种方法要应用在(fast绝对速度 != slow一次走的步数)的情况下,不然fast和slow不会相遇。(fast绝对速度 = fast一次走的步数 - 环长)
(2)若带环返回环的长度,若不带环长度环的长度为0
size_t LinkListCycleLen(LinkNode* phead)
{
if(phead == NULL)
{
return 0;
}
LinkNode* meet_node = LinkListHasCycle(phead);
if(meet_node == NULL)
{
return 0;
}
LinkNode* cur = meet_node->next;
size_t len = 1;
while(cur != meet_node)
{
cur = cur->next;
++len;
}
return len;
}
void TestCycleLen()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkNode* pow_e = LinkListFind(head,'e');
pow_e->next = head->next->next;
size_t p = LinkListCycleLen(head);
printf("%d\n",p);
}
时间复杂度:O(n)
(3)求环的入口
链表开始到入口点的位置 = 相遇位置到入口点位置
LinkNode* LinkListCycleEntry(LinkNode* phead)
{
if(phead == NULL)
{
return NULL;
}
LinkNode* meet_node = LinkListHasCycle(phead);
if(meet_node == NULL)
{
return;
}
LinkNode* cur1 = phead;
LinkNode* cur2 = meet_node;
while(cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
void TestCycleEntry()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'e');
LinkNode* pow_e = LinkListFind(head,'e');
pow_e->next = head->next->next;
LinkNode* p = LinkListCycleEntry(head);
printf("%c\n",*p);
}
时间复杂度:O(n)
8.判断两个链表是否相交,若相交,求交点(假设链表不带环)
(1)是否相交
因为链表每个节点只有一个next所以相交只有
而没有
所以定义一个cur1,一个cur2,都让他们走到最后看是否相等如果相等则相交
int LinkListHasCross(LinkNode* head1,LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return 0;
}
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
while(cur1 != NULL)
{
cur1 = cur1->next;
}
while(cur2 != NULL)
{
cur2 = cur2->next;
}
return cur1 == cur2 ? 1 : 0;
}
void TestHasCross()
{
TEST_HEADER;
LinkNode* head1;
LinkNodeInit(&head1);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'b');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'d');
LinkListPushBack(&head1,'e');
LinkNode* head2;
LinkNodeInit(&head2);
LinkListPushBack(&head2,'a');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'c');
LinkNode* pos_c = LinkListFind(head2,'c');
pos_c->next = head1->next;
int ret = LinkListHasCross(head1,head2);
printf("ret : expected 1 ,actual %d\n",ret);
}
(2)求交点
分别求两个链表的长度,长的减短的定义为offset,长的先走offset步(两指针已经在同一起跑线),然后一起走,重合即为交点
LinkNode* LinkListCrossPos(LinkNode* head1,LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;
}
size_t len1 = LinkListSize(head1);
size_t len2 = LinkListSize(head2);
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
if(len1 > len2)
{
size_t offset = len1 - len2;
int i = 0;
for(i = 0;i < offset;++i)
{
cur1 = cur1->next;
}
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 == cur2)
{
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
if(len1 < len2)
{
size_t offset = len2 - len1;
int i = 0;
for(i = 0;i < offset;++i)
{
cur2 = cur2->next;
}
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 == cur2)
{
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
return NULL;
}
void TestCrossPos()
{
TEST_HEADER;
LinkNode* head1;
LinkNodeInit(&head1);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'b');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'d');
LinkListPushBack(&head1,'e');
LinkNode* head2;
LinkNodeInit(&head2);
LinkListPushBack(&head2,'a');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'c');
LinkNode* pos_c = LinkListFind(head2,'c');
pos_c->next = head1->next;
LinkNode* pos = LinkListCrossPos(head1,head2);
printf("pos : expected b ,actual %c\n",pos->data);
}
9.判断两个链表是否相交,若相交,求交点(假设链表可能带环)
(1)是否相加
一共分3种情况:(1)都不带环,用上面的方法
(2)一个带环一个不带环一定不相交
(3)两个都带环,又分三种情况:
a)如果两个环的入口相同,则交点在环外
b)两个环的入口点不同,但从一个入口点出发,绕环一周,能到达另一个入口点,该情况下,两个环的入口点就是链表的交点,有两个交点,交点在还 上
c)如果不是上面说的两种则说明不相交
int LinkListHasCrossWithCycle(LinkNode* head1,LinkNode* head2)
{
if(head1 == NULL && head2 == NULL)
{
return 0;
}
//分别求两个链表的环的入口
LinkNode* entry1 = LinkListCycleEntry(head1);
LinkNode* entry2 = LinkListCycleEntry(head2);
//两个链表都不带环,直接使用前面的方式判定相交
if(entry1 == NULL && entry2 == NULL)
{
return LinkListHasCross(head1,head2);
}
//如果一个带环一个不带环,那么直接返回不相交
if((entry1 == NULL && entry2 != NULL)||
(entry2 == NULL && entry1 != NULL))
{
return 0;
}
//如果两个链表都带环
//a)如果这两个入口点重合,说明相交,并且是环外相交
if(entry1 == entry2)
{
return 1;
}
//b)如果从一个入口点出发,绕环一周,能到达第二个入口点
// 说明也是相交,并且是环上相交
LinkNode* cur = entry1->next;
while(cur != entry1)
{
if(cur == entry2)
{
return 1;
}
cur = cur->next;
}
//c)如果不是上面两种情况,就说明不相交
return 0;
}
void TestHasCrossWithCycle()
{
//两个链表都不带环
TEST_HEADER;
LinkNode* head1;
LinkNodeInit(&head1);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'b');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'d');
LinkListPushBack(&head1,'e');
LinkNode* head2;
LinkNodeInit(&head2);
LinkListPushBack(&head2,'a');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'c');
LinkNode* pos_c = LinkListFind(head2,'c');
pos_c->next = head1->next;
int ret1 = LinkListHasCrossWithCycle(head1,head2);
printf("ret1 : expected 1 ,actual %d\n",ret1);
//一个带环一个不带环
LinkNode* head3;
LinkNodeInit(&head3);
LinkListPushBack(&head3,'a');
LinkListPushBack(&head3,'b');
LinkListPushBack(&head3,'c');
LinkListPushBack(&head3,'d');
LinkListPushBack(&head3,'e');
LinkNode* pow_e = LinkListFind(head3,'e');
pow_e->next = head3->next->next;
LinkNode* head4;
LinkNodeInit(&head4);
LinkListPushBack(&head4,'a');
LinkListPushBack(&head4,'b');
LinkListPushBack(&head4,'c');
LinkListPushBack(&head4,'d');
LinkListPushBack(&head4,'e');
int ret2 = LinkListHasCrossWithCycle(head3,head4);
printf("ret2 : expected 0 ,actual %d\n",ret2);
//两个入口点重合,环外相交
LinkNode* head5;
LinkNodeInit(&head5);
LinkListPushBack(&head5,'a');
LinkListPushBack(&head5,'b');
LinkListPushBack(&head5,'c');
LinkListPushBack(&head5,'d');
LinkListPushBack(&head5,'e');
LinkListPushBack(&head5,'f');
LinkListPushBack(&head5,'g');
LinkNode* pos_g = LinkListFind(head5,'g');
pos_g->next = head5->next->next->next;
LinkNode* head6;
LinkNodeInit(&head6);
LinkListPushBack(&head6,'a');
LinkListPushBack(&head6,'b');
LinkNode* pos_b = LinkListFind(head6,'b');
pos_b->next = head5->next->next;
int ret3 = LinkListHasCrossWithCycle(head5,head6);
printf("ret3 : expected 1 ,actual %d\n",ret3);
//环上相交
LinkNode* head7;
LinkNodeInit(&head7);
LinkListPushBack(&head7,'a');
LinkListPushBack(&head7,'b');
LinkListPushBack(&head7,'c');
LinkListPushBack(&head7,'d');
LinkListPushBack(&head7,'e');
LinkListPushBack(&head7,'f');
LinkListPushBack(&head7,'g');
LinkListPushBack(&head7,'h');
LinkNode* pos_h = LinkListFind(head7,'h');
pos_h->next = head7->next->next->next;
LinkNode* head8;
LinkNodeInit(&head8);
LinkListPushBack(&head8,'a');
LinkListPushBack(&head8,'b');
LinkListPushBack(&head8,'c');
LinkListPushBack(&head8,'d');
LinkNode* pos_d = LinkListFind(head8,'c');
pos_d->next = head7->next->next->next;
int ret4 = LinkListHasCrossWithCycle(head7,head8);
printf("ret4 : expected 1 ,actual %d\n",ret4);
}
(2)求交点
a)
b)交点即为环的入口点
LinkNode* LinkListCrossWithCyclePos(LinkNode* head1,LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;
}
//交点在环上则为两个环的入口点
LinkNode* entry1 = LinkListCycleEntry(head1);
LinkNode* entry2 = LinkListCycleEntry(head2);
if(entry1 != entry2)
{
LinkNode* cur = entry1;
for(;cur!=entry2;cur = cur->next);
return entry2;
cur = entry2;
/*for(;cur!=entry1;cur = cur->next);
return entry1;*/
}
//交点在环外
else if(entry1 == entry2)
{
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
size_t len1 = 0;
size_t len2 = 0;
for(cur1 = head1;cur1!=entry1;cur1 = cur1->next )
{
len1++;
}
for(cur2 = head2;cur2!=entry2;cur2 = cur2->next )
{
len2++;
}
if(len1 > len2)
{
size_t offset = len1 - len2;
size_t i = 0;
cur1 = head1;
cur2 = head2;
for(i = 0;i < offset;++i)
{
cur1 = cur1->next;
}
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 == cur2)
{
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
if(len1 < len2)
{
size_t offset = len2 - len1;
size_t i = 0;
cur1 = head1;
cur2 = head2;
for(i = 0;i < offset;++i)
{
cur2 = cur2->next;
}
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 == cur2)
{
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
}
else
{
return NULL;
}
}
void TestCrossWithCyclePos()
{
TEST_HEADER;
//环外相交
LinkNode* head1;
LinkNodeInit(&head1);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'b');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'d');
LinkListPushBack(&head1,'e');
LinkListPushBack(&head1,'f');
LinkListPushBack(&head1,'g');
LinkNode* pos_g = LinkListFind(head1,'g');
pos_g->next = head1->next->next->next;
LinkNode* head2;
LinkNodeInit(&head2);
LinkListPushBack(&head2,'a');
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'c');
LinkNode* pos_c = LinkListFind(head2,'c');
pos_c->next = head1->next;
LinkNode* pos1 = LinkListCrossWithCyclePos(head1,head2);
printf("pos : expected b,actual %c\n",pos1->data);
//环上相交
LinkNode* head3;
LinkNodeInit(&head3);
LinkListPushBack(&head3,'a');
LinkListPushBack(&head3,'b');
LinkListPushBack(&head3,'c');
LinkListPushBack(&head3,'d');
LinkListPushBack(&head3,'e');
LinkListPushBack(&head3,'f');
LinkListPushBack(&head3,'g');
LinkListPushBack(&head3,'h');
LinkNode* pos_h = LinkListFind(head3,'h');
pos_h->next = head3->next->next->next;
LinkNode* head4;
LinkNodeInit(&head4);
LinkListPushBack(&head4,'a');
LinkListPushBack(&head4,'b');
LinkListPushBack(&head4,'c');
LinkListPushBack(&head4,'d');
LinkNode* pos_d = LinkListFind(head4,'d');
pos_d->next = head3->next->next->next->next;
LinkNode* pos2 = LinkListCrossWithCyclePos(head3,head4);
printf("pos : expected e,actual %c\n",pos2->data);
}
10.求两个已排序单链表中相同的数据
先比较cur1和cur2,若cur1 < cur2 那么cur1中的元素肯定不是交集,同理,若cur2 < cur1 那么cur2中的元素肯定不是交集
相等把元素放到new_head
LinkNode* LinkListUnionSet(LinkNode* head1,LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;
}
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
LinkNode* new_head = NULL;
LinkNode* new_tail = NULL;
while((cur1 != NULL) &&( cur2 != NULL))
{
if(cur1->data < cur2->data)
{
cur1 = cur1->next;
}
else if(cur2->data < cur1->data)
{
cur2 = cur2->next;
}
//两个相等
else
{
if(new_head == NULL)
{
new_head = new_tail = CreatNode(cur1->data);
}
else
{
new_tail->next = CreatNode(cur1->data);
new_tail = new_tail->next;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
return new_head;
}
void TestUnionSet()
{
TEST_HEADER;
LinkNode* head1;
LinkNodeInit(&head1);
LinkListPushBack(&head1,'a');
LinkListPushBack(&head1,'b');
LinkListPushBack(&head1,'c');
LinkListPushBack(&head1,'d');
LinkListPushBack(&head1,'e');
LinkNode* head2;
LinkNodeInit(&head2);
LinkListPushBack(&head2,'b');
LinkListPushBack(&head2,'c');
LinkNode* head = LinkListUnionSet(head1,head2);
LinkListPrintChar(head,"两个已排序单链表中的相同元素");
}
11.复杂链表的复制。
一个链表的每一个节点,有一个指向next指针,指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或NULL
(1)
typedef struct ComplexNode
{
LinkNodeType data;
struct ComplexNode* next;
struct ComplexNode* random;
}ComplexNode;
ComplexNode* CreateComplexNode(LinkNodeType value)
{
ComplexNode* new_node = (ComplexNode*)malloc(sizeof(ComplexNode));
new_node->data = value;
new_node->next = NULL;
new_node->random = NULL;
return new_node;
}
size_t Diff(ComplexNode* src,ComplexNode* dest)
{
size_t offset = 0;
while(src != NULL)
{
if(src == dest)
{
break;
}
++offset;
src = src->next;
}
if(src == NULL)
{
return (size_t)-1;
}
return offset;
}
ComplexNode* Step(ComplexNode* head,size_t offset)
{
ComplexNode* cur = head;
size_t i = 0;
while(1)
{
if(cur == NULL)
{
return NULL;
}
if(i >= offset)
{
return cur;
}
++i;
cur = cur->next;
}
return NULL;
}
ComplexNode* CopyComplexList(ComplexNode* head)
{
//先按照简单链表进行复制
ComplexNode* new_head = NULL;
ComplexNode* new_tail = NULL;
ComplexNode* cur = head;
for(;cur != NULL;cur = cur->next)
{
ComplexNode* new_node = CreateComplexNode(cur->data);
if(new_head == NULL)
{
new_head = new_tail = new_node;
}
else
{
new_tail->next = new_node;
new_tail = new_tail->next;
}
}
//遍历旧链表,找到每个链表节点random指针相对于链表头部的偏移量
//遍历新链表,根据偏移量,设置新链表的random
ComplexNode* new_cur = new_head;
for(cur = head;cur != NULL;cur = cur->next,new_cur = new_cur->next)
{
if(cur->random == NULL)
{
new_cur->random = NULL;
continue;
}
//通过Diff函数,计算出链表的两个节点的偏移量
size_t offset = Diff(head,cur->random) ;
//通过Step函数,相当于求出从new_head出发,走了offset步,到达的位置是谁
new_cur->random = Step(new_head,offset);
}
return new_head;
}
void PrintComplexList(ComplexNode* head,const char* msg)
{
printf("[%s]\n",msg);
ComplexNode* cur = head;
for(;cur != NULL;cur = cur->next)
{
printf("[%c] ",cur->data);
}
printf("\n");
for(cur = head ;cur != NULL;cur =cur->next)
{
if(cur->random == NULL)
{
printf("[NULL] ");
continue;
}
printf("[%c] ",cur->random->data);
}
printf("\n");
}
void TestCopyComplexList()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
ComplexNode* a = CreateComplexNode('a');
ComplexNode* b = CreateComplexNode('b');
ComplexNode* c = CreateComplexNode('c');
ComplexNode* d = CreateComplexNode('d');
ComplexNode* e = CreateComplexNode('e');
a->next = b;
b->next = c;
c->next = d;
d->next = e;
e->next =NULL;
a->random = c;
b->random = a;
c->random = NULL;
d->random = d;
e->random = c;
ComplexNode* new_head = CopyComplexList(a);
PrintComplexList(new_head,"拷贝复杂链表");
}
(2)
ComplexNode* CopyComplexList2(ComplexNode* head)
{
//遍历链表,给每个节点后插入新的节点
ComplexNode* cur = head;
for(;cur != NULL;cur = cur->next->next)
{
ComplexNode* new_node = CreateComplexNode(cur->data);
new_node->next = cur->next;
cur->next = new_node;
}
//维护新结点的random指针
for(cur = head;cur != NULL;cur = cur->next->next)
{
ComplexNode* new_cur = cur->next;
if(cur->random == NULL)
{
new_cur->random == NULL;
continue;
}
new_cur->random = cur->random->next;
}
//将新结点拆除
ComplexNode* new_head = NULL;
ComplexNode* new_tail = NULL;
for(cur = head;cur != NULL;cur = cur->next)
{
ComplexNode* new_cur = cur->next;
cur->next = new_cur->next;
if(new_head == NULL)
{
new_head = new_tail = new_cur;
}
else
{
new_tail->next = new_cur;
new_tail = new_tail->next;
}
}
return new_head;
}
void TestCopyComplexList2()
{
TEST_HEADER;
LinkNode* head;
LinkNodeInit(&head);
ComplexNode* a = CreateComplexNode('a');
ComplexNode* b = CreateComplexNode('b');
ComplexNode* c = CreateComplexNode('c');
ComplexNode* d = CreateComplexNode('d');
ComplexNode* e = CreateComplexNode('e');
a->next = b;
b->next = c;
c->next = d;
d->next = e;
e->next =NULL;
a->random = c;
b->random = a;
c->random = NULL;
d->random = d;
e->random = c;
ComplexNode* new_head = CopyComplexList2(a);
PrintComplexList(new_head,"拷贝复杂链表");
}