链表常见面试题-C语言实现

前面的博客已经介绍过了实现链表的一些相关的功能,所以在这里就不对链表多加解释说明了。

对于链表相关面试题这里解释几个有特点的题:

1.对于求查找链表的中间结点,要求只能遍历一次链表?

方式:使用两个指针,一个快指针,一个慢指针,快指针走两步慢指针走一步,这样当快指针指向结尾空指针的时候,慢指针刚好指向中间结点。

图示:

《链表常见面试题-C语言实现》

2.查找链表倒数第K个结点要求只能遍历一次链表?

方式:同样运用快慢指针,先让快指针走K-1次然后让快慢指针一起走,当fast->next==NULL时,慢指针刚好指向倒数第K个结点,注意这里的快指针还是一次走两步。

图示:

《链表常见面试题-C语言实现》

3判断一个链表是否带环,带环求环的入口点?

方式:还是对快慢指针的运用,让两个指针一直走,如果相遇则带环,否则不带环。因为快慢的指针速度不一样,如果带环他们都上了环相当于跑圈,速度不一样肯定会相遇,如果不带环快指针肯定先指向NULL,也不会相遇。

图示:

《链表常见面试题-C语言实现》

4.求环的入口点?

方式:还是使用快慢指针,不过这里需要用到快慢指针在环上的相遇点,具体过程如下图

图示:

《链表常见面试题-C语言实现》

当然这个题的解法还有很多,大家可以自己思考一下其他的方法

5.判断两个链表是否相交,求交点?

方式:这里还是对快慢指针的应用,具体过程如下图

《链表常见面试题-C语言实现》

接下来给出所有问题的代码

首先给出头文件List.h

#define _CRT_SECURE_NO_WARNINGS 1
#ifndef __LIST_H__
#define __LIST_H__

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int Datatype;

typedef struct Node
{
	Datatype data;
	struct Node *next;
}Node,*PLinklist;

void initList(PLinklist* pplist);//初始化头指针
void pushback(PLinklist* pplist,Datatype);//尾插法
void showlist(PLinklist pplist);//正顺打印结点
void destory(PLinklist* pplist);//释放所开辟的结点
void _showlist(PLinklist pplist);//逆序打印
void delnotetail(PLinklist pos);//删除无头非尾结点
PLinklist find_list(PLinklist pplist, Datatype d);//查找链表
void inertfrontnode(PLinklist pos, Datatype d);//无头结点非尾结点前插入一个元素
void josephcycle(PLinklist pplist,Datatype  k);//约瑟夫环
void rever(PLinklist* pplist);//逆序链表
void bubble(PLinklist pplist);//排序链表
PLinklist Merge(PLinklist* pplist, PLinklist* pplists);//合并两个有序链表和并后也为空
PLinklist findmiddle(PLinklist pplist);//查找中间结点
void deletk(PLinklist pplist,int k);//查找倒数第K个结点.只能遍历一次离岸边
PLinklist checkcircle(PLinklist pplist);//判断一个链表带不带环,带环返回两个指针相遇点的地址
int getcirclelong(PLinklist meet);//如果有环求环的长度
PLinklist findenterpoint(PLinklist pplist, PLinklist meet);//如果带环则找入口点,//meet为相遇点
PLinklist checklist(PLinklist pplist, PLinklist pplists);//判断两条链表是否相交,相交返回交点

#endif

接下来给出具体实现函数的文件List.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"

void initList(PLinklist* pplist)
{
	*pplist = NULL;//pplist里面放的是指针变量head的地址,*pplist就是指针变量地址的值,在这里赋值为空
}
void pushback(PLinklist* pplist,Datatype d)
{
	Node *p = *pplist;//P里面存的是头指针的地址
	PLinklist cur= (PLinklist)malloc(sizeof(Node));//开辟第一个结点
	if (cur == NULL)
	{
		perror("usr malloc ");
		exit(EXIT_FAILURE);
	}
	memset(cur, 0, sizeof(Node));
	cur->data = d;
	cur->next = NULL;
	if (p== NULL)
	{
		*pplist = cur;//头结点的地址给头指针
	}
	else
	{
		while (p->next != NULL)
		{
			p= p->next;
		}
		p->next = cur;
	}
}


void showlist(PLinklist pplist)
{
	Node *cur = pplist;
	while (cur != NULL)
	{
		printf("%d--", cur->data);
		cur = cur->next;
	}
}
void destory(PLinklist* pplist)
{
	Node *cur = *pplist;//cur里面存的头指针的地址
	while (cur!= NULL)
	{
		Node *p = cur;//保存第一个结点的地址
		cur = cur->next;//cur保存第二个结点的地址
			free(p);//
	}
	*pplist = NULL;
}
void _showlist(PLinklist pplist)
{
	if (pplist == NULL)
		return;
	else if (pplist->next == NULL)
		printf("%d ", pplist->data);
	else
	{
		_showlist(pplist->next);
		printf("%d ", pplist->data);
	}
}
PLinklist find_list(PLinklist pplist, Datatype d)//查找链表返回地址
{
	Node *cur = pplist;
	while (cur)
	{
		if (cur->data == d)
		{
			return cur;
		}
		cur = cur->next;
	}
	return;
}
void delnotetail(PLinklist pos)//删除无头非尾结点
{
	Node *cur = NULL;
	assert(pos->next);
	cur = pos->next;
		pos->data = cur->data;
		pos->next = cur->next;
		free(cur);
}
void inertfrontnode(PLinklist pos, Datatype d)
{
	assert(pos);
	Node *p = (PLinklist)malloc(sizeof(Node));
	if (p == NULL)
	{
		perror("use malloc");
		exit(EXIT_FAILURE);
	}
	p->data = pos->data;
	pos->data = d;
	p->next = NULL;
	p->next = pos->next;
	pos->next = p;
}
void josephcycle(PLinklist pplist, Datatype  k)//约瑟夫环
{
	Node *cur = pplist;
	Node *del = NULL;
	int count = 0;
	while (1)
	{
		count = k;
		if (cur == cur->next)//剩一个数字退出
		{
			break;
		}
		while (count-2>0)
		{
			cur = cur->next;
			--count;
		}
		printf("%d  ", cur->next->data);
		del = cur->next;
		cur->next = del->next;
		cur = cur->next;
		free(del);
		
	}
	printf("%d\n", cur->data);
}
void rever(PLinklist* pplist)//逆序链表
{
	Node *cur = *pplist;
	Node *tem = NULL;
	Node *head = NULL;
	if ((cur == NULL) || (cur->next == NULL))
	{
		return;
	}
	while (cur)
	{
		tem = cur->next;
		cur->next = head;
		head = cur;
		cur = tem;
	}
	*pplist = head;
}
void bubble(PLinklist pplist)//排序算法
{
	int count = 1;
	Node *cur = pplist;
	Node *src = pplist;
	while (src->next != NULL)
	{
		count++;
		src = src->next;
	}
	int i = 0,j=0;
	for (i = 0; i < count; i++)
	{
		Node *cur = pplist;
		for (j = 0; j < count - 1 - i; j++)
		{
			int temp = 0;
			if ((cur->data)>(cur->next->data))
			{
				temp = cur->data;
				cur->data = cur->next->data;
				cur->next->data = temp;
			}
			cur = cur->next;
		}
	}
}
PLinklist Merge(PLinklist* pplist, PLinklist* pplists)//链接两个有序链表
{
	Node  *cur1 = *pplist;
	Node  *cur2 = *pplists;
	Node  *head = NULL;
	Node  *tail = NULL;
	if (cur1 == NULL&&cur2 == NULL)//两条都为空不合并
		return NULL;
	if (cur1 == cur2)
		return cur1;
	if (cur1 == NULL)
		return cur2;
	if (cur2 == NULL)
		return cur1;
	if (cur1->data > cur2->data)
	{
		head = cur1;
		cur2 = cur2->next;
		head->next = NULL;
		tail = head;
	}
	else
	{
		head = cur1;
		cur1 = cur1->next;
	}
	head->next = NULL;
	tail = head;
	while (cur1 != NULL&&cur2 != NULL)
	{
		if (cur1->data < cur2->data)
		{
			tail->next = cur1;
			cur1 = cur1->next;
		}
		else
		{
			tail->next = cur2;
			cur2 = cur2->next;
		}
		tail->next->next = NULL;
		tail = tail->next;
	}
	if (cur1 == NULL)
	{
		tail->next = cur2;
	}
	else
		tail->next = cur1;
	return head;
}
PLinklist findmiddle(PLinklist pplist)//查找中间结点的元素
{
	Node *slow = pplist;
	Node *quic = pplist;
	while (quic != NULL&&quic->next != NULL)//这里的顺序很重要不然就会越界程序崩溃
	{
		quic = quic->next->next;
		slow = slow->next;
	}
	return slow;
}
void deletk(PLinklist pplist, int k)//删除倒数第K个结点
{
	Node *first = pplist;
	Node *second = pplist;
	while (first->next != NULL)
	{
		if (--k <= 0)
		{
			second = second->next;//指向删除的结点
		}
		first = first->next;
	}
	if (k <= 0)
	{
		Node *src = second->next;
		second->data = second->next->data;
		second->next = second->next->next;//
		free(src);
		/*second->next->next = NULL;*/
	}
}
PLinklist checkcircle(PLinklist pplist)//判断一个链表是否带环
{
	Node *slow = pplist;
	Node *fast = pplist;
	while (fast&&fast->next)
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			return fast;
		}
	}
		return NULL;
}
int getcirclelong(PLinklist meet)//meet为入口点
{
	Node *cur = meet;
	int count = 0;
	do
	{
		count++;
		cur=cur->next;
	} while (cur != meet);
		return count;
}
PLinklist findenterpoint(PLinklist pplist,PLinklist meet)//meet为相遇点点
{
	Node *cur = pplist;
	while (meet != cur)
	{
		meet = meet->next;
		cur = cur->next;
	}
	return meet;
}
PLinklist checklist(PLinklist pplist, PLinklist pplists)//判断两条链表是否相交,相交返回交点
{
	Node *src = pplist;
	Node *dest = pplists;
	assert(pplist&&pplist);
	while (src->next != NULL)
	{
		src = src->next;
	}
	while (dest ->next!= NULL)
	{
		dest = dest->next;
	}
	if (src == dest)//相交了
	{
		Node *meet = NULL;
		src->next = pplists;//接成一个环
		meet = checkcircle(pplist);//找环指针的相遇地点
		Node *ret=findenterpoint(pplist, meet);//找环的入口点
		return ret;
	}
	else
	{
		return NULL;
	}
}

最后给出test.c文件主要是测试函数和main函数

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//void test2()
//{
//	PLinklist head;
//	initList(&head);
//	int i = 0;
//	for (i = 1; i < 42; i++)
//	{
//		pushback(&head, i);
//	}
//	find_list(head, 41)->next = head;
//	josephcycle(head, 3);
//	/*showlist(head);*/
//}
void test()
{
	PLinklist head;//定义头指针
	//PLinklist heads;//定义头指针
	initList(&head);//将头指初始化为空避免也指针的存在
	//initList(&heads);//将头指初始化为空避免也指针的存在,测试合并链表所定义的
	pushback(&head, 1);
	pushback(&head, 2);
	pushback(&head, 3);
	pushback(&head, 4);
	pushback(&head, 5);
	pushback(&head, 6);
	//pushback(&heads, 7);
	//pushback(&heads, 8);
	//pushback(&heads, 9);
	showlist(head);
	printf("\n");
	Node *ret = findmiddle(head);
	printf("%d", ret->data);
	
	//showlist(heads);
	//printf("\n");
	//find_list(heads, 9)->next = find_list(head, 5);
	//Node *ptr=checklist(head, heads);
	//printf("%d", ptr->data);
	//Node *src=checkcircle(head);//检查带不带环
	//printf("%d", src->data);
	//int ret=getcirclelong(src);
	//printf("%d", ret);
	//Node *dest=findenterpoint(head, src);//找入口点函数
	//printf("%d", dest->data);
	//showlist(head);
	//printf("\n");
	//deletk(head, 3);
	//pushback(&head, 8);
	//showlist(head);
	//printf("\n");
	//rever(&head);
	//showlist(findmiddle(head)->dtaa);
	//Node *x = findmiddle(head);//打印中间函数
	//printf("%d",x->data );
	//PLinklist pos=find_list(head, 4);
	//inertfrontnode(pos, 10);
	//test2();
	//delnotetail(pos);
	//bubble(head);
	/* printf("\n");*/
	 //showlist(Merge(&head, &heads));
	//showlist(heads);
	//_showlist(head);//逆序打印
	//destory(&head);
	//showlist(head);

}
int main()
{
	test();
	system("pause");
	return 0;
}

以上测试函数是我自己编写时按自己想法测试的,比较凌乱,你可以根据自己的想法去测试!

有什么问题欢迎留言一起交流学习!

    原文作者:IT_iverson
    原文地址: https://blog.csdn.net/IT_iverson/article/details/76615041
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞