前面的博客已经介绍过了实现链表的一些相关的功能,所以在这里就不对链表多加解释说明了。
对于链表相关面试题这里解释几个有特点的题:
1.对于求查找链表的中间结点,要求只能遍历一次链表?
方式:使用两个指针,一个快指针,一个慢指针,快指针走两步慢指针走一步,这样当快指针指向结尾空指针的时候,慢指针刚好指向中间结点。
图示:
2.查找链表倒数第K个结点要求只能遍历一次链表?
方式:同样运用快慢指针,先让快指针走K-1次然后让快慢指针一起走,当fast->next==NULL时,慢指针刚好指向倒数第K个结点,注意这里的快指针还是一次走两步。
图示:
3判断一个链表是否带环,带环求环的入口点?
方式:还是对快慢指针的运用,让两个指针一直走,如果相遇则带环,否则不带环。因为快慢的指针速度不一样,如果带环他们都上了环相当于跑圈,速度不一样肯定会相遇,如果不带环快指针肯定先指向NULL,也不会相遇。
图示:
4.求环的入口点?
方式:还是使用快慢指针,不过这里需要用到快慢指针在环上的相遇点,具体过程如下图
图示:
当然这个题的解法还有很多,大家可以自己思考一下其他的方法
5.判断两个链表是否相交,求交点?
方式:这里还是对快慢指针的应用,具体过程如下图
接下来给出所有问题的代码
首先给出头文件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;
}
以上测试函数是我自己编写时按自己想法测试的,比较凌乱,你可以根据自己的想法去测试!
有什么问题欢迎留言一起交流学习!