链表的简单面试题

1.从尾到头打印单链表

  • 思路一:定义两个指针,PNode和pend,pNode指向第一个结点,pend指向NULL

                   每次从头开始遍历直到pNode->pNext=pend,打印出pNode,再将pNode赋给pend

                    pFirst赋给pNode,保证每次都是从头开始遍历

代码如下:

void PrintReverse(SlistNode *pFirst)
{
	SlistNode *pNode = pFirst;
	SlistNode *pend = NULL;
	while (pend != pFirst)//外循坏是让pend每次减小一个
	{
		while (pNode->pNext != pend)//内循坏是pNode遍历
		{
			pNode = pNode->pNext;
		}
		printf("%d-> ", pNode->data);
		pend = pNode;
		pNode = pFirst;
	}

}
  • 思路二:递归

代码如下:

void show(SlistNode *p)
{
	if (p->pNext){
		show(p->pNext);
	}
	printf("<-%d", p->data);
}

2.逆置/反转单链表

思路:

  • 头删->头插
  • 尾删->尾插

以头删头插为例,代码如下:

void ReverseSlist(sListNode *pFirst)
{
	//assert(pFirst);
	DataType data;
	sListNode *pNewNode = NULL;
	while (pFirst)
	{
		data = pFirst->data;
		PopFront(&pFirst);
		PushFront(&pNewNode, data);

	}
	return pNewNode;
}

PushFront和PopFront函数参见单链表的博客

3.在无头单链表的一个节点前插入一个节点(不能遍历单链表)

思路:因为不知道pPos的前一个结点,所以需将新结点pNewNode插入到pPos的后面

         然后将pPos的数据搬移到新建的结点pNewNode的数据

        最后将新数据放到pPos的数据区,pPos的指针指向新节点

总结:pPos放的是要插入的数据,pNewNode放的是pPos的原始数据

代码如下:

void InsertNode(sListNode *pPos,DataType data)
{
	sListNode *pNewNode = (sListNode*)malloc(sizeof(sListNode));
	assert(pNewNode);
	pNewNode->data = pPos->data;
	pNewNode->pNext = pPos->pNext;
	pPos->data = data;
	pPos->pNext = pNewNode;

}

4.删除一个无头单链表的非尾结点(不能遍历单链表)

思路:交换pos和pos->pNextNode的数据(相当于交换了两个结点的位置),使问题转换为删除pos指向的结点的下一个结点

代码如下:

void PopNode(sListNode *pPos)
{
	assert(pPos);
	sListNode *NextNode = pPos->pNext;
	pPos->data = NextNode->data;
	pPos->pNext = NextNode->pNext;
	free(NextNode);
}

5.单链表排序(冒泡排序)

思路:外层循坏控制循坏次数

         内层循坏两两节点比较,每次比较的都是尾节点前面的数   

代码如下:

void SortSqlist(sListNode *pFirst)
{
	assert(pFirst);
    sListNode *pEnd = NULL;
	int flag = 0;
	//外层循坏
	while (pEnd!=pFirst)
	
	{
		sListNode *PreNode = pFirst;
		//内层循坏,两两进行比较,每次参与比较的都是尾结点前面的结点
		while (PreNode->pNext!=pEnd)
		{
			sListNode *CurNode = PreNode->pNext;
			if (PreNode->data > CurNode->data)
			{
				DataType tmp = PreNode->data;
				PreNode->data = CurNode->data;
				CurNode->data = tmp;
				flag = 1;
			}
			PreNode = PreNode->pNext;
		}
		if (flag == 0)
		{
			break;
		}
		pEnd = PreNode;
	}
	
}

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

思路:用快慢指针的方法,快指针走两步,慢指针走一步,当快指针走完时,慢指针的位置就是中间节点

           注意:应该对快指针每走一步就进行判断是否等于NULL

代码如下:

int FindMidNode(sListNode *pFirst)
{
	assert(pFirst);
	sListNode *pFast = pFirst;
	sListNode *pSlow = pFirst;
	//while (pFast->pNext != NULL)
	//{
	//	pFast = pFast->pNext->pNext;//没有考率pFast->pNext=NULL的情况
	//	pSlow = pSlow->pNext;
	//}
	while (1)
	{
		pFast = pFast->pNext;
		if (pFast == NULL)
		{
			break;
		}
		pFast = pFast->pNext;
		if (pFast == NULL)
		{
			break;
		}
		pSlow = pSlow->pNext;
	}
	return pSlow;
}

测试代码:

sListNode *pFound = FindMidNode(pFirst);
printf("%d\n", pFound->data);

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

思路:同样是快慢指针的方法,让快慢指针相差k步,即先让快指针走k-1步,再让快慢指针同时走,快指针走完,慢指针走到的位置就是倒数第k个节点

int  FindK(sListNode *pFirst, int k)
{
	assert(pFirst);
	sListNode *pFast = pFirst;
	sListNode *pSlow = pFirst;
	while (--k)//不能是k--,快指针先走k-1步
	{
		if (pFast == NULL)
		{
			break;
		}
		pFast = pFast->pNext;
	}
	while (pFast->pNext)
	{
		pFast = pFast->pNext;
		pSlow = pSlow->pNext;
	}
	return pSlow;
}

8.删除链表中的倒数第k个节点

代码如下:

void PopK(sListNode **ppFirst, int k)
{
	assert(ppFirst);
        assert(*ppFirst);
	sListNode *pFound = FindK(*ppFirst, k);
	sListNode *pNode = *ppFirst;
	if (pFound == *ppFirst)
	{
		sListNode *pOldFirst = *ppFirst;
		*ppFirst = (*ppFirst)->pNext;
		free(pOldFirst);
		return;//不加return会出错
		
	}
	while (pNode->pNext != pFound)
	{
		pNode = pNode->pNext;
	}
	pNode->pNext = pFound->pNext;
	free(pFound);
	//PopAddress(ppFirst, pFound);
}

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

思路:定义两个指针分别指向链表1和链表2,指针小的往后走

  注意:不要忘了考虑当一个链表为空的情况

代码如下:

DataType UnitSlist(sListNode *s1, sListNode *s2)
{
	assert(s1);
	assert(s2);
	sListNode *p1=s1;
	sListNode *p2=s2;
	sListNode *pNewNode = NULL;
	while (p1 != NULL&&p2 != NULL)
	{
		if (p1->data < p2->data)
		{
			pushBack(&pNewNode, p1->data);
			p1 = p1->pNext;
		}
		else
		{
			pushBack(&pNewNode, p2->data);
			p2 = p2->pNext;
		}
		
	}
	//有一个链表为空的情况下
	sListNode *pNotEmpty = p1;
	if (p1 == NULL)
	{
		pNotEmpty = p2;
	}
	//如果有一个链表为空,将不空的链表的剩余数据插入新链表
	while (pNotEmpty != NULL)
	{
		pushBack(&pNewNode, pNotEmpty->data);
		pNotEmpty = pNotEmpty->pNext;
	}
	return pNewNode;
}

测试代码:

sListNode *pNewList = UnitSlist(s1, s2);
print(pNewList);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值