三:单链表中环的检测、环的入口结点和环的长度

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013139008/article/details/83242764

单链表的创建、打印和释放见博客 一:单链表的创建、打印和释放

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;
}

猜你喜欢

转载自blog.csdn.net/u013139008/article/details/83242764