有关链表的面试题(再续)

今天让我们来做一些复杂一些的链表面试题。

1.复杂链表的复刻。

typedef struct CN{             //复杂链表的结构体。
	int data;                  //每个节点的数据。
	struct CN *pNext;          //指向下一个节点。
	struct CN *pRandom;        //指向随机节点或NULL。
}  CN;

CN *Copy(CN *pFirst)
{
	CN *pNode=pFirst;
	CN *pNewNode;
	CN *pOldRandom;
	CN *pNewRandom;
	CN *pNewFirst=pFirst->pNext;
	//1.复制节点放到老节点后边。
	for(pNode=pFirst;pNode!=NULL;pNode=pNode->pNext->pNext)
	{
		pNewNode=(CN *)malloc(sizeof(CN));   //开辟一个空间。
		pNewNode->data=pNode->data;          //拷贝节点的值。
		pNewNode->pRandom=NULL;
		pNewNode->pNext=pNode->pNext;
		pNode->pNext=pNewNode;               //把新节点放在老节点后面。
	}

	//2.复制pRandom。
	for(pNode=pFirst;pNode!=NULL;pNode=pNode->pNext->pNext)
	{
		pNewNode=pNode->pNext;             
		pOldRandom=pNode->pRandom;

		if(pOldRandom!=NULL)
		{
			pNewRandom=pOldRandom->pNext;
			pNewNode->pRandom=pNewRandom;
		}
	}

	//3.拆链表。
	for(pNode=pFirst;pNode!=NULL;pNode=pNode->pNext)
	{
		pNewNode=pNode->pNext;
		pNode->pNext=pNewNode->pNext;
		if(pNode->pNext!=NULL)
		{
			pNewNode->pNext=pNode->pNext->pNext;
		}
		else{
			pNewNode->pNext=NULL;
		}
	}
	return pNewFirst;
}

CN *Buy(int data)                      //建立复杂链表。
{
	CN *pNode=(CN *)malloc(sizeof(CN));
	pNode->data=data;
	pNode->pNext=NULL;
	pNode->pRandom=NULL;
	return pNode;
}

void Print(CN *pFirst)        //打印各个节点的数据。
{
	CN *pNode;
	for(pNode=pFirst;pNode!=NULL;pNode=pNode->pNext)
	{
		printf("[%d, (%p, %d)] ",
			pNode->data,
			pNode->pRandom,
			pNode->pRandom ? pNode->pRandom->data : 0);
	}
	printf("\n");
}

void test()       //测试程序。
{
	CN	*p1 = Buy(1);
	CN	*p2 = Buy(2);
	CN	*p3 = Buy(3);
	CN	*p4 = Buy(4);

	p1->pNext = p2;
	p2->pNext = p3;
	p3->pNext = p4;

	p1->pRandom = p4;
	p4->pRandom = p1;
	p2->pRandom = p2;

	Print(p1);

	CN	*pNew = Copy(p1);

	Print(pNew);
}

2.//判断两个链表是否相交,若相交,求交点。


SListNode *Jiao(SListNode *a1,SListNode *a2)
{
	SListNode *n1=a1;           //先定义两个指针指向两个链表头。
	SListNode *n2=a2;
	int z=0;                    //计数。
	int x=0;
	while(n1->pNext!=NULL)        //求两个链表的尾结点并记下总节点个数。
	{
		n1=n1->pNext;
		z+=1;
	}
	while(n2->pNext!=NULL)
	{
		n2=n2->pNext;
		x+=1;
	}
	if(n1!=n2)             //如果两个尾结点不同,证明两个链表不相交。
	{
		printf("Not\n");
		return;
	}
	else{
		printf("Yes\n");
		if(x==z)          //否则当两个链表一样长时。
		{ 
			n1=a1;        //先让指针回到头指针。
			while(n1->pNext!=NULL)
			{
				if(n1==n2)            //循环指针求两个相等时的指针输出即可得到解。
				{
					return n1;
				}
				n1=n1->pNext;
			}
		}
		else if(x<z)              //如果第一个大,就先让它移到与第二个一样的位置,在进行如上的操作。
		{
			z=z-x;
			n1=a1;
			while(z)
			{
				n1=n1->pNext;
			}
			while(n1->pNext!=NULL)
			{
				if(n1==n2)
				{
					return n1;
				}
				n1=n1->pNext;
			}
		}
		else if(x>z)               //当第二个大时如上操作即可。
		{
			x=x-z;
			n2=a2;
			while(x)
			{
				n2=n2->pNext;
			}
			while(n2->pNext!=NULL)
			{
				if(n2==n1)
				{
					return n2;
				}
				n2=n2->pNext;
			}
		}
	}
}
这两个题挺复杂的,需要好好琢磨才能掌握。



猜你喜欢

转载自blog.csdn.net/ymk1507050118/article/details/80896747