LinkList.h
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node *next;
}Node, *pNode,List,*pList;
typedef struct NewNode
{
DataType data;
struct NewNode *next;
struct NewNode *random;
}pNewList;
void lnitLinkList(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);
void GetListLength(pList plist);
//链表面试题
//1.逆序打印单项链表
void PrintTailToHead(pList plist);
void Row(pList plist);
//2.删除一个无头单链表的非尾节点(不能遍历这个链表)
void DelNode(pList pos);
//3.从无头单链表的一个节点前插入一个节点(不能便利单链表)
void InsertNode(pList pos, DataType d);
//4.单链表实现约瑟夫环;
pList JosephCycle(pList *pplist);
//5.逆置/反转单链表
void ReverseList(pList *pplist);
//6.单链表排序
void LinkBubbleSort(pList *pplist);
void LinkQuickSort(pList *pplist);
//7.合并两个有序的单链表
pList MergeList(pList *pplist, pList *cur);
//8.遍历一遍链表,找到中间的那个节点
pList FindNode(pList *pplist);
//9.遍历一遍链表,找出倒数第K个节点
pList FindKNode(pList *pplist,DataType k);
//10.删除倒数第K个节点
pList EraseKNode(pList *pplist, DataType k);
//11.判断单链表是否带环,若带环,求环的长度,求环的入口点,并计算每个算法的时间复杂度&空间复杂度
pList IsCycle(pList plist);
DataType Looplength(pList ret);
pList LinkInNode(pList plist, pList ret);
//12.判断两个链表是否相交,若相交,求交点(假设链表不带环)
pList LinkIntersect1(pList plist,pList cur);
pList LinkIntersect2(pList plist,pList cur);
//13.判断来两个链表是否相交,若相交,求交点
pList LinkInterLoop(pList plist, pList cur);
//14.求两个以排序单链表中相同的数据
void UnionSet(Node *l1, Node *l2);
//
pNewList* CopLinklist(pNewList **pplist);
#endif //_LINKLIST_H_
Link.c
链表的基本操作:
#include"Linklist.h"
//建立一个节点
pNode BuyNode(DataType d)
{
pNode cur = NULL;
cur = (pList)malloc(sizeof(Node));
if(NULL == cur)
{
printf("申请失败");
exit(1);
}
cur->data = d;
cur->next = NULL;
return cur;
}
//初始化
void lnitLinkList(pList *pplist)
{
assert(pplist);
*pplist = NULL;
}
//销毁链表
void DestroyLinkList(pList *pplist)
{
pList top = *pplist;
assert(pplist);
while(top != NULL)
{
pList cur = top;
top = top->next;
free(cur);
cur = NULL;
}
*pplist = NULL;
}
//尾插法
void PushBack(pList* pplist, DataType d)
{
pList ret = NULL;
pNode cur = BuyNode(d);
assert(pplist);
ret = *pplist;
//如果链表为空
if(*pplist == NULL)
*pplist = cur;
//如果链表非空,则找到最后一个节点
else
{
while(ret->next != NULL)
{
ret = ret->next;
}
ret->next = cur;
}
}
//头插
void PushFront(pList *pplist, DataType d)
{
pNode NewNode = BuyNode(d);
assert(pplist);
NewNode->next = *pplist;
*pplist = NewNode;
}
//尾删
void PopBack(pList* pplist)
{
pList cur = NULL;
assert(pplist);
cur = *pplist;
//如果链表为空
if(*pplist == NULL)
return ;
//如果只有一个节点
else if((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
//有两个以上的节点
else
{
while(cur->next->next != NULL)
cur = cur->next;
free(cur->next);
cur->next = NULL;
}
}
//头删
void PopFront(pList *pplist)
{
pList cur = NULL;
assert(pplist);
cur = *pplist;
//空链表
if(NULL == cur)
return ;
//不为空链表
else
{
*pplist = cur->next;
free(cur);
cur = NULL;
}
}
//找指定数据的位置
pNode Find(pList plist, DataType d)
{
//链表为空时
if(NULL == plist)
printf("链表为空\n");
else
{
while(plist->data != d && plist != NULL)
plist = plist->next;
}
return plist;
}
//打印
void PrintLinklist(pList plist)
{
if(plist == NULL)
printf("链表为空\n");
else
{
while(NULL != plist)
{
printf("%d->", plist->data);
plist = plist->next;
}
}
printf("NULL\n");
}
//在指定位置之前插入
//指定位置一定要在链子内
void Insert(pList *pplist,pNode pos, DataType d)
{
pList NewNode = BuyNode(d);
pList cur = NULL;
assert(pplist);
//空链表时(并且指定位置为空时)
if(*pplist == NULL && pos == NULL)
{
*pplist = BuyNode(d);
return;
}
//有一个节点时
cur = *pplist;
if(cur == pos)
{
NewNode->next = *pplist;
*pplist = NewNode;
}
//有两个以上的结点时
else
{
while(cur->next != pos)
{
cur = cur->next;
}
cur->next = BuyNode(d);
cur->next->next = pos;
}
}
//指定位置删除
void Erase(pList *pplist, pNode pos)
{
pList cur = NULL;
assert(pplist);
cur = *pplist;
//当链表为空时
if(*pplist == NULL)
{
return;
}
//当要删除的节点时第一个节点时
if(*pplist == pos)
{
*pplist = (*pplist)->next;
free(cur);
cur = NULL;
}
//当要删除的节点不是第一个时
else
{
pNode ret = NULL;
while(cur->next != pos)
cur = cur->next;
ret = cur->next;
cur->next = cur->next->next;
free(ret);
ret = NULL;
}
}
//删除第一个
void Remove(pList *pplist, DataType d)
{
pList cur = NULL;
assert(pplist);
cur = Find(*pplist, d);
if(cur != NULL)
Erase(pplist, cur);
}
//删除链表中所有指定值的节点
void RemoveAll(pList *pplist, DataType d)
{
pNode ret = NULL;
pList cur = NULL;
assert(pplist);
cur = *pplist;
//链表为空时
if(*pplist == NULL)
return ;
//链表不为空时
if(cur->next != NULL)//链表有两个或两个以上的节点
{
while(cur->next != NULL)
{
if(cur->next->data == d)
{
ret = cur->next;
cur->next = ret->next;
free(ret);
ret = NULL;
}
else
cur = cur->next;
}
}
//判断第一个节点
if((*pplist)->data == d)
{
PopFront(pplist);
}
}
链表的面试题:
1.从头到尾打印单链表
(1)递归打印,直接递归到最后一个节点,遍历打印该节点,然后返回到上一层,再次遍历打印倒数第二个节点。直到调用函数函数结束
(2)循环打印单链表,首先用一个指针pEnd指向NULL,另一个指针pNode指向链表的首地址,当pNode->next域是pEnd时,代表找到最后一个元素,先遍历打印该节点,然后将pEnd指向pNode此时的地址,将pNode指向链表的首地址。如果此时的 pEnd == pNode时直接退出。否则,将pNode再次从头开始遍历,当pNode->next域是pEnd时,找到上次遍历节点的前一个节点。然后将pEnd再次指向pNode,如此反复,直到pEnd == pNode时停止。
(3)创建一个栈,遍历单链表,每遍历一个节点就将该节点的数据放入栈中,全部放入之后,将栈中的元素不断出栈,这样就形成了链表的逆序打印。
//逆序打印单链表
//递归
void Row(pList plist)
{
if(plist == NULL)
return ;
else
{
Row(plist->next);
printf("<-%d", plist->data);
}
}
//非递归写法
void PrintTailToHead(pList plist)
{
pList pEnd = NULL;
pList pFirst = plist;
while(pEnd != plist)
{
pFirst = plist;
while(pFirst->next != pEnd)
{
pFirst = pFirst->next;
}
printf("<-%d", pFirst->data);
pEnd = pFirst;
}
printf("\n");
}
2..删除一个无头单链表的非尾节点(不能遍历这个链表)
这题的意思就是只给你一个节点的位置,要你删除该节点。
思路:首先用pos表示要删除的节点,用NextNode表示要删除节点的下一个节点。因为要删除的节点一定不是尾节点,所以它的下一个节点一定存在。我们将NextNode中的数据替换掉pos中的数据。然后将pos节点中的next域指向NextNode中next域中存放的地址,这样就达到删除的效果,最后将NextNode节点释放。(该方法叫替换删除法)
//删除一个无头单链表的非尾节点
void DelNode(pList pos)
{
pList cur = NULL;
assert(pos && pos->next);
cur = pos->next;
pos->data = cur->data;
pos->next = cur->next;
free(cur);
cur = NULL;
}
3.从无头单链表的一个节点前插入一个节点(不能遍历单链表)
这题的意思和上题差不多,只给你一个节点的地址,然后让你在该节点的前面插入一个新节点
思路:和上题差不多,因为我们不知道该节点前面一个节点的地址,所以无法直接插入。用一个指针pos指向该节点,然后用Node来记录新节点的位置,既然无法直接插入到pos的前面,那么就将Node节点插入到pos节点的后面,然后交换Node节点和pos节点中的数据,这样新节点就插入到前面了。
//3.从无头单链表的一个节点前插入一个节点(不能便利单链表)
//创建一个数据为d的新节点连接在此节点和下一个节点之间,然后交换新节点和此节点的数据;
void InsertNode(pList pos, DataType d)
{
pList node = pos;
DataType ret = 0;
assert(pos);
node = BuyNode(d);
node->next = pos->next;
pos->next = node;
ret = pos->data ;
pos->data = node->data;
node->data = ret;
}
4.单链表实现约瑟夫环
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列
思路:首先将链表的最后一个节点的next域指向首节点,这样就构成了一个环,然后从首节点开始,将首节点的编号为1,依此遍历,每遍历一个节点数字加1,假设m = 3,所以每次遇到编号为三的节点就出列(出列就和上面的删除一个非尾节点的操作一样),下一个节点从1开始,继续遍历直到链表中只有一个元素时退出。
//4.单链表实现约瑟夫环(此时已构成环)
pList JosephCycle(pList *pplist)
{
pList cur = NULL;
assert(pplist);
cur = *pplist;
while(cur->next != cur)
{
int i = 0;
pList ret = cur;
for(i = 1; i < 3; i++)
{
cur = cur->next;
}
ret = cur->next;
cur->data = ret->data;
cur->next = ret->next;
free(ret);
ret = NULL;
}
*pplist = cur;
return cur;
}
5.逆置/反转单链表
思路:
如果链表为空或者链表内只有一个节点时,不需要逆置。
如果链表有两个节点的时候,将第二个节点的next域指向第一个节点,然后将第一个节点的next域指向NULL,最后将链表指针指向第二个节点
如果链表有两个以上的结点时。使用三个指针分别指向:Fir指向第一个节点,Sec指向第二个节点,Tre指向空
1.将Tre指向Sec后面的节点。
2.将Sec指向节点的next域指向Fir。
3.将Fir指向Sec的位置,然后将Sec指向Tre,将Tre指向Sec中next域中存放的地址。
直到Sec为空时结束。然后将原链表中第一个节点的next域指向空,将指向链表的指针指向Fir的位置
//5.逆置/反转单链表
void ReverseList(pList *pplist)
{
pList Fir = NULL;
pList Sec = NULL;
pList Tre = NULL;
assert(pplist);
//链表只有一个节点时
if((*pplist)->next == NULL)
return;
//链表有两个节点时
if((*pplist)->next->next == NULL)
{
(*pplist)->next->next = *pplist;
*pplist = NULL;
return;
}
//链表有两个以上的节点时
Fir = *pplist;
Sec = Fir->next;
while(Sec != NULL)
{
Tre = Sec->next;
Sec->next = Fir;
Fir = Sec;
Sec = Tre;
}
(*pplist)->next = NULL;
*pplist = Fir;
}
6.合并两个有序的链表,使合并之后的链表依然有序。
思路:使用两个指针,一个指针Fir指向第一条链表,另一个指针Sec指向第二条链表,然后再使用一个指针NewList指向合并之后链表的首地址,使用一个指针End指向合并后链表的尾(刚开始时将End = NewList)
如果Fir为空时,直接让NewList指向第二条链表,反之,如果Sec为空时,将NewList指向第一条链表。否则执行下面的循环
比较Fir和Sec节点中元素的大小,如果Fir小的话,让End指向Fir,然后将Fir指向它后面的那个节点(Fir = Fir->next),反之如果Sec小的话,让End指向Sec,然后将Sec指向它后面的节点(Sec = Sec->next)。
如果Fir或者Sec指向空时退出。
然后查看哪一条链表不为空,将该链表直接接到新链表的后面。
//合并两个有序的单链表
pList MergeList(pList *pplist, pList *cur)
{
pList Fir = NULL;
pList Sec = NULL;
pList Newlist = NULL;
assert(pplist && cur);
Fir = *pplist;
Sec = *cur;
while(Fir != NULL && Sec != NULL)
{
if(Fir->data < Sec->data)
{
PushBack(&Newlist, Fir->data);
Fir = Fir->next;
}
else
{
PushBack(&Newlist, Sec->data);
Sec = Sec->next;
}
}
if(Fir != NULL)
{
while(Fir != NULL)
{
PushBack(&Newlist, Fir->data);
Fir = Fir->next;
}
}
if(Sec != NULL)
{
while(Sec != NULL)
{
PushBack(&Newlist, Sec->data);
Sec = Sec->next;
}
}
return Newlist;
}
7.查找链表的中间节点,要求只遍历一遍链表
思路:
如果链表为空的话,直接返回
1.如果链表中只有一个节点或两个节点,直接返回第一个节点的地址。
2.如果存在两个节点以上的节点,那么此时设置两个指针,一个指针Fir每次走一个节点,另一个指针Sec每次走两个节点。这样一直向后遍历,直到Sec走到空或者Sec->next为空时停止,此时Fir所指向的节点就是中间节点。
//遍历一遍链表,找出中间节点
pList FindNode(pList *pplist)
{
pList Fir = NULL;
pList Sec = NULL;
assert(pplist);
//空链表时
if(*pplist == NULL)
return NULL;
//链表只有一个节点时
if((*pplist)->next == NULL)
return *pplist;
//链表有多个节点
Fir = *pplist;
Sec = (*pplist)->next;
while(Sec->next && Sec->next->next)
{
Fir = Fir->next;
Sec = Sec->next->next;
}
return Fir;
}
8.遍历一遍链表,找出倒数第K个节点
思路:如果链表为空的话,直接返回。
1.如果链表没有K个节点的话,也直接返回。
2.如果链表中的节点个数大于等于K个时,设置两个指针,一个指针Sec首先走K步(也就是指向第K个节点),一个指针Fir指向链表的第一个节点。然后Fir和Sec每次遍历一个节点,直到Sec为空时退出,此时Fir指向的节点就是第K个节点。
//遍历一遍找出倒数第K个节点
pList FindKNode(pList *pplist,DataType k)
{
pList Fir = NULL;
pList Sec = NULL;
int i = 0;
assert(pplist);
Sec = *pplist;
//链表的节点数少于k个
while(Sec != NULL)
{
i++;
Sec = Sec->next;
if(i == k)
break;
}
if(i < k)
return NULL;
//链表的节点数大于等于k个
else
{
Fir = *pplist;
while(Sec != NULL)
{
Fir = Fir->next;
Sec = Sec->next;
}
}
return Fir;
}
9.删除倒数第K个节点
首先找到第K个节点,这部操作和上面一样。如过链表中没有K个节点,那么就不用删除。如果链表中有K个历节点,假设用EraseNode表示倒数的第K个节点,用Next表示EraseNode节点的下一个节点。首先将Next中的数据替代EraseNode节点中的数据,然后将EraseNode节点的next域指向Next节点的下一个节点。
//删除链表的倒数第k个节点
pList EraseKNode(pList *pplist, DataType k)
{
pList Tre = NULL;
pList Fir = NULL;
pList Sec = NULL;
int i = 0;
assert(pplist);
Sec = *pplist;
//链表的节点数少于k个
while(Sec != NULL)
{
i++;
Sec = Sec->next;
if(i == k)
break;
}
if(i < k)
{
printf("链表没有%d个节点\n", k);
return NULL;
}
//链表的节点数大于等于k个
else
{
Fir = *pplist;
while(Sec != NULL)
{
Fir = Fir->next;
Sec = Sec->next;
}
}
//删除该节点
if(Fir->next != NULL)
{
Tre = Fir->next;
Fir->data = Tre->data;
Fir->next = Tre->next;
free(Tre);
Tre = NULL;
}
return *pplist;
}
10.判断单链表是否带环,若带环,求环的长度,求环的入口点
1.判断单链表是否带环。
思路:如果链表为空的话,链表不带环。
如果链表不为空的话,设置两个指针Fir和Sec,然后开始向前移动,Fir一次移动一步,Sec一次移动两步。如果Sec或者Sec->next为空时,代表该链表没有环。如果Sec == Fir时,代表链表有环。
//判断单链表是否有环
pList IsCycle(pList plist)
{
pList slow = plist;
pList fast = plist;
//判断是否有环(用两个指针,一个每次走一步,一个每次走两步,如果有环的话,快慢指针一定会在环内的某一点相遇)
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//当慢的与快的相遇时,代表有环
if(slow == fast)
{
return slow;
}
}
return NULL;
}
2.若有环,求环的长度。
思路:首先进行进行上面的操作,如果带环的话,用lengh长度,lenght刚开始等于1。用一个指针pos标记Sec == Fir的节点的位置,t表示换的,然后让Fir从此位置开始,依此向后遍历,每遍历一个节点的话,lenght++;直到pos == Sec时退出遍历,这时lenght的大小就是环的长度。
//求环的长度
DataType Looplength(pList ret)
{
int count = 1;
pList cur = NULL;
cur = ret->next;
//计算环的长度(绕环走一圈)
while(cur != ret)
{
cur = cur->next;
count++;
}
return count;
}
3.如果有环的话,求入口点。
思路:设置两个指针ret和cur,cur指向链表的第一个节点,ret指向交点(判断链表带不带环中Fir == Sec的点)。两个指针同时向前移动,每次移动一步。当它们相遇时(ret == cur)此处就是环的入口点。
//求入口点
pList LinkInNode(pList plist, pList ret)
{
//计算入口点
//一个节点从头开始走,另一个从交点(上面判断单链表是否带环的交点)开始走,每次走一步,最后它们会在入口点相遇
pList cur = NULL;
cur = plist;
while(cur != ret)
{
cur = cur->next;
ret = ret->next;
}
return cur;//入口点
}
10.判断两个链表是否相交,若相交,求交点(假设链表不带环)
两种方法:
1.首先将其中一条链表的首尾相连成环,如果两个链表相交的话,就和上面的操作(判断链表是否带环)一样,那么换的入口点就是两条链表的交点。
2.首先遍历两条链表,记录两条链表的长度,然后用count记录下两条链表之差。设置两个指针Fir和Sec只想两个链表,首先找到比较长的那条链表,假设Fir指向的链表比较长,那么Fir先向后遍历count个节点。此时两个链表的长度相等,这时让两个指针依此向后遍历,每遍历一个节点判断一次。判断Fir 是否等于 Sec,如果在两个指针等于空之前相等的话,第一次相等的节点就是入口点
//12.判断两个链表是否相交,若相交,求交点(假设链表不带环)
//用构成环的方法
pList LinkIntersect1(pList plist, pList cur)
{
//判断两个链表是否相交(判断两个链表的尾节点是否相同)
pList Fir = plist;
pList Sec = cur;
while(Fir->next != NULL)
{
Fir = Fir->next;
}
while(Sec->next != NULL)
{
Sec = Sec->next;
}
if(Fir == Sec)
{
printf("两个链表相交\n");
}
else
{
printf("两个链表不相交\n");
return NULL;
}
//如果带环,求交点
//1.构成环
Fir->next = plist;
//2.求两个链表的交点(也就是带环链表的入口点)
return LinkInNode(cur, IsCycle(cur));
}
//不用带环的计算
pList LinkIntersect2(pList plist,pList cur)
{
int i = 0;
int j = 0;
int count = 0;
pList Fir = plist;
pList Sec = cur;
//计算出两个链表的长度
while(Fir != NULL)
{
i++;
Fir = Fir->next;
}
while(Sec != NULL)
{
j++;
Sec = Sec->next;
}
//计算出长的链表比短的链表多出几个节点,那么长的链表就先走几步,这样两个链表就是相同的长度
Fir = plist;
Sec = cur;
if(i > j)
{
count = i - j;
while(count--)
{
Fir = Fir->next;
}
}
else
{
count = j - i;
while(count--)
{
Sec = Sec->next;
}
}
//然后两个链表同时前进,每走一步比较一次
while(Fir != NULL && Sec != NULL)
{
if(Fir == Sec)
return Fir;
Fir = Fir->next;
Sec = Sec->next;
}
return NULL;
}
11.判断两个链表是否相交,若相交,求交点(假设链表可能带环)
1.如果两条链表都不带环,只有情况1和情况4,再判断两条链表是否相交
用上面第10个标题中判断两个不带环的链表是否相交的方法做。
2.如果一条链表带环,一条链表不带环。则是情况2.
这种情况一定不相交
3.如果两个链表都有环的话,则是情况3、5、6;
两条链表带环不相交
两条链表带环相交(交点一种情况是在环外,另一种是交点在环内且交点有两个)
首先判断入口点是否相同,如果入口点相同的话,是情况5的相交
如果入口点不相同,那么取链表1的入口点,然后遍历一遍链表2的环,如果遍历的过程中有节点与链表1的入口点相同,代表两条链表相交,为情况6.如果没有节点与链表1的入口点相同的话,代表两条链表不相交,是情况3.
pList LinkInterLoop(pList plist, pList cur)
{
pList Fir = IsCycle(plist);
pList Sec = IsCycle(cur);
pList node = Fir->next;
int i = 0; //(记录两个单链表是否在同一个环内,在的话为1,不在为0)
//先判断两个链表是否带环
if(Fir && Sec)
{
printf("这两个单链表带环");
//1.判断这两个单链表是否带相同的环(如果两个有环单链表的相遇在同一个环内)
while(node != Fir )
{
if(node == Sec || node->next == Sec)//在环内找到另一个单链表的相遇点
{
i = 1;
break;
}
node = node->next;
}
//如果有入口点相同且两个链表带有相同的环
if(i == 1 && LinkInNode(plist, Fir) == LinkInNode(cur, Sec))
{
pList endnode = LinkInNode(plist, Fir);
endnode->next = NULL;
return LinkIntersect1(plist, cur);
}
//如果两个链表有相同的环但入口点不同时,两个链表的交点就是他们的入口点
if(i == 1 && LinkInNode(plist, Fir) != LinkInNode(cur, Sec))
{
return LinkInNode(plist,Fir);
}
}
//当其中一个带环,另一个不带环时.没有交点
if(Fir == NULL || Sec == NULL)
{
return NULL;
}
//两个都不带环
if(Fir == NULL && Sec == NULL)
{
return LinkIntersect1(plist, cur);
}
//其他
return NULL;
}
12.复制一个复杂链表
//复制一个复杂链表
pNewList* CopLinklist(pNewList *pplist)
{
pNewList *cur = pplist;
pNewList *NewList = NULL;
pNewList *ret = NULL;
//1.将原链表的每个节点后面都接一个相同的节点
while(cur)
{
NewList = (pNewList *)malloc(sizeof(struct NewNode));
if(NewList == NULL)
{
printf("申请内存失败\n");
return NULL;
}
NewList->data = cur->data;
NewList->next = cur->next;
cur->next = NewList;
cur = NewList->next;
}
//2.将随机指针域复制下来
cur = pplist;
while(cur)
{
ret = cur->next;
if(NULL == cur->random)
ret->random = NULL;
else
ret->random = cur->random->next;
cur = ret->next;
}
//3.将原节点后面的节点拆下来
NewList = (pplist)->next;//拆之前,记住新链表的地址
cur = pplist;
ret = cur->next;
while(ret)
{
cur->next = ret->next;
cur = ret;
ret = cur->next;
}
cur->next = NULL;
return NewList;
}
13.求两个已排序单链表中的相同数据
因为这两个单链表已经有序,所以我们可以依此遍历比较。
思路:用两个指针l1和l2来指向两条单链表,循环下面的操作
1.如果l1指向的节点大于l2中的数据,l2向后移动一个节点
2.如果l1指向的节点小于l2中的数据,l1向后移动一个节点
3.否则代表l1中的数据与l2中的数据相等。直接遍历该节点,然后将l1和2都向后移动。
如果有一条链表走到空时,直接退出循环。
//求两个以排序单链表的中相同的数据
void UnionSet(Node *l1, Node *l2)
{
LinkBubbleSort(&l1);
LinkBubbleSort(&l2);
while(l1 && l2)
{
if(l1->data > l2->data)
l2 = l2->next;
else if(l1->data < l2->data)
l1 = l1->next;
else
{
printf("%d\n", l1->data);
l1 = l1->next;
l2 = l2->next;
}
}
}
LinkList.c
#include"Linklist.h"
void TextPushPop(pList *pplist)
{
pNode NewNode = NULL;
assert(pplist);
lnitLinkList(pplist);
PushBack(pplist, 1);
PushBack(pplist, 2);
PushBack(pplist, 3);
PushFront(pplist, 4);
PrintLinklist(*pplist);
PopBack(pplist);
PrintLinklist(*pplist);
PopFront(pplist);
PopFront(pplist);
PrintLinklist(*pplist);
}
void LinkFindInsert(pList plist)
{
pList NewNode = NULL;
NewNode = Find(plist, 2);
Insert(&plist, NewNode, 5);
PrintLinklist(plist);
}
void LinkErase(pList *pplist)
{
PushBack(pplist, 2);
PushBack(pplist, 3);
PushBack(pplist, 4);
PushFront(pplist, 1);
Erase(pplist, Find(*pplist,3));
PrintLinklist(*pplist);
Erase(pplist, Find(*pplist,1));
PrintLinklist(*pplist);
Erase(pplist, Find(*pplist,4));
PrintLinklist(*pplist);
RemoveAll(pplist, 1);
PrintLinklist(*pplist);
}
void LinkOrder(pList plist)
{
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 4);
PushFront(&plist, 1);
Row(plist);
printf("\n");
PrintTailToHead(plist);
}
void DelpList(pList plist)
{
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 4);
PushFront(&plist, 1);
DelNode(Find(plist, 3));
InsertNode(Find(plist,1), 5);
ReverseList(&plist);
PrintLinklist(plist);
}
void LinkYsfh(pList *pplist)
{
pList ret = NULL;
PushBack(pplist, 2);
PushBack(pplist, 3);
PushBack(pplist, 4);
PushFront(pplist, 1);
Find(*pplist, 4)->next = *pplist;
ret = JosephCycle(pplist);
printf("最后剩余的为%d\n", ret->data);
}
void LinkSort(pList plist)
{
pList cur = NULL;
pList ret = NULL;
PushBack(&plist, 2);
PushBack(&plist, 4);
PushBack(&plist, 6);
PushFront(&plist, 0);
PushBack(&cur, 3);
PushBack(&cur, 5);
PushBack(&cur, 7);
PushFront(&cur, 1);
ret = MergeList(&plist, &cur);
LinkBubbleSort(&plist);
PrintLinklist(ret);
}
void LinkFind(pList plist)
{
pList cur = NULL;
int i = 0;
scanf("%d", &i);
PushBack(&plist, 1);
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 4);
cur = FindNode(&plist);
cur = FindKNode(&plist, i);
if(cur != NULL)
printf("倒数第%d个数为%d\n", i, cur->data);
else
printf("链表没有%d个节点\n", i);
EraseKNode(&plist, i);
PrintLinklist(plist);
}
void Linkloop(pList plist)
{
pList cur = NULL;
PushBack(&plist, 1);
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 4);
PushBack(&plist, 5);
PushBack(&plist, 6);
PushBack(&plist, 7);
Find(plist, 7)->next = Find(plist, 5);
cur = IsCycle(plist);
if(cur == NULL)
printf("改单链表不带环\n");
else
{
printf("带环\n");
printf("环的长度为%d\n", Looplength(cur));
printf("入口点为%d\n", LinkInNode(plist, cur)->data);
}
}
void LinkInter(pList plist)
{
pList cur = NULL;
pList ret = NULL;
PushBack(&cur, 8);
PushBack(&cur, 9);
PushBack(&cur, 10);
PushBack(&plist, 1);
PushBack(&plist, 2);
PushBack(&plist, 3);
PushBack(&plist, 4);
PushBack(&plist, 5);
PushBack(&plist, 6);
PushBack(&plist, 7);
PushBack(&plist, 11);
PushBack(&plist, 12);
PushBack(&plist, 13);
Find(cur, 10)->next = Find(plist, 6);
Find(plist, 13)->next = Find(plist, 11);
ret = LinkIntersect1(plist, cur);
ret = LinkIntersect2(plist,cur);
ret = LinkInterLoop(plist, cur);
if(ret != NULL)
printf("交点为%d\n",ret->data );
else
printf("两个链表不相交\n");
}
void FindSameNode()
{
pList cur = NULL;
pList ret = NULL;
PushBack(&cur, 8);
PushBack(&cur, 9);
PushBack(&cur, 10);
PushBack(&ret, 9);
PushBack(&ret, 10);
PushBack(&ret, 11);
PushBack(&ret, 12);
UnionSet(cur, ret);
}
void Text()
{
pNewList Node1 ;
pNewList Node2 ;
pNewList Node3 ;
pNewList Node4;
pNewList *NewNode = NULL;
Node1.data = 1;
Node1.next = &Node2;
Node1.random = &Node3;
Node2.data = 2;
Node2.next = &Node3;
Node2.random = &Node1;
Node3.data = 3;
Node3.next = &Node4;
Node3.random = &Node3;
Node4.data = 4;
Node4.random = NULL;
Node4.next = NULL;
NewNode = CopLinklist(&Node1);
}
int main()
{
List *pHead = NULL;
TextPushPop(&pHead);
LinkFindInsert(pHead);
LinkErase(&pHead);
LinkOrder(pHead);
DelpList(pHead);
LinkYsfh(&pHead);
LinkSort(pHead);
LinkFind(pHead);
Linkloop(pHead);
LinkInter(pHead);
FindSameNode();
Text();
DestroyLinkList(&pHead);
return 0;
}