单链表的创建、打印和释放见博客 一:单链表的创建、打印和释放
1. 创建带环单链表
/**
* 创建带环单链表
* @param[in] aArray[] int :单链表结点值的数组
* @param[in] iCnt int :单链表结点值的数组长度
* @param[in] iIdx int :单链表环入口结点值在数组中的位置
*/
NODE_t * CreateCircleSList(int aArray[], int iCnt, int iIdx) {
NODE_t *pList = CreateArraySList(aArray, iCnt);
if (pList == NULL) {
printf("CreateArraySList error\n");
return NULL;
}
/* 如果环的入口结点超出结点数,环的入口设置为最后一个结点 */
if (iIdx > iCnt) {
iIdx = iCnt;
}
/* 遍历找到单链表的第iIdx个结点和最后一个结点 */
NODE_t *pLast = NULL; // 保存单链表的最后一个结点
NODE_t *pNode = NULL; // 保存单链表的第iIdx个结点
NODE_t *pHead = pList->pNext; // pHead指向单链表的第一个有效结点
int iNo = 0;
while (pHead != NULL) {
iNo++;
if (iNo == iIdx) {
pNode = pHead;
}
pLast = pHead;
pHead = pHead->pNext;
}
pLast->pNext = pNode;
return pList;
}
2. 检测单链表中是否存在环
/**
* 检测单链表中是否存在环
* 使用快慢指针,慢指针步长为1,快指针步长为2,
* 在单链表遍历结束前,快慢指针相遇,则存在环
* 相遇时的结点应该是大于进入环之前的结点个数,且是环的结点数的整数倍的最小值
* @return NULL :不存在环
* @return 快慢指针相遇结点的地址
*/
NODE_t * IsSListLoop(NODE_t *pList) {
if (pList == NULL || pList->pNext == NULL) {
printf("single list is empty\n");
return NULL;
}
/*
NODE_t *pSlow = pList->pNext; // 慢指针从头结点走一步
NODE_t *pFast = pSlow->pNext; // 快指针从头结点走两步
while (pSlow != NULL && pFast != NULL) {
if (pSlow == pFast) {
return pSlow;
}
pSlow = pSlow->pNext;
pFast = pFast->pNext;
if (pFast != NULL) {
pFast = pFast->pNext;
}
}
return NULL;
*/
NODE_t *pSlow = pList;
NODE_t *pFast = pList;
while (pFast != NULL && pFast->pNext != NULL) {
pSlow = pSlow->pNext;
pFast = pFast->pNext->pNext;
if (pSlow == pFast) {
break;
}
}
return (pFast == NULL || pFast->pNext == NULL) ? NULL : pSlow;
}
3. 返回环的入口结点指针
/**
* 找到单链表环的入口结点并返回
* 判断单链表中是否存在环,若存在,返回判断环是否存在时快慢指针的相遇结点
* 然后从头结点和相遇结点同时按照步长为1移动,
* 当两个结点再次相遇时,相遇结点即是环的入口结点
*/
NODE_t * FindLoopSListEnter(NODE_t *pList) {
NODE_t *pMeet = IsSListLoop(pList);
if (pMeet == NULL) {
printf("single list has no loop\n");
return NULL;
}
NODE_t *pHead = pList;
while (pMeet != pHead) {
pHead = pHead->pNext;
pMeet = pMeet->pNext;
}
return pHead;
}
4. 求带环单链表环的长度
/**
* 求带环单链表的环的长度
*/
int FindSListLoopLen(NODE_t *pList) {
NODE_t *pMeet = IsSListLoop(pList);
if (pMeet == NULL) {
printf("single list has no loop\n");
return 0;
}
NODE_t *pSlow = pMeet;
NODE_t *pFast = pMeet;
int iLoopLen = 0;
do {
pSlow = pSlow->pNext;
pFast = pFast->pNext->pNext;
iLoopLen++;
} while (pSlow != pFast);
return iLoopLen;
}
5. 测试代码
int main() {
/* 创建带环单链表,判断单链表是否带环 */
NODE_t *pList3 = CreateCircleSList(aArray, 6, 3);
NODE_t *pMeet = IsSListLoop(pList3);
if (pMeet) {
printf("single list has loop\n");
}
else {
printf("single list has no loop\n");
}
/* 求单链表环的入口结点 */
NODE_t *pEnter = FindLoopSListEnter(pList3);
if (pEnter != NULL) {
printf("enter node value: %d\n", pEnter->iData);
}
/* 求单链表环的长度 */
int iLoopLen = FindSListLoopLen(pList3);
printf("single list loop len: %d\n", iLoopLen);
//FreeSList(pList3); 因为该单链表带环,所以不能使用上面方法释放该单链表
return 0;
}