链表面试题小结(待完成)

以下代码使用的公共结构:

链表节点:

struct ListNode
{
	int data;
	ListNode *next;
};

辅助函数:

//make a list
ListNode *makeList(int *arr, int n)
{
	if(arr == NULL || n <= 0)
		return NULL;
	ListNode *phead = new ListNode;
	phead->data = arr[0];
	phead->next = NULL;
	ListNode *ptr = phead;
	for(int i = 1; i < n; i++)
	{
		ListNode *node = new ListNode;
		node->data = arr[i];
		node->next = NULL;
		ptr->next = node;
		ptr = node;
	}
	return phead;
}

//print a list
void printList(ListNode *phead)
{
	ListNode *node = phead;
	while(node != NULL)
	{
		cout << node->data << "\t";
		node = node->next;
	}
	cout << endl;
}
一,从尾到头打印链表

题目:给定一个单链表的头节点,从尾到头打印出该链表的所有节点。


解答:

  1. 使用递归,在递归中,若节点有后续节点,则先处理后续节点,再打印本节点的数据
  2. 递归的本质就是使用栈,所以可以不是用递归,而是在遍历链表的时候将链表数据压入栈中,遍历结束之后出栈就可以得到从尾到头的所有节点值

代码:

/*******************************************************
**question 1
********************************************************/

//solution 1
void printListFromTail_1(ListNode *phead)
{
	if(phead == NULL) return;
	printListFromTail_1(phead->next);
	cout << phead->data << endl;
}

//solution
void printListFromTail_2(ListNode *phead)
{
	if(phead == NULL) return;
	stack<int> myStack;
	ListNode *node = phead;
	do
	{
		myStack.push(node->data);
		node = node->next;
	}while(node != NULL);

	while(myStack.size() > 0)
	{
		cout << myStack.top() << endl;
		myStack.pop();
	}
}

测试及其用例:

//test
/*********************************
arr[10] = {....}
arr[0] = {....}
arr[1] = {....}
arr = NULL
**********************************/
int main()
{
	int arr[1] = {1};
	ListNode *phead = makeList(arr, 1);
	printListFromTail_1(phead);
	printListFromTail_2(phead);
	return 0;
}

二,链表中的倒数第 K个节点

题目:给出一个单链表的头节点,写一个函数获得其倒数第K个节点


解答:

最简单的做法是:先遍历链表,获得链表的长度n,然后再次遍历链表,从头节点开始的第n - K + 1即是所求节点。

优化以下的做法是:使用两个指针,一个先向前遍历K 个节点,另外一个指着头节点,然后两个指针一起向前遍历链表直到链表结尾。这时后面一个节点所指的就是倒数第K个节点


代码:

/*******************************************************
**question 2
********************************************************/
ListNode *getKthNodeFromTail(ListNode *phead, int k)
{
	if(phead == NULL || k <= 0) return NULL;
	ListNode *pBegin = phead;
	ListNode *pEnd = phead;
	for(int i = 0; i < k - 1; i++)
	{
		if(pBegin->next != NULL)
			pBegin = pBegin->next;
		else
			return NULL;
	}

	while(pBegin->next != NULL)
	{
		pBegin = pBegin->next;
		pEnd = pEnd->next;
	}
	return pEnd;
}


测试及其用例:

//test
/*********************************
arr[10] = {....} k = 10
arr[10] = {....} k = 1
arr[10] = {....} k = 5
**********************************/
int main()
{
	int arr[1] = {1};
	ListNode *phead = makeList(arr, 1);
	getKthNodeFromTail(phead, 1);
	return 0;
}


三,反转链表

题目:给定一个单链表的头节点指针,请反转该单链表,并返回反转之后的单链表的头节点指针


解答:使用两个指针,反转链表,这个比较简单。


代码:

/*******************************************************
**question 3
********************************************************/
ListNode *reverseList(ListNode *phead)
{
	if(phead == NULL) return NULL;
	if(phead->next == NULL) return phead;
	ListNode *pBegin = phead->next;
	ListNode *pEnd = phead;
	pEnd->next = NULL;
	do
	{
		ListNode *pTemp = pBegin->next;
		pBegin->next = pEnd;
		pEnd = pBegin;
		pBegin = pTemp;
	}while(pBegin != NULL);
	return pEnd;
}

四,判断单链表是否有环

五,合并两个排序的链表

六,复杂链表的复制

七,两个链表的第一个公共节点

题目:给定两个单链表的头节点,写一个函数返回两个单链表的第一个公共节点


解答:

由于是两个单链表存在公共节点,那么说明是Y型结构,第一个公共节点之后的节点都是公共节点,所以解决这个问题的方法就是利用这些公共节点。

  1. 将两个链表从前到后遍历,将他们的节点分别压入两个栈中,然后出栈比较,直到节点不一样,说明上一个出栈的节点就是第一个公共子节点。时间复杂度是O(M + N),空间复杂度是O(M + N)
  2. 分别遍历两个节点,得到两个节点的长度为:M、N。让长的链表先往前走|M - N|步,然后两个链表一起往前遍历,直到两个链表遇到的节点一样,即为公共子节点

代码:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值