链表和顺序表的面试题(中级版)

下面的题中要用到的函数以及数据类型:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int DataType;
typedef struct SLinkList
{
	DataType data;
	struct SLinkList*PNext;
}SNode;
// 初始化 
void SLinkList_InIt(SNode **Phead)
{
	assert(Phead != NULL);
	*Phead = NULL;
}

1.合并两个有序链表,合并后依然有序

思路:

  • 两个指针分别指向两个有序链表
  • 比较两个指针指向的节点的数字的大小,将较小的拿出来放到新的链表中,
  • 更新拿出来数据的那个指针,另外一个不动
  • 将剩下的节点链接到新的链表后面
/*
1. 两个指针分别指向两个有序链表

2.比较两个指针指向的节点的数字的大小,将较小的拿出来放到新的链表中,

3.更新拿出来数据的那个指针,另外一个不动

4.当其中一个链表指向NULL时,停止循环判断是否有剩下的链表,如果有将剩下的节点链接到新的链表后面

5.返回新的链表
*/
//创建一个新结点
static SNode* BuySListNode(DataType data)
{
	SNode *pNewNode = (SNode*)malloc(sizeof(SNode));
	if (pNewNode == NULL)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->PNext = NULL;
	return pNewNode;
}
void PushBack(SNode **Phead, DataType data)//后插
{
	assert(Phead != NULL);
	if (*Phead == NULL)
	{
		*Phead = BuySListNode(data);
		return;
	}
	else
	{
		SNode*ptmp = *Phead;
		while (ptmp->PNext)
		{
			ptmp = ptmp->PNext;
		}
		ptmp->PNext = BuySListNode(data);
	}

}
SNode*MergeSList(SNode*Pfirst1, SNode* Pfirst2)//合并函数
{
	SNode*PL1 = Pfirst1;
	SNode*PL2 = Pfirst2;
	SNode*PNewNode = NULL;
	SNode*RetNode = NULL;
	SNode*Pnode = NULL;
	while (PL1 != NULL&&PL2 != NULL)//比较两个链表中的数据,如果任何一个链表指向NULL结束循环
	{
		if (PL1->data < PL2->data)
		{
			PushBack(&PNewNode, PL1->data);
			PL1 = PL1->PNext;
		}
		else
		{
			PushBack(&PNewNode, PL2->data);
			PL2 = PL2->PNext;
		}
	}
	if (PL1 == NULL)//判断链表是否有剩余
	{
		RetNode = PL2;
	}
	else
	{
		RetNode = PL1;
	}
	for (Pnode = RetNode; Pnode != NULL; Pnode = Pnode->PNext)//将剩余的链表中的数据尾插到新的链表中
	{
		PushBack(&PNewNode, Pnode->data);
	}
	return PNewNode;
}

原理图:


2.查找单链表的中间节点,要求只能遍历一次链表

思路:

  • 快慢指针,快指针一次向后走两步,慢指针一次走一步,慢指针最后所停的位置就是中间节点的位置
  • 当快指针指向空或者PFast->PNext == NULL或者PFast->PNext->PNext == NULL,它们三个条件任意一个成立的时候退出循环
//查找链表的中间节点,要求只能遍历一次链表(快慢指针的思想)
SNode* FindMiddleNode(SNode*Phead)
{
	assert(Phead != NULL);
	if (Phead == NULL)
	{
		return NULL;
	}
	SNode*PFast = Phead;
	SNode*PSlow = Phead;
	while (PFast != NULL&&PFast->PNext != NULL&&PFast->PNext->PNext != NULL)
	{
		PFast = PFast->PNext->PNext;
		PSlow = PSlow->PNext;
	}
	return PSlow;
} 

原理图:


3.查找单链表的倒数第K个节点,要求只能遍历一次链表

这个题与上一题有异曲同工之妙,都是快慢指针的思想。

思路:

  • 快慢指针的思想
  • 先让快指针往前走k-1步
  • 再同时让快指针和慢指针往后走
  • 当快指针指向NULL的时候这时候慢指针指向的节点就是要找的倒数第K个节点 
SNode* FindLastKNode(SNode*Phead, int k)
{
	assert(Phead != NULL);
	if (Phead == NULL || k <= 0)
	{
		return NULL;
	}
	SNode*PFast = Phead;
	SNode*PSlow = Phead;
	int i = 0;
	for (i = 0; i < k - 1; i++)//这里PFsat先往前走k-1步
	{
		PFast = PFast->PNext;
	}
	while (PFast->PNext != NULL)
	{
		PFast = PFast->PNext;
		PSlow = PSlow->PNext;
	}
	return PSlow;
} 

原理图:


4.求两个已排序链表中相同的数据。

思路:

  • 两个指针分别指向两个有序链表
  • 比较两个指针指向的节点的数字的大小,哪个小就让哪个往前走一步,
  • 如果相等的话将数值尾插到新的链表中,然后两个指针同时往后走一步
  • 当两个链表任意一个指向NULL时,停止循环
  • 返回新的链表
static SNode* BuySListNode(DataType data)
{
	SNode *pNewNode = (SNode*)malloc(sizeof(SNode));
	if (pNewNode == NULL)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->PNext = NULL;
	return pNewNode;
}
void PushBack(SNode **Phead, DataType data)//后插
{
	assert(Phead != NULL);
	if (*Phead == NULL)
	{
		*Phead = BuySListNode(data);
		return;
	}
	else
	{
		SNode*ptmp = *Phead;
		while (ptmp->PNext)
		{
			ptmp = ptmp->PNext;
		}
		ptmp->PNext = BuySListNode(data);
	}

}
SNode* UnionSet(SNode*Phead1, SNode*Phead2)
{
	if (Phead1 == NULL || Phead2 == NULL)
	{
		return NULL;
	}
	SNode*PL1 = Phead1;
	SNode*PL2 = Phead2;
	SNode*PNewNode = NULL;
	SNode*Pnode = NULL;
	while ((PL1 != NULL) && (PL2 != NULL))
	{
		if (PL1->data < PL2->data)
		{
			PL1 = PL1->PNext;
		}
		else if (PL1->data>PL2->data)
		{
			PL2 = PL2->PNext;
		}
		else
		{
			PushBack(&PNewNode, PL1->data);
			PL1 = PL1->PNext;
			PL2 = PL2->PNext;

		}
	}
	return PNewNode;
}

原理图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值