链表常见笔试题

单链表的简单操作已经在前面的几篇文章里有写,在这里就不再赘述,下面就是一些常见的笔试面试题

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,"拷贝复杂链表");
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值