链表:
一种链式存储的线性表,用一组地址任意的存储单元存放线性表的 数据元素,称存储单元为一个节点。链表可以分为带头结点的单链表和不带头结点的单链表。此片文章是不带头结点的单链表
上图为单链表结构,每个节点均有数据域data和指向下一个节点的指针域pNext。
链表优缺点:在执行插入和删除操作是不需要移动元素,但在查询时必须通过头结点进行查询比较麻烦。由于存放元素的地址不连续。因此有可能造成空间浪费。
链表结构c语言描述
typedef int DataType;
typedef struct SList
{
DataType data;
struct SList* pNext;
}SList;
函数声明:
void Init(SList **ppHead);//初始化
SList* BuyNewNode(DataType data);//申请新节点
void PushBack(SList **ppHead, DataType data);//头插
void myprintf(SList *ppHead);//打印函数
void DestroyLinkList(SList **ppHead);//销毁
void SListPopBack(SList** pHead);//尾删
void SListPushFront(SList** pHead, DataType data);//头插
void SListPopFront(SList** pHead);//头删
//面试题
void PrintListFromTail2Front(SList* pHead);// 从尾到头打印单链表
void DeleteListNotTail(SList* pos);// 删除单链表的非尾结点,不能遍历链表
void InsertPosFront(SList* pos, DataType data);// 在单链表非头结点前插入新节点,要求不能遍历链表
SList* JosephCircle(SList* pHead, int M);// 用单链表模拟实现约瑟夫环
void BubbleSort(SList* pHead);// 用冒泡排序对单链表进行排序
SList* FindMiddleNode(SList* pHead);// 查找单链表的中间结点,要求只能遍历一次链表
SList* FindLastKNode(SList* pHead, int K);// 查找单链表的倒数第K个结点,要求只能遍历一次链表
void ReverseList(SList** pHead);// 单链表的逆置尾插
SList* ReverseListOP(SList* pHead);//头插
SList* MergeList(SList* pHead1, SList* pHead2);// 合并两个有序链表,合并成功后依然有序
SList* HasListCircle(SList* pHead);// 检测单链表是否带环
int GetCircleLen(SList* pHead);// 求环的长度
SList* GetEnterNode(SList* pHead, SList* pMeetNode);// 求环的入口点
int IsListCross(SList* pHead1, SList* pHead2);// 判断两个单链表是否相交(链表不带环)
SList* GetCrossNode(SList* pHead1, SList* pHead2);// 若相交,求交点
int IsListCrossWithCircle(SList* pHead1, SList* pHead2);// 检测两个链表是否相交,链表可能带环
函数的实现:
#include"SList.h"
#include<stdio.h>
#include<malloc.h>
void Init(SList **ppHead)//初始化
{
*ppHead = NULL;
}
SList* BuyNewNode(DataType data)//申请新节点
{
SList *pNewNode = (SList*)malloc(sizeof(SList));
if (pNewNode == NULL)
{
assert(0);
return NULL;
}
assert(pNewNode);
pNewNode->data = data;
pNewNode->pNext = NULL;
return pNewNode;
}
void PushBack(SList **ppHead, DataType data)//尾插
{
SList *pNewNode = BuyNewNode(data);//如果头结点不存在用申请的节点来创建头结点
if (*ppHead == NULL)
{
*ppHead = pNewNode;
}
else
{
SList *pCur = *ppHead;
while (pCur->pNext != NULL)
{
pCur = pCur->pNext;
}
pCur->pNext = pNewNode;
pNewNode->pNext = NULL;
}
}
void DestroyLinkList(SList **ppHead)//销毁
{
SList *Cur = *ppHead;
SList *Pre = NULL;
while (Cur)
{
Pre = Cur->pNext;
free(Cur);
Cur = Pre;
}
ppHead = NULL;
}
void SListPopBack(SList** ppHead)//尾删
{
assert(ppHead);
if (*ppHead == NULL)
{
return;
}
SList* cur = *ppHead;
SList* pre = NULL;
while (cur->pNext!=NULL)
{
pre = cur;
cur = cur->pNext;
}
free(cur);
cur=NULL;
pre->pNext = NULL;
}
void SListPushFront(SList** ppHead, DataType data)//头插
{
SList *pNewNode = BuyNewNode(data);
if (ppHead == NULL)
{
*ppHead = pNewNode;
}
else
{
pNewNode->pNext = *ppHead;
*ppHead = pNewNode;
}
}
void SListPopFront(SList** ppHead)//头删
{
SList* pDel = NULL;
assert(ppHead);
if (NULL == *ppHead)
return;
pDel = *ppHead;
*ppHead = pDel->pNext;
free(pDel);
}
SList* SListFind(SList* pHead, DataType data)//查找某个节点
{
SList* pCur = pHead;
while (pCur)
{
if (data == pCur->data)
return pCur;
pCur = pCur->pNext;
}
return NULL;
}
SList* SListBack(SList* pHead)//获取最后一个节点
{
SList* pPreCur = NULL;
SList* pCur = pHead;
while (pCur)
{
pPreCur = pCur;
pCur = pCur->pNext;
}
return pPreCur;
}
void PrintListFromTail2Front(SList* ppHead)// 从尾到头打印单链表
{
if (ppHead != NULL)
{
PrintListFromTail2Front(ppHead->pNext);
printf("%d", ppHead->data);
}
}
void DeleteListNotTail(SList* pos)// 删除单链表的非尾结点,不能遍历链表
{
assert(pos);
if (pos == NULL || pos->pNext == NULL)//该节点和下一个节点不能为空
{
return;
}
SList*cur = NULL;
cur = pos->pNext;
pos->data = cur->data;
pos->pNext = cur->pNext;
free(cur);
}void InsertPosFront(SList* pos, DataType data)// 在单链表非头结点前插入新节点,要求不能遍历链表
{
SList*pNewNode = NULL;
if (pos ==NULL)
return;
pNewNode = BuyNewNode(pos->data);
pNewNode->pNext = pos->pNext;
pos->pNext = pNewNode;
pos->data = data;
}
SList* JosephCircle(SList* pHead, int M)// 用单链表模拟实现约瑟夫环
{
SList*Tail = pHead;
SList*cur = NULL;
while (Tail->pNext != NULL)
{
Tail = Tail->pNext;
}
Tail->pNext =pHead;
cur = pHead;
while (cur->pNext != cur)
{
int k = M;
SList*next = NULL;
while (--k)
cur = cur->pNext;
next = cur->pNext;//伪删除是指并不是将这个节点删除,而是将该节点的data改为下一个节点的data.
cur->data = next->data;
cur->pNext = next->pNext;
free(next);
}
return cur;
}
void BubbleSort(SList* pHead)// 用冒泡排序对单链表进行排序
{
SList* pTailNode = NULL;
int isChange = 0;
if (NULL == pHead || NULL == pHead->pNext)//链表为空或只有一个节点不同排序
return;
while (pHead != pTailNode)//排序轮数
{
SList* pPre = pHead;
SList* pCur = pPre->pNext;
isChange = 0;
// 冒泡方法
while (pCur != pTailNode)//每一轮需要进行的排序次数
{
if (pPre->data > pCur->data)
{
DataType temp = pPre->data;
pPre->data = pCur->data;
pCur->data = temp;
isChange = 1;
}
pPre = pCur;
pCur = pCur->pNext;
}
if (!isChange)//如果次序正常则不进行这次排序
return;
pTailNode = pPre;//当一遍排序结束后最后一个节点不同在排序将为指针向前移动
}
}
SList* FindMiddleNode(SList* pHead)// 查找单链表的中间结点,要求只能遍历一次链表
{
SList *slow = pHead;
SList*fast = pHead;
while (fast&&fast->pNext)
{
slow = slow->pNext;
fast = fast->pNext->pNext;
}
return slow;
}
SList* FindLastKNode(SList* ppHead, int K)// 查找单链表的倒数第K个结点,要求只能遍历一次链表
{
SList *pFast = ppHead;
SList *pSlow = ppHead;
if (ppHead == NULL || K <= 0)
return 0;
while (--K)
{
if (pFast == NULL)
return NULL;
pFast = pFast->pNext;
}
while (pFast->pNext!=NULL)
{
pFast = pFast->pNext;
pSlow = pSlow->pNext;
}
return pSlow;
}
void ReverseList(SList** ppHead)// 单链表的逆置
{
SList *pCur = NULL;
SList *pPre = NULL;
SList *pNext = NULL;
pCur = *ppHead;
while (pCur)
{
pNext = pCur->pNext;
pCur->pNext = pPre;//将取下来的节点直接连在pPre的前面
pPre = pCur;
pCur = pNext;
}
*ppHead = pPre;
}
SList* MergeList(SList* pHead1, SList* pHead2)// 合并两个有序链表,合并成功后依然有序
{
SList *pNewNode = NULL;
SList *pTail = NULL;//用来保证新节点不用动因此先插一个节点;
SList*pL1 = pHead1;
SList*pL2 = pHead2;
if (pHead1 == NULL)
return pHead2;
if (pHead2 == NULL)
return pHead2;
if (pL1->data <= pL2->data)//先存放一个节点
{
pNewNode = pTail = pL1;
pL1 = pL1->pNext;
}
else
{
pNewNode = pTail = pL2;
pL2 = pL2->pNext;
}
while (pL1&&pL2)
{
if (pL1->data <= pL2->data)
{
pTail->pNext = pL1;
pL1 = pL1->pNext;
}
else
{
pTail->pNext= pL2;
pL2 = pL2->pNext;
}
pTail = pTail->pNext;
}
if (pL1)
pTail->pNext = pL1;
else
pTail->pNext = pL2;
return pNewNode;
}
SList* HasListCircle(SList* ppHead)// 检测单链表是否带环
{
SList *pFast = ppHead;
SList *pSlow = ppHead;
while (pFast&&pFast->pNext)//肯定会在环内相遇
{
pFast = pFast->pNext->data;
pSlow = pSlow->pNext;
if (pFast == pSlow)
return pFast;
}
return NULL;
}
int GetCircleLen(SList* pMeetNode)// 求环的长度
{
int count = 1;
SList *pCur = pMeetNode;
if (pMeetNode == NULL)
return 0;
while (pCur->pNext != pMeetNode)
{
count++;
pCur = pCur->pNext;
}
return count;
}
SList* GetEnterNode(SList* ppHead, SList* pMeetNode)// 求环的入口点
{
SList *pH = ppHead;
SList *pM = pMeetNode;
if (ppHead == NULL || pMeetNode == NULL)
return NULL;
while (pH!=pM)//相遇点和从头开始的节点一定会在入口点相交
{
pH = pH->pNext;
pM = pM->pNext;
}
return pM;
}
int IsListCross(SList* pHead1, SList* pHead2)// 判断两个单链表是否相交(链表不带环)
{
SList*pH1 = pHead1;
SList*pH2 = pHead2;
if (pHead1 == NULL || pHead2 == NULL)
return 0;
while (pH1)
pH1 = pH1->pNext;
while (pH2)
pH2 = pH2->pNext;
return pH1 == pH2;
}
SList* GetCrossNode(SList* pHead1, SList* pHead2)// 若相交,求交点
{
SList *pH1 = pHead1;
SList *pH2 = pHead2;
int count = 0;
int size1 = 0;
int size2 = 0;
while (pH1 != NULL)
{
pH1 = pH1->pNext;
size1++;
}
while (pH2 != NULL)
{
size2++;
pH2 = pH2->pNext;
}
count = size1 - size2;
if (count > 0)
{
while (count--)
pH1 = pH1->pNext;
}
else
{
while (count++)
pH2 = pH2->pNext;
}
while (pH1 != pH2)
{
pH1 = pH1->pNext;
pH2 = pH2->pNext;
}
return pH1;
}
int IsListCrossWithCircle(SList* pHead1, SList* pHead2)
{
SList* pMeetNode1 = NULL;
SList* pMeetNode2 = NULL;
if (NULL == pHead1 || NULL == pHead2)
return 0;
pMeetNode1 = HasListCircle(pHead1);
pMeetNode2 = HasListCircle(pHead2);
if (NULL == pMeetNode1 && NULL == pMeetNode2)//不带环相交
{
SList* pTailNode1 = pHead1;
SList* pTailNode2 = pHead2;
while (pTailNode1->pNext)
pTailNode1 = pTailNode1->pNext;
while (pTailNode2->pNext)
pTailNode2 = pTailNode2->pNext;
if (pTailNode1 == pTailNode2)
return 1;
}
else if (pMeetNode1 && pMeetNode2)//带还相交
{
SList* pCur = pMeetNode1;
while (pCur->pNext != pMeetNode1)
{
if (pCur == pMeetNode2)
return 2;
pCur = pCur->pNext;
}
if (pCur == pMeetNode2)
return 2;
}
return 0;
}
void myprintf(SList *ppHead)
{
SList *pCur = ppHead;
while (pCur != NULL)
{
printf("%d", pCur->data);
pCur = pCur->pNext;
}
}