在面试中面试数据结构中关于链表的基本操作,从未到头打印单链表、逆置\翻转单链表、合并两个有序链表,合并后链表依然有序、查找单链表的中间结点,只能遍历一次单链表、删除链表的倒数第K个结点,要求只能遍历一次单链表等链表的操作,都是面试中常考题,所以这些是必须会的,实现如下
head.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int DataType;
typedef struct ListNode
{
struct ListNode* _pNext;
DataType data;
}*PNode;
void PrintSListFromTail2Head(PNode pHead); // 逆序打印单链表
void DeleteListNotTailNode(PNode pos); // 删除链表的非尾结点,要求:不能遍历链表
void InesrtPosFront(PNode pos, DataType data); // 在链表pos位置前插入值到data的结点
PNode FindMiddleNode(PNode pHead); // 查找链表的中间结点,要求只能遍历一次链表
PNode FindLastKNode(PNode pHead, int K); // 查找链表的倒数第K个结点,要求只能遍历一次链表
PNode DeleteLastKNode(PNode pHead, int K); // 删除链表的倒数第K个结点,要求只能遍历一次链表
void JosephCircle(PNode* pHead, const int M); // 用单链表实现约瑟夫环
void ReverseSList(PNode* pHead); // 链表的逆置--三个指针
PNode ReverseSListOP(PNode pHead); // 链表的逆置--头插法
void BubbleSort(PNode pHead); // 用冒泡排序思想对单链表进行排序
PNode MergeSList(PNode pHead1, PNode pHead2); // 合并两个有序单链表,合并后依然有序
int IsSListCross(PNode pHead1, PNode pHead2); // 判断两个单链表是否相交---链表不带环
PNode GetCorssNode(PNode pHead1, PNode pHead2); // 求两个单链表相交的交点---链表不带环
head.c
#include"head.h"
void PrintSListFromTail2Head(PNode pHead) // 逆序打印单链表
{
assert(pHead);
PNode pNewNode = pHead;
if (NULL == pHead)
{
return;
}
else if (pNewNode)
{
PrintSListFromTail2Head(pNewNode->_pNext);
}
printf("%d", pNewNode->data);
return;
}
void DeleteListNotTailNode(PNode pos) // 删除链表的非尾结点,要求:不能遍历链表
{
PNode p_Cur = pos->_pNext;
pos->data =p_Cur->data;
pos->_pNext = p_Cur->_pNext;
free(p_Cur);
p_Cur = NULL;
}
void InesrtPosFront(PNode pos, DataType data) // 在链表pos位置前插入值到data的结点
{
PNode p = pos->_pNext; //放置pos位置后面的指针
pos ->_pNext = (PNode)BuyNewNode(pos->data); //新建立的结点放在pos后面,并且新建立的结点的data是pos位置的data
pos->_pNext->_pNext = p; //将原来pos后面的结点连接起来
pos->data = data; //将需要插入的数据元素放在pos的位置
}
PNode FindMiddleNode(PNode pHead) // 查找链表的中间结点,要求只能遍历一次链表
{
assert(pHead);
if (NULL == pHead->_pNext )
{
return pHead;
}
PNode Fast = pHead; //建立一个快指针,每次走两步
PNode Slow = pHead; //建立一个慢指针,一次走一步
while (Fast && Fast->_pNext) //判断元素个数是奇数和偶数时,返回中间结点
{
Fast = Fast->_pNext->_pNext;
Slow = Slow->_pNext;
}
return Slow; //最后返回慢指针刚好走到中间结点
}
PNode FindLastKNode(PNode pHead, int K) // 查找链表的倒数第K个结点,要求只能遍历一次链表
{
assert(pHead);
if (NULL == pHead || K<=0) //判空链表和输入的合法性
{
return NULL;
}
PNode Fast = pHead;
PNode Slow = pHead;
while (K--)
{
Fast = Fast->_pNext; //快指针先向后走k步,然后慢指针和快指针一起以相同的速度向后走
}
while (Fast)
{
Fast = Fast->_pNext;
Slow = Slow->_pNext;
}
return Slow;
}
PNode DeleteLastKNode(PNode pHead, int K) // 删除链表的倒数第K个结点,要求只能遍历一次链表
{
assert(pHead);
if (NULL == pHead)
{
return NULL;
}
PNode Fast = pHead;
PNode Slow = pHead;
PNode Cur_Node = NULL;
while (K--)
{
Fast = Fast->_pNext; //快指针先向后走k步,然后慢指针和快指针一起以相同的速度向后走
}
while (Fast)
{
Fast = Fast->_pNext;
Cur_Node = Slow;
Slow = Slow->_pNext;
Cur_Node->_pNext = Slow->_pNext;
}
return pHead;
}
void JosephCircle(PNode* pHead, const int M) // 用单链表实现约瑟夫环
{
PNode Cur_node = NULL;
PNode Del_node = NULL;
int count = 0;
assert(pHead);
if (NULL == pHead || M <= 0)
{
return;
}
Cur_node = *pHead;
while (Cur_node->_pNext)
{
Cur_node = Cur_node->_pNext;
}
Cur_node->_pNext = *pHead;
Cur_node = *pHead;
while (Cur_node->_pNext != Cur_node)
{
count = M;
while (--count)
{
Cur_node = Cur_node->_pNext;
}
Del_node = Cur_node->_pNext;
Cur_node->_pNext = Del_node->_pNext;
free(Del_node);
Del_node = NULL;
}
}
void ReverseSList(PNode* pHead) // 链表的逆置--三个指针
{
PNode Pre_node = NULL;
PNode Cur_node = NULL;
PNode Next_node = NULL;
assert(pHead);
Cur_node = *pHead;
while (Cur_node)
{
Pre_node = Cur_node;
Cur_node = Cur_node->_pNext;
Pre_node->_pNext = Next_node;
Next_node = Pre_node;
}
}
PNode ReverseSListOP(PNode pHead) // 链表的逆置--头插法
{
PNode Cur_node = NULL;
PNode Next_node = NULL;
assert(pHead);
if (NULL == pHead || NULL == pHead->_pNext)
{
return NULL;
}
while (pHead)
{
Cur_node = pHead;
pHead = pHead->_pNext;
Cur_node->_pNext = Next_node;
Next_node = Cur_node;
}
pHead = Next_node;
return pHead;
}
void BubbleSort(PNode pHead) // 用冒泡排序思想对单链表进行排序,从小到大排序
{
PNode Tail = NULL;
PNode P_Cur = pHead;
int flag = 0;
if (NULL == pHead || NULL == pHead->_pNext)
{
return;
}
while (Tail != pHead) //先判断单链表是否是有序的,按照排序结果,如果一趟排序,标记flag没有发生变化就直接打印单链表
{
P_Cur = pHead;
flag = 0;
}
while (P_Cur!=Tail)
{
while (P_Cur->_pNext!=Tail)
{
if (P_Cur->data > P_Cur->data)
{
DataType tmp = P_Cur->data;
P_Cur->data = P_Cur->_pNext->data;
P_Cur->_pNext->data = tmp;
flag = 1;
}
P_Cur = P_Cur->_pNext;
}
Tail = P_Cur;
if (0 == flag)
{
return;
}
}
}
PNode MergeSList(PNode pHead1, PNode pHead2) // 合并两个有序单链表,合并后依然有序
{
PNode P_NewNode = NULL;
pHead1 = pHead1->_pNext;
pHead2 = pHead2->_pNext;
P_NewNode = pHead1;
while (pHead1 && pHead2) //两个链表首先都不为空,然后判断两个链表的data的大小
{
if (pHead1->data > pHead2->data)
{
P_NewNode = P_NewNode->_pNext;
P_NewNode->data = pHead2->data;
pHead2 = pHead2->_pNext;
}
else
{
P_NewNode = P_NewNode->_pNext;
P_NewNode->data = pHead1->data;
pHead1 = pHead1->_pNext;
}
}
P_NewNode->_pNext = pHead1 ? pHead1 : pHead2; //判断链表是否一个已经为空,直接将另一个链表的内容链接在后面
free(pHead2);
return P_NewNode;
}
int IsSListCross(PNode pHead1, PNode pHead2) // 判断两个单链表是否相交---链表不带环
{
PNode p1 = pHead1;
PNode p2 = pHead2;
int p1_Size = 0; //pHead1的大小,设置计数器计数
int p2_Size = 0; //pHead2的大小,设置计数器计数
int k = 0; //PHead1和PHead大小比较相差的步数
if (NULL == p1 || NULL == p2) //判断链表是否为空,如果为空就返回0,所以不想交
{
return 0;
}
while (p1) //链表1不为空继续计数
{
p1_Size++;
p1 = p1->_pNext;
}
while (p2) //链表的大小
{
p2_Size++;
p2 = p2->_pNext;
}
if (p1_Size > p2_Size)
{
k = p1_Size - p2_Size;
while (k--)
{
p1->_pNext;
}
p2->_pNext;
if (p1->data == p2->data)
{
return 1;
}
}
if (p1_Size < p2_Size)
{
k = p2_Size - p1_Size;
while (k--)
{
p2->_pNext;
}
p1->_pNext;
}
if (p1->data == p2->data)
{
return 1;
}
}
PNode GetCorssNode(PNode pHead1, PNode pHead2) // 求两个单链表相交的交点---链表不带环
{
PNode p1 = pHead1;
PNode p2 = pHead2;
int p1_Size = 0; //pHead1的大小,设置计数器计数
int p2_Size = 0; //pHead2的大小,设置计数器计数
int k = 0; //PHead1和PHead大小比较相差的步数
if (NULL == p1 || NULL == p2) //判断链表是否为空,如果为空就返回0,所以不想交
{
return NULL;
}
while (p1) //链表1不为空继续计数
{
p1_Size++;
p1 = p1->_pNext;
}
while (p2) //链表的大小
{
p2_Size++;
p2 = p2->_pNext;
}
if (p1_Size > p2_Size)
{
k = p1_Size - p2_Size;
while (k--)
{
p1->_pNext;
}
p2->_pNext;
if (p1->data == p2->data)
{
return p1;
}
}
if (p1_Size < p2_Size)
{
k = p2_Size - p1_Size;
while (k--)
{
p2->_pNext;
}
p1->_pNext;
}
if (p1->data == p2->data)
{
return p1;
}
else
{
return NULL;
}
}