数据结构 单链表相关习题3

1.判定两个链表是否相交, 并求出交点

解题思路:

    两链表若相交,则其最后一个节点必定相同。所以遍历得出两链表的尾节点可得知两链表是否相交。

    若两链表相交,则求出两链表长度,相减得其差值len。

    较长链表先向后遍历len次,随后两链表同时向后遍历。直到出现两值相同时,该节点即为相交点。

//判定两个链表是否相交, 并求出交点 
LinkNode* HasCross(LinkNode* head1, LinkNode* head2)
{
    if(head1 == NULL || head2 == NULL)
    {   
        return NULL;
    }   
    int len1 = 0,len2 = 0,len = 0;
    LinkNode* cur1 = head1;
    LinkNode* cur2 = head2;
    while(cur1)
    {   
        len1++;
        cur1 = cur1->next;
    }   
    while(cur2)
    {   
        len2++;
        cur2 = cur2->next;
    }   
    if(len1 > len2)
    {   
        len = len1 - len2;
        while(len--)
        {   
            cur1 = cur1->next;
        }   
    }   
    else
    {   
        len = len2-len1;
        while(len--)
        {   
            head2 = head2->next;
        }   
    }   
    while(head1 != head2)
    {   
        head1 = head1->next;
        head2 = head2->next;
    }   
    return head1;
}
//测试函数
void TestHasCross()
{
	TITLE;
	LinkNode* head,*head2;
	LinkListInit(&head);
	LinkListInit(&head2);
	LinkListPushBack(&head,'a');
	LinkListPushBack(&head,'b');
	LinkListPushBack(&head,'c');
	LinkListPushBack(&head,'d');
	LinkListPushBack(&head,'e');

	LinkListPushBack(&head2,'h');
	LinkListPushBack(&head2,'i');
	LinkListPushBack(&head2,'j');
	LinkListPushBack(&head2,'k');

	LinkNode* pos1 = LinkListFind(head,'d');
	LinkNode* pos2 = LinkListFind(head2,'k');
	pos2->next = pos1;
	LinkListPrint(head,"单链表head1");
	LinkListPrint(head2,"单链表head2");
	LinkNode* ret = HasCross(head,head2);
	printf("两元素相交于d\n");
	printf("expect is d,actul is %c\n",ret->data);
}

运行结果:


2.判定两个链表是否相交. 但是链表可能带环 

可分为三种情况:

1.两个不带环链表,上一题已经解决

2.一个带环,一个不带环

    不可能相交

3.两个带环链表,可分为以下两种情况


两带环链表是否相交判断方法:

    我们可以先分别求出两环快慢指针的相遇点meet(快指针一次走2步,慢指针一次走1步)。

    随后用其中一个meet点绕环一周,若能遇到另一个meet点则两链表相交。

    反之,两链表不相交。

   
int HasCrossWithCycle(LinkNode* head1, LinkNode* head2)
{
	if(head1 == NULL || head2 == NULL)	
	{
		return 0;	
	}
	int ret1 = HasCycle(head1);
	int ret2 = HasCycle(head2);
	if(ret1 == 0 && ret2 == 0)
	{
		//表示两链表都不带环	
		LinkNode* ret = HasCross(head1,head2);
		if(ret != NULL)
			//两链表相交
			return 1;
		else
			//两链表不相交
			return 0;
	}
	else if(ret1 == 1 && ret2 == 1)
	{
		LinkNode* MeetNode1 = GetMeetNode(head1); 
		LinkNode* cur = MeetNode1;
		LinkNode* MeetNode2 = GetMeetNode(head2);
		while(cur->next != MeetNode1)
		{
			if(cur == MeetNode2)
			{
				//表示两环相交
				return 1;
			}
			cur = cur->next;
		}
		return 0;
	}
	else
	{
		//表示一个链表带环,一个链表不带环
		//此时,两链表不可能相交
		return 0;
	}
}

运行结果:


3. 求两个有序链表的交集 

解题思路:

    从头节点开始,比较当前两节点大小。

    若相等,将该节的值点插入新链表,两链表同时向后走一步。

    若不相等,将较小值的链表向后走一步。(因为是有序链表,所以node1小于node2的话,node1一定小于node2后面的节点,不可能出现相等的情况。)

//求两个有序链表的交集,返回表示交集的新链表
//小的值往后移,相等都往后移
LinkNode* UnionSet(LinkNode* head1, LinkNode* head2)
{
    LinkNode* newHead;
    LinkListInit(&newHead);
    while(head1 && head2)
    {    
        if(head1->data < head2->data)
            head1 = head1->next;     
        else if(head1->data > head2->data)
            head2 = head2->next;
        else 
        {    
            //两值相等,加入新链表
            LinkListPushBack(&newHead,head1->data);
            head1 = head1->next;
            head2 = head2->next;
        }    
    }    
    return newHead;
}
//测试函数
void TestUnionSet()
{
	TITLE;
	LinkNode* head,*head2,*ret;
	LinkListInit(&head);
	LinkListInit(&head2);
	LinkListPushBack(&head,'a');
	LinkListPushBack(&head,'b');
	LinkListPushBack(&head,'c');
	LinkListPushBack(&head,'d');
	LinkListPushBack(&head,'e');

	LinkListPushBack(&head2,'b');
	LinkListPushBack(&head2,'d');
	LinkListPushBack(&head2,'r');
	LinkListPushBack(&head2,'z');
	LinkListPrint(head,"单链表head1");
	LinkListPrint(head2,"单链表head2");

	ret = UnionSet(head,head2);
	LinkListPrint(ret,"两链表交集为");
	
}

运行结果:

4.拷贝复杂链表


//拷贝复杂链表
typedef struct ComplexNode
{
	DataType data;
	struct ComplexNode* next;
	struct ComplexNode* random;
}ComplexNode;


ComplexNode* CreateComplexNode(DataType data)
{
	ComplexNode* newNode = (ComplexNode*)malloc(sizeof(ComplexNode));
	if(newNode == NULL)
	{
		printf("申请失败\n");
		return NULL;
	}
	newNode->data = data;
	newNode->next = NULL;
	newNode->random = NULL;
	return newNode;
}
//打印复杂链表
void ComplexNodePrint(ComplexNode* head,char* msg)
{
	printf("[%s]\n",msg);
	ComplexNode* cur = head;
	while(cur)
	{
		printf("%c ",cur->data);
		cur = cur->next;
	}
	printf("\n[random]\n");
	cur = head;
	while(cur)
	{
		if(cur->random == NULL)
		{
			printf("[%c->NULL] ",cur->data);
			cur = cur->next;
			continue;
		}
		printf("[%c->%c] ",cur->data,cur->random->data);
		cur = cur->next;
	}
	printf("\n");
}
//拷贝复杂链表
ComplexNode* CopyComplex(ComplexNode* head)
{
	if(head == NULL)
	{
		return;
	}
	ComplexNode* cur = head;
	//此循环,是将原链表后每个节点插入新节点
	while(cur)
	{
		ComplexNode* newNode = CreateComplexNode(cur->data);
		newNode->next = cur->next;
		cur->next = newNode;
		cur = newNode->next;
	}
	cur = head;
	ComplexNode* newNode = NULL;
	//此循环,是给新插入的节点的随机指针域赋值
	while(cur)
	{
		newNode = cur->next;
		if(cur->random)
		{
			newNode->random = cur->random->next;
		}
		cur = newNode->next;
	}
	cur = head;
	ComplexNode* newHead = cur->next;
	ComplexNode* x = head;
	//此循环,是将插入的节点从原链表拆分下来,形成新链表完成拷贝
	while(cur->next)
	{
		cur = cur->next;
		x->next = cur->next;
		x = cur;
	}
	return newHead;
}
测试函数:
void TestComplexNode()
{
	TITLE;
	ComplexNode* head;
	ComplexNode* a = CreateNode('a');
	ComplexNode* b = CreateNode('b');
	ComplexNode* c = CreateNode('c');
	ComplexNode* d = CreateNode('d');
	head = a;
	a->next = b;
	b->next = c;
	c->next = d;
	d->next = NULL;

	a->random = c;
	b->random = d;
	c->random = a;
	d->random = NULL;
	ComplexNodePrint(head,"原链表");

	ComplexNode* newNode = CopyComplex(head);
	ComplexNodePrint(head,"拷贝后链表");
}

运行结果:



猜你喜欢

转载自blog.csdn.net/ihaha233/article/details/80410383