在面试中,链表题出现的频率也是相当的高,以下是对链表题的一个总结,归纳:
1 .从尾到头打印单链表
2.删除⼀个⽆头单链表的⾮尾节点
3.在⽆头单链表的⼀个⾮头节点前插⼊⼀个节点
4.单链表实现约瑟夫环
5.逆置/反转单链表
6.单链表排序(冒泡排序&快速排序)
7.合并两个有序链表,合并后依然有序
8.查找单链表的中间节点,要求只能遍历⼀次链表
9.查找单链表的倒数第k个节点,要求只能遍历⼀次链表
10.判断单链表是否带环?若带环,求环的长度?求环的⼊⼜点?并计算每个算法
的时间复杂度&空间复杂度。
11.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
12.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
3.在⽆头单链表的⼀个⾮头节点前插⼊⼀个节点
4.单链表实现约瑟夫环
5.逆置/反转单链表
6.单链表排序(冒泡排序&快速排序)
7.合并两个有序链表,合并后依然有序
8.查找单链表的中间节点,要求只能遍历⼀次链表
9.查找单链表的倒数第k个节点,要求只能遍历⼀次链表
10.判断单链表是否带环?若带环,求环的长度?求环的⼊⼜点?并计算每个算法
的时间复杂度&空间复杂度。
11.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
12.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
具体代码如下:
typedef int DataType;//数据类型的重定义
typedef struct Node
{
DataType _data;
struct Node* next;//指向下一个结点的指针
}Node,*pNode,*pList;
void InitLinkList(pList* pplist) //链表初始化函数
{
assert(pplist);
*pplist = NULL;
}
pNode BuyNode(DataType x)//新建一个结点
{
pNode pnode=malloc(sizeof(Node));
if(pnode==NULL)
{
perror("PushBack()::malloc");//内存开辟失败
exit(1);
}
pnode->next=NULL;
pnode->_data=x;
return pnode;
}
void PushBack(pList *pplist,DataType x)//在单链表的尾部插入一个元素
{
pNode pnode=NULL;
assert(pplist);
pnode=BuyNode(x);
if(*pplist==NULL)//链表为空
{
*pplist=pnode;
}
else//找到尾结点,在其后面插入
{
pNode cur=*pplist;
while(cur->next)
{
cur=cur->next;
}
cur->next=pnode;
}
}
void PopBack(pList *pplist)//删除尾部结点
{
pNode cur=NULL;
assert(pplist);
if(*pplist==NULL)//空链表
{
return;
}
else if((*pplist)->next==NULL)//只有一个结点
{
free(*pplist);
*pplist=NULL;
}
else //两个或两个以上结点
{ cur=*pplist;//在单链表中删除一个结点需找到其前一个结点
while((cur->next)->next)//查找尾部结点的前一个结点
{
cur=cur->next;
}
free(cur->next);//此时cur->next指向尾部结点
cur->next=NULL;
}
}
void PushFront(pList *pplist,DataType x)//首部插入结点
{
pNode pnode=NULL;
assert(pplist);
pnode=BuyNode(x);
if(*pplist==NULL)
{
*pplist=pnode;
}
else
{
pnode->next=*pplist;//插在头部结点之前
*pplist=pnode;
}
}
void PopFront(pList *pplist)//首部结点的删除
{
pNode del=NULL;
assert(pplist);
del=*pplist;
if(*pplist==NULL)
{
return;
}
*pplist=del->next;
free(del);
del=NULL;//将del置空,防止其成为野指针
}
void BubbleSort(pList* pplist)//冒泡排序
{
pNode cur=NULL;
pNode tail=NULL;
assert(pplist);
if(*pplist==NULL &&(*pplist)->next==NULL)//若单向链表为空或只有一个元素时,不进行排序
{
return;
}
while(tail != (*pplist)->next)//控制排序的趟数
{
cur=*pplist;//每次比较都从头部开始
while(cur!=tail && ( cur->next!=tail))//每趟中的比较次数
{
if(cur->_data > (cur->next)->_data)
{
DataType tmp=cur->_data;
cur->_data=(cur->next)->_data;
(cur->next)->_data=tmp;
}
cur=cur->next;
}
tail=cur;//尾部结点为比较的最后一个元素
}//执行完一趟后,tail向前跳转
}
void ReversePrint(pList plist) //逆序打印单项链表
{
pNode cur=plist;
if(plist==NULL)
{
return;
}
if(cur->next)//寻找尾部结点
{
ReversePrint(cur->next);//递归
}
printf("%d",cur->_data);
}
pNode Find(pList plist,DataType x)//查找某个元素
{
pNode cur=plist;
if(cur==NULL)
{
return NULL;
}
else
{
while(cur&&(cur->_data!=x))//从前往后依次遍历整个链表
{
cur=cur->next;
}
if(cur!=NULL)
{
return cur;//返回结点位置
}
return NULL;//找不到返回空
}
}
void EraseNotTail(pNode pos)//删除无头单链表的非尾结点
{
pNode del=NULL; //将指定位置处的结点,将其后一个结点的数据赋给指定位置处的数据,然后将其后一个结点删除
if(pos==NULL)
{
return;
}
if(pos->next)
{
pos->_data=(pos->next)->_data;
del=pos->next;
pos->next=del->next;
free(del);
del=NULL;
}
}
//在无头单链表的非头结点前插入一个元素
void InsertFrontNode(pNode pos, DataType x)//思路:在指定位置的后面插入一个元素,它们的数据进行交换
{
pNode pnode=BuyNode(x);
DataType tmp;
if(pos==NULL)
{
return;
}
pnode->next=pos->next;
pos->next=pnode;
tmp=pos->_data;
pos->_data=pnode->_data;
pnode->_data=tmp;
}
void JosephCycle(pList* pplist, int k)//约瑟夫环问题
{
pNode cur=NULL;
pNode del=NULL;
int i=0;
assert(pplist);
if(*pplist==NULL)
{
return;
}
cur=*pplist;
while(cur!=cur->next)
{
for(i=0;inext;
}
printf("%d ",cur->_data);
cur->_data=(cur->next)->_data;
del=cur->next;
cur->next=del->next;
free(del);
del=NULL;
}
printf("%d",cur->_data);
}
void ReverseList(pList* pplist)//逆序单向链表
{
pNode cur=NULL;
pNode next=NULL;
pNode tmp=NULL;
assert(pplist);
if((*pplist==NULL) && ((*pplist)->next==NULL))
{
return;
}
cur=*pplist;
next=cur->next;
cur->next=NULL;
while(next)
{
tmp=next->next;
next->next=cur;
cur=next;
next=tmp;
}
*pplist=cur;
}
pList Merge(const pList* p1, const pList* p2)//合并两个有序列表
{
pList newlist=NULL;
pList list1=NULL;
pList list2=NULL;
pList tail=NULL;
assert(p1&&p2);
list1=*p1;
list2=*p2;
if(list1==list2)//list1与list2为同一条链表,或都为空链表
{
return NULL;
}
if(list1==NULL)//一条为空,另一条不为空
{
return list2;
}
if(list2==NULL)
{
return list1;
}
if(list1->_data_data)//新链表的首部
{
newlist=list1;
list1=list1->next;
}
else
{
newlist=list1;
list1=list1->next;
}
tail=newlist;//新链表的尾部
while(list1 && list2)
{
if(list1->_data_data)
{
tail->next=list1;
list1=list1->next;
tail=tail->next;
}
else
{
tail->next=list2;
list2=list2->next;
tail=tail->next;
}
}
if(list1==NULL)
{
tail->next=list2;
}
else
{
tail->next=list1;
}
return newlist;
}
//查找单链表的中间节点,要求只能遍历一次链表
pNode FindMidNode(pList plist)
{//定义两个指针分别为fast和slow,fast每次跳两下,slow每次一下,
//当fast指向链表尾部时,slow所指的位置就是中间结点
pNode fast=plist;
pNode slow=plist;
while((fast) && (fast->next))//链表的结点个数存在奇数和偶数
{
fast=(fast->next)->next;
slow=slow->next;
}
return slow;
}
//查找单链表的倒数第k个节点,要求只能遍历一次链表
pNode FindKNode(pList plist, int k)
{//定义两个指针分别为fast和slow,
//使fast先走k-1步,之后slow再走,当fast指向尾部时,slow所指的就是倒数第k个元素
pNode fast=plist;
pNode slow=plist;
while(fast && fast->next)
{
if(--k<=0)
{
slow=slow->next;
}
fast=fast->next;
}
if(k<=0)
{
return slow;
}
return NULL;
}
//查找单链表的倒数第k个节点,要求只能遍历一次链表
pNode FindKNode(pList plist, int k)
{
pNode fast=plist;
pNode slow=plist;
int i=0;
for(i=0;inext)
{
fast=fast->next;
}
else
{
break;
}
}
if(inext)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
}
pNode CheckCircle(pList plist) //判断链表是否带环
{
pNode fast=plist;
pNode slow=plist;
while(fast && fast->next)//当fast=slow时代表有环
{
fast=(fast->next)->next;
slow=slow->next;
if(fast==slow)
{
return fast;
}
}
return NULL;
}
int GetCircleLength(pNode meet) //求环的长度
{ //从相遇点转一圈的距离
pNode pnode=meet->next;//meet为fast和slow的相遇点
int i=1;
while(pnode!=meet)
{
pnode=pnode->next;
i++;
}
return i;
}
pNode GetCycleEntryNode(pList plist, pNode meet) //求环的入口点
{
pNode pnode=plist;
if((plist==NULL)&&(meet==NULL))
{
return NULL;
}
while(pnode!=meet)
{
meet=meet->next;
pnode=pnode->next;
}
return meet;
}
int CheckCross(pList list1, pList list2)//判断两条单链表是否相交
{
pNode p1=list1;
pNode p2=list2;
while(p1 && p1->next)
{
p1=p1->next;
}
while(p2 && p2->next)
{
p2=p2->next;
}
if((p1==p2)&&(p1!=NULL))
{
return 1;
}
return -1;
}
pNode GetCrossNoCycle(pList list1, pList list2)//转化成不带环的链表求解
{
pNode meet=NULL;
pNode cur=list1;
pNode crossNode=NULL;
while(cur&&cur->next)
{
cur=cur->next;
}
cur->next=list2;
meet=CheckCircle(list1);
crossNode=GetCycleEntryNode(list1,meet);
return crossNode;
}
pNode GetCycleFrontEntryNode(pList list,pNode meet)//求入口点的前一个结点
{
pNode cur=list;
pNode p=GetCycleEntryNode(list,meet);//环的入口点
while(cur->next!=p)
{
cur=cur->next;
}
return cur;
}
//在两个链表已经相交的前提下,转化成不带环的链表求解
pNode GetCrossNode(pList list1, pList list2) //求交点
{
pNode p1=CheckCircle(list1);//判断是否带环,相遇点
pNode p2=CheckCircle(list2);//判断是否带环
pNode crossNode=NULL;
if(p1==NULL && p2==NULL)//list1不带环
{
crossNode=GetCrossNoCycle(list1,list2);
return crossNode;
}
else if (p1&&p2) //如果两个链表都带环
{
pNode endNode= NULL;
pNode cur= NULL;
endNode=GetCycleFrontEntryNode(list1,p1);//找到环入口的前一个结点
cur=endNode->next; //保存环的入口
endNode->next = NULL; //将环断开拆分成两个不带环的链表
crossNode=GetCrossNoCycle(list1,list2); //获得交点
endNode->next = cur; //复原链表
}
return crossNode;
}
void Display(pNode plist)
{
pNode cur=plist;
while(cur)
{
printf("%d->",cur->_data);
cur=cur->next;
}
printf("NULL\n");
}
void Destory(pNode *pplist)
{
pNode del=NULL;
pNode cur=NULL;
assert(pplist);
del=*pplist;
cur=*pplist;
while(cur)
{
del=cur;
cur=cur->next;
free(del);
}
del=NULL;
*pplist=NULL;
}