链表面试题(二)

5 【逆置/反转单链表】 6【 单链表排序(冒泡排序)】,7 【合并两个有序链表,合并后依然有序】,8【求两个已排序单链表中相同的数据】
创建链表或是打印链表在上一篇,戳链接 点击打开链接
5【逆置/反转单链表】,创建一个新结点作为逆置链表的尾,从链表第一个结点开始,复制该结点并头插到逆置链表上,一直复制到原链表的最后一个结点,最后返回逆置好的链表
SListNode* SListReverse(SListNode* list)
{
	if (list == NULL || list->_next == NULL)
	{
		return list;
	}
	SListNode* ReverseList = NULL;
	SListNode* pCurrent = list;
	while (pCurrent != NULL)
	{
		SListNode* pTemp = pCurrent;
		pCurrent = pCurrent->_next;
		pTemp->_next = ReverseList;
		ReverseList = pTemp;
	}
	return ReverseList;
}
6【单链表排序(冒泡排序)】,弄三个结点,分别在链表的尾(尾巴结点),链表的前两个,前两个从前往后依次比较,筛选出最大的,一轮下来,最大的就在尾,把尾巴结点往前放一个即就是刚比较完的前面结点的位置,把两个比较结点再从头开始向后比较,筛选最大的,直到尾巴结点到链表头处,那么排序就完成了(升序)
void SListBubbleSort(SListNode* list)
{
	assert(list);
	SListNode* pTail = list;
	SListNode* pcur = list->_next;
	SListNode* pnext = pcur->_next;
	while (pTail->_next != NULL)
	{
		pTail = pTail->_next;
	}
	while (list->_next != pTail)
	{
		pcur = list->_next;
		pnext = pcur->_next;
		while (pnext->_next != NULL)
		{
			if (pcur->_data > pnext->_data)
			{
				int tmp = pcur->_data;
				pcur->_data = pnext->_data;
				pnext->_data = tmp;

				pcur = pnext;
				pnext = pnext->_next;
			}
			else
			{
				pcur = pnext;
				pnext = pnext->_next;
			}
		}
		pTail = pcur;
	}
}
7【合并两个有序链表】,合并后依然有序,假设两个链表都是升序的,先比较俩链表的头结点谁比较小,较小的内个结点就做新链表的头,然后俩链表一个结点一个结点的比较,直到一个比完了,把剩下内个接到新链表上就可以了
SListNode* SListMerge(SListNode* list1, SListNode* list2)
{
	if (list1 == NULL)
		return list2;
	if (list2 == NULL)
		return list1;
	SListNode* NewList = NULL;
	if (list1->_data < list2->_data)
	{
		NewList = list1;
		NewList->_next = NULL;
		list1 = list1->_next;
	}
	else
	{
		NewList = list2;
		NewList->_next = NULL;
		list2 = list2->_next;
	}
	SListNode* pTmp = NewList;
	while (list1 != NULL&&list2 != NULL)
	{
		if (list1->_data < list2->_data)
		{
			pTmp->_next = list1;
			list1 = list1->_next;
			pTmp = pTmp->_next;
			pTmp->_next = NULL;
		}
		else
		{
			pTmp->_next = list2;
			list2 = list2->_next;
			pTmp = pTmp->_next;
			pTmp->_next = NULL;
		}
	}
	if (list1 != NULL)
		pTmp->_next = list1;
	else
		pTmp->_next = list2;
	return NewList;
}

8【求两个已排序单链表中相同的数据】,从俩链表的头开始比较,谁小谁就往前走一个(->next),相等的话就打印出来然后都往前走一个,一直到有一个链表走完了,完了也就没有比较的必要了
void UnionSet(SListNode* l1, SListNode* l2)
{
	assert(l1);
	assert(l2);
	SListNode* pNode1 = l1;
	SListNode* pNode2 = l2;
	while (l1&&l2)
	{
		if (pNode1->_data == pNode2->_data)
		{
			printf("%d", pNode1->_data);
			pNode1 = pNode1->_next;
			pNode2 = pNode2->_next;
		}
		else if (pNode1->_data > pNode2->_data)
		{
			pNode2 = pNode2->_next;
		}
		else
			pNode1 = pNode1->_next;
	}
}

如果有不对的地方,可以评论告诉我,望指导!


<think> 首先,用户查询是:“我想查找关于表的面试题 请问表相关面试题”。用户想查找表相关的面试题。 从系统指令中,我需要: - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 - 结构清晰,帮助用户逐步解决问题。 - 参考提供的站内引用:[1], [2], [3], [4]。 这些引用包含表相关的内容: - 引用[1]:涉及合并两个有序链表的代码(mergeTwoLists),并提到一个面试题“以给定值x为基准将表分割成两部分,所有小于x的结点排在大于或等于x的结点之前”。 - 引用[2]:讨论表中环的检测。 - 引用[3]:提到数据结构面试题,包括表分割(第六题:表分割)。 - 引用[4]:类似[1],有合并表的代码和再次提到“编写代码,以给定值x为基准将表分割成两部分”。 用户没有指定具体的表问题,而是请求一般的表面试题。所以,我应该提供一个表面试题的集合,基于提供的引用。 结构化回答: 1. **介绍**:简要解释表在面试中的重要性。 2. **列出常见表面试题**:基于引用整理相关问题。 - 从引用中提取的问题: - 合并两个有序链表(mergeTwoLists):这在引用[1], [3], [4]中都有代码。 - 表分割:以给定值x分割表,小于x的在前。[^1], [^3], [^4] - 检测表中环的存在:[^2] - 其他常见表问题(我可以添加,但要基于引用)。引用提到“表经典面试题”和“数据结构 十一道表相关面试题”,但具体内容没有列出。我应该专注于引用的内容。 引用[3]说“数据结构 十一道表相关面试题”,但没有列出所有题。引用中只提到了合并表和表分割。 所以,我列出明确的: - 合并两个有序链表 - 表分割:以x为基准分割 - 检测表是否有环 此外,我可以添加一些其他常见问题,如反转表、找出中间节点、删除节点等,但引用的内容中没有这些。用户指令说“尽可能多的参考用户上一次的问题和你的回答”,但这是第一次交互,所以参考提供的引用。 用户消息开头是“参考站内引用”,所以我优先使用这些。 3. **提供示例代码**:如果可能,展示一些代码片段,但要简洁。 4. **生成相关问题**:在结尾添加相关问题,引导用户深入。 回答结构: - 开头:确认用户查询,介绍表面试题。 - 主要内容:列出几个常见表面试题,简要描述,并引用来源。 - 结尾:生成相关问题。 使用引用自然地添加标识:[^1], [^2], [^3], [^4]。 例如: - 对于表分割问题,可以说:这是一个常见问题,要求以值x分割表。[^1][^3][^4] 代码部分:引用中有代码,但我可以简要描述,而不是复制整个代码块。 在回答中,代码应该用代码块格式,如 ```c 或 ```java。 系统指令说“所有行内数学表达式必须使用$...$”,但这里是表问题,可能不需要数学表达式,除非涉及计算。 现在,列出基于引用的面试题: 1. **合并两个有序链表**:合并两个升序表为一个新的升序表。这在引用[1], [3], [4]中都有代码实现。[^1][^3][^4] 2. **表分割**:以给定值x为基准,将表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。这在引用[1], [3], [4]中提及。[^1][^3][^4] 3. **检测表是否有环**:确定表中是否存在环。引用[2]描述了这个问题。[^2] 此外,引用[3]提到“十一道表相关面试题”,但没有列出所有题。我可以暗示有其他问题。 在生成相关问题中,我可以问关于这些。 完整回答: - 介绍:表是数据结构中常见主题,面试中经常考察。 - 列出问题: 1. 合并两个有序链表:描述 + 引用。 2. 表分割:描述 + 引用。 3. 检测表环:描述 + 引用。 4. 其他可能的问题如反转表等,但引用的内容中没有,所以 stick to references. - 引用[3]提到“第六题 :表分割”,所以有其他题,但未列出。我可以 generalise. 最好只覆盖引用的内容。 结尾:生成相关问题,如: - 如何实现反转表? - 如何找出表的中间节点? </think> ### 表相关面试题概述 表是一种常见的数据结构,在面试中经常被考察,因为它能有效测试候选人对指针操作、内存管理和算法设计的理解。表面试题通常涉及基本操作(如插入、删除、遍历)以及更复杂的算法(如合并、分割、环检测)。基于提供的站内引用内容,以下是一些经典的表面试题,这些题目在牛客网、LeetCode等平台中高频出现。我会简要描述每个问题的核心要求,并提供关键思路或代码片段(基于引用中的实现)。代码示例使用C语言或Java,以匹配引用内容。 #### 1. 合并两个有序链表 **问题描述**: 将两个升序合并为一个新的升序表。新表应通过拼接给定表的节点来构建。 - **关键思路**: 使用哨兵节点(带头节点)简化边界处理,并用两个指针遍历原表,比较节点值,较小的节点被尾插到新表中。如果一个表为空,则直接返回另一个表。 - **代码示例 (C语言, 基于引用[1][^1]和引用[4][^4])**: ```c typedef struct ListNode ListNode; struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { if (list1 == NULL) return list2; if (list2 == NULL) return list1; ListNode *newhead = (ListNode*)malloc(sizeof(ListNode)); // 创建哨兵节点 ListNode *newtail = newhead; ListNode *l1 = list1; ListNode *l2 = list2; while (l1 && l2) { if (l1->val < l2->val) { newtail->next = l1; newtail = newtail->next; l1 = l1->next; } else { newtail->next = l2; newtail = newtail->next; l2 = l2->next; } } if (l1) newtail->next = l1; // 处理剩余节点 if (l2) newtail->next = l2; ListNode *ret = newhead->next; free(newhead); // 释放哨兵节点 return ret; } ``` **参考理由**: 该方法高效且易于理解,时间复杂度为$O(n+m)$(n和m为长度),空间复杂度为$O(1)$。[^1][^4] #### 2. 表分割(以给定值x为基准) **问题描述**: 以给定值x为基准,将表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。要求保持节点在原表中的相对顺序。 - **关键思路**: 创建两个表(一个用于小于x的节点,一个用于大于或等于x的节点),遍历原表分配节点,最后连接两个表。注意避免使用额外空间或破坏原有顺序。 - **代码示例 (Java, 基于引用[3][^3]和引用[4][^4])**: ```java public class Solution { public ListNode partition(ListNode head, int x) { ListNode lessHead = new ListNode(-1); // 哨兵节点 for < x ListNode greaterHead = new ListNode(-1); // 哨兵节点 for >= x ListNode lessCur = lessHead; ListNode greaterCur = greaterHead; ListNode cur = head; while (cur != null) { if (cur.val < x) { lessCur.next = cur; lessCur = lessCur.next; } else { greaterCur.next = cur; greaterCur = greaterCur.next; } cur = cur.next; } lessCur.next = greaterHead.next; // 连接两个表 greaterCur.next = null; // 防止环 return lessHead.next; } } ``` **参考理由**: 此解法在$O(n)$时间内完成,空间复杂度$O(1)$,且保持了节点顺序,适用于面试中的算法考察。[^1][^3][^4] #### 3. 检测表是否有环 **问题描述**: 确定表中是否存在环,并通过整数pos表示环的入口位(索引从0开始)。评测系统内部使用pos标识环,但函数参数不包含pos。 - **关键思路**: 使用快慢指针(Floyd判圈算法)。快指针每次移动两步,慢指针每次移动一步,如果相遇则存在环。相遇后,重一个指针到表头,两个指针同步移动,再次相遇点即为环入口。 - **关键描述 (基于引用[2][^2])**: - 如果表中有某个节点,可以通过连续跟踪next指针再次到达,则表中存在环。 - 快慢指针法的时间复杂度为$O(n)$,空间复杂度为$O(1)$,是高效的标准解法。 **示例伪代码**: ```c bool hasCycle(struct ListNode *head) { if (head == NULL) return false; struct ListNode *slow = head; struct ListNode *fast = head; while (fast != NULL && fast->next != NULL) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; // 相遇表示有环 } return false; } ``` **参考理由**: 该问题测试对指针和循环的理解,是表面试的基础题。[^2] #### 其他常见表面试题提示 除了上述基于引用的问题外,表面试中还有以下高频题(虽未在引用中详细展开,但常与这些题组合考察): - **反转表**: 将序,时间复杂度$O(n)$。思路:使用迭代或递归调整指针方向。 - **找出表中间节点**: 使用快慢指针,快指针到末尾时慢指针即为中间点。 - **删除表节点**: 如删除指定值的节点或重复节点,需处理边界条件。 这些题目在LeetCode和牛客网有大量练习资源,建议结合平台刷题。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值