链表面试题总结:
-
逆序打印单项链表 递归实现
-
在无头单链表的非头结点前插入一个元素
-
约瑟夫环问题
首先了解约瑟夫环是什么:约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。
-
合并两个有序列表
创建一个新链表,将两个链表遍历,小的放进新链表中,直到一个为空,将剩余放进新链表中
-
查找单链表的中间节点,要求只能遍历一次链表
运用两个快慢指针解决,
fast每次走两步,
slow每次走一步,
当fast走到尾时,
slow指向的是中间节点
因为slow走的是fast的一半。
-
查找单链表的倒数第k个节点,要求只能遍历一次链表
先将fast走k步,后slow与fast同时走,当fast走到尾时,slow指向的是倒数第k个
-
判断链表是否带环
当有环时,fast总会与slow相遇,否则fast会走向空。
-
求环的长度
-
求环的入口点
-
判断两条单项链表是否相交
-
找到交点
以下是代码实现:
linklist.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;
}Node, *pNode, List, *pList;
void InitLinkList(pList* pplist);
pNode BuyNode(DataType d);
void DestroyLinkList(pList* pplist); // 释放链表
void PushBack(pList* pplist, DataType d);
void PopBack(pList* pplist); //尾删
void PushFront(pList* pplist, DataType d);
void PopFront(pList* pplist);
pNode Find(pList plist, DataType d);
void Insert(pList* pplist, pNode pos, DataType d);//在指定位置之前插入一个值
void Erase(pList* pplist, pNode pos);//指定位置删除
void Remove(pList* pplist, DataType d);
void RemoveAll(pList* pplist, DataType d);
void EraseNotTailNode(pNode pos);
void PrintLinkList(pList plist);
int GetListLength(pList plist);
//链表面试题
void PrintTailToHead(pList plist); // 逆序打印单项链表
void InsertFrontNode(pNode pos, DataType x);//在无头单链表的非头结点前插入一个元素
void JosephCycle(pList* pplist, int k); //约瑟夫环问题
pList Merge(pList* p1, pList* p2); //合并两个有序列表
pNode FindMidNode(pList plist); //查找单链表的中间节点,要求只能遍历一次链表
pNode FindKNode(pList plist, int k); //查找单链表的倒数第k个节点,要求只能遍历一次链表
void MakeRing(pList* pplist); //建环
pNode CheckCircle(pList plist);//判断链表是否带环
int GetCircleLength(pNode meet); //求环的长度
pNode GetCycleEntryNode(pList plist, pNode meet); //求环的入口点
int CheckCross(pList list1, pList list2); //判断两条单项链表是否相交
pNode GetCrossNode(pList list1, pList list2);//找到交点
#endif //__LINKLIST_H__
linklist.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "linklist.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
void PrintLinkList(pList plist)
{
pNode cur = plist;
if (cur == NULL)
{
printf("empty");
}
else
{
while (cur)
{
printf("%d-> ", cur->data);
cur = cur->next;
}
printf("over");
}
printf("\n");
}
void InitLinkList(pList* pplist)
{
assert(pplist != NULL);
(*pplist) = NULL;
}
pNode BuyNode(DataType d)
{
pNode NewNode = NULL;
NewNode = (pNode)malloc(sizeof(Node));
if (NewNode == NULL)
{
printf("开创失败");
exit(EXIT_FAILURE);
}
else
{
NewNode->data = d;
NewNode->next = NULL;
}
return NewNode;
}
void DestroyLinkList(pList* pplist)
{
pNode cur = *pplist;
pNode del = NULL;
assert(pplist);
while (cur)
{
del = cur;
cur = cur->next;
free(del);
del = NULL;
}
}
void PushBack(pList* pplist, DataType d)
{
assert(pplist);
pNode NewNode = BuyNode(d);
pNode cur = *pplist;
if (cur == NULL)
{
*pplist = NewNode;
return;
}
else
{
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = NewNode;
}
}
void PopBack(pList* pplist)
{
assert(pplist != NULL);
pNode cur = *pplist;
if (cur->next == NULL)
{
free(cur);
*pplist = NULL;
}
while (cur->next->next != NULL)
{
cur = cur->next;
}
free(cur->next);
cur->next = NULL;
}
void PushFront(pList* pplist, DataType d)
{
assert(pplist != NULL);
pNode cur = BuyNode(d);
cur->next = *pplist;
*pplist = cur;
}
void PopFront(pList* pplist)
{
assert(pplist);
if (*pplist == NULL)
{
return;
}
pNode del = NULL;
del = *pplist;
*pplist = del->next;
free(del);
}
pNode Find(pList plist, DataType d)
{
pNode cur = plist;
while (cur->next != NULL)
{
if (cur->data == d)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
void Insert(pList* pplist, pNode pos, DataType d)
{
assert(pplist);
pNode NewNode = BuyNode(d);
pNode cur = *pplist;
if (*pplist == pos)
{
PushFront(pplist, d);
}
else
{
while (cur &&cur->next != pos)
{
cur = cur->next;
}
NewNode->next = pos;
cur->next = NewNode;
}
}
void Erase(pList* pplist, pNode pos)
{
assert(pplist);
if (*pplist == NULL)
{
return;
}
pNode cur = *pplist;
while (cur&&cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
free(pos);
}
void Remove(pList* pplist, DataType d)
{
assert(pplist);
pNode del = *pplist;
while(del->data != d)
{
del = del->next;
}
pNode cur = *pplist;
while (cur->next != del)
{
cur = cur->next;
}
cur->next = del->next;
free(del);
}
void RemoveAll(pList* pplist, DataType d)
{
assert(pplist);
pNode cur = *pplist;
pNode pre = *pplist;
while (cur != NULL)
{
if (cur->data == d)
{
pNode del = cur;
pre->next = cur->next;
cur = pre->next;
free(del);
}
else
{
pre = cur;
cur = cur->next;
}
}
}
void EraseNotTailNode(pNode pos)
{
pNode cur = pos;
if (cur == NULL || cur->next == NULL)
return;
cur = pos->next;
pos->data = cur->data;
pos->next = cur->next;
free(cur);
}
int GetListLength(pList plist)
{
assert(plist);
pNode cur = plist;
int length = 0;
while (cur != NULL)
{
length++;
cur = cur->next;
}
return length;
}
//
//
//递
//
//
//归
//
//
void PrintTailToHead(pList plist)
{
if (plist != NULL)
{
if (plist->next != NULL)
{
PrintTailToHead(plist->next);
}
printf("%d ", plist->data);
}
}
void InsertFrontNode(pNode pos, DataType x)
{
pNode NewNode = BuyNode(x); //插入分两步
NewNode->next = pos->next; //先与后面相连
pos->next = NewNode; //再将之连到pos->next
DataType tmp = 0;
tmp = pos->data;
pos->data = NewNode->data;
NewNode->data = tmp;
}
void JosephCycle(pList* pplist, int k)
{
assert(pplist);
pNode tou = *pplist;
pNode cur = *pplist;
pNode pre = NULL;
while (tou->next != NULL) //建环
{
tou = tou->next;
}
tou->next = *pplist;
while (cur->next != cur)
{
for (int i = 1; i <= k; i++) //循环k次
{
pre = cur;
cur = cur->next;
}
pre->next = cur->next; //将cur前后2个节点相连
free(cur);
cur = pre->next; //再从pre下一个报数
}
cur->next = NULL;
}
pNode FindMidNode(pList plist)
{
pNode slow = plist;
pNode fast = plist;
while (fast != NULL&&fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
pNode FindKNode(pList plist, int k)
{
pNode first = plist;
pNode second = plist;
while (k--)
{
first = first->next;
}
while (first != NULL)
{
first = first->next;
second = second->next;
}
return second;
}
List* Merge(pList* p1, pList* p2)
{
assert(p1);
assert(p2);
List* list = NULL;
pNode cur1 = p1;
pNode cur2 = p2;
while (cur1 != NULL&&cur2 != NULL)
{
if (cur1->data < cur2->data)
{
PushBack(&list, cur1->data);
cur1 = cur1->next;
}
else
{
PushBack(&list, cur2->data);
cur2 = cur2->next;
}
}
while (cur1 != NULL)
{
PushBack(&list, cur1->data);
cur1 = cur1->next;
}
while (cur2 != NULL)
{
PushBack(&list, cur2->data);
cur2 = cur2->next;
}
return list;
}
void MakeRing(pList* pplist)
{
assert(pplist);
pNode cur = *pplist;
pNode per = *pplist;
while (cur->next!=NULL)
{
cur = cur->next;
}
cur->next = per->next->next;
}
pNode CheckCircle(pList plist)//判断链表是否带环
{
assert(plist);
pNode fast = NULL;
pNode slow = NULL;
fast = plist;
slow = plist;
while (1)
{
fast = fast->next->next;
slow = slow->next;
if (fast->next == NULL)
return NULL;
if (fast == slow)
return slow;
}
}
int GetCircleLength(pNode meet) //求环的长度 给的是相遇点
{
pNode cur = meet;
int count = 1;
while (cur->next != meet)
{
count++;
cur = cur->next;
}
return count;
}
pNode GetCycleEntryNode(pList plist, pNode meet)//求环的入口点
//相遇点到入口点的距离 等于 链表从头走到入口点的位置
{
assert(plist);
pNode cur = plist;
pNode tail = meet;
while (cur != tail)
{
cur = cur->next;
tail = tail->next;
}
return cur;
}
int CheckCross(pList list1, pList list2) //判断两条单项链表是否相交
{
pNode cur1 = list1;
pNode cur2 = list2;
while (cur1->next != NULL)
{
cur1 = cur1->next;
}
while (cur2->next != NULL)
{
cur2 = cur2->next;
}
if (cur1 == cur2)
return 1;
else
return 0;
}
pNode GetCrossNode(pList list1, pList list2)
{
assert(list1);
assert(list2);
int len1 = GetListLength(list1);
int len2 = GetListLength(list2);
pNode cur = list1;
pNode tmp = list2;
if (len1 > len2)
{
for (int i = 0; i < len1 - len2; i++)
{
cur = cur->next;
}
}
if (len1 < len2)
{
for (int i = 0; i < len2 - len1; i++)
{
tmp = tmp->next;
}
}
while (list1 != NULL)
{
if (list1 == list2)
return list1;
list1 = list1->next;
list2 = list2->next;
}
return NULL;
}