数据结构与算法系列:链表

Posted 朔方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法系列:链表相关的知识,希望对你有一定的参考价值。

 

 

链表定义:

1 // 链表结点
2 struct ListNode
3 {
4     int          m_nValue;
5     ListNode*    m_pNext;
6 };

常见问题:

#include <iostream>
#include <stack>


// 输入数据
int Read()
{
    int value;
    std::cin >> value;
    return value;
}


// 创建链表
ListNode* CreateList(int nLen)
{
    ListNode* pHead = NULL;
    ListNode* pCurr = NULL;
    ListNode* pNext = NULL;

    for (int nIdx = 0; nIdx < nLen; ++nIdx)
    {
        pNext = new ListNode;
        pNext->m_nValue = Read();
        pNext->m_pNext = NULL;

        if (NULL == pHead)
        {
            pHead = pNext;
        }
        else
        {
            pCurr->m_pNext = pNext;
        }

        pCurr = pNext;
    }

    if (NULL == pCurr)
    {
        delete pCurr;
        pCurr = NULL;
    }

    if (NULL == pNext)
    {
        delete pNext;
        pNext = NULL;
    }

    return pHead;
}


// 计算链表长度
int GetListLength(ListNode* pHead)
{
    unsigned int nLength = 0;

    ListNode* pNode = pHead;
    while (NULL != pNode)
    {
        ++nLength;
        pNode = pNode->m_pNext;
    }

    return nLength;
}


// 向链表的末尾添加一个结点
// pHead 是一个指向指针的指针,由于要修改头结点,必须采用指向指针的指针
void AddToTail(ListNode** pHead, int value)
{
    ListNode* pNew = new ListNode;
    pNew->m_nValue = value;
    pNew->m_pNext = NULL;

    if (NULL == *pHead)
    {
        *pHead = pNew;
    }
    else
    {
        ListNode* pNode = *pHead;

        while (NULL != pNode->m_pNext)
        {
            pNode = pNode->m_pNext;
        }

        pNode->m_pNext = pNew;
    }
}


// 删除头结点
// pHead 是一个指向指针的指针,由于要修改头结点,必须采用指向指针的指针
void RemoveHead(ListNode** pHead)
{
    if (NULL != *pHead)
    {
        if (NULL == (*pHead)->m_pNext)
        {
            pHead = NULL;
        }
        else
        {
            ListNode* pNode = *pHead;
            *pHead = (*pHead)->m_pNext;
        }
    }
}


// 删除指定结点
// pHead 是一个指向指针的指针,由于要修改头结点,必须采用指向指针的指针
void RemoveNode(ListNode** pHead, int value)
{
    if (NULL == pHead || NULL == *pHead)
    {
        return;
    }

    ListNode* pToBeDeleted = NULL;
    if (value == (*pHead)->m_nValue)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;

        while (NULL != pNode->m_pNext && value != pNode->m_pNext->m_nValue)
        {
            pNode = pNode->m_pNext;
        }

        if (NULL != pNode->m_pNext && value == pNode->m_pNext->m_nValue)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

    if (NULL == pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}


// 在O(1)时间删除链表结点
void DeleteNode(ListNode** pHead, ListNode* pToBeDeleted)
{
    if (NULL == pHead || NULL == pToBeDeleted)
    {
        return;
    }

    // 要删除的结点不是尾结点
    if (NULL != pToBeDeleted->m_pNext)
    {
        ListNode* pNext = pToBeDeleted->m_pNext;
        pToBeDeleted->m_nValue = pNext->m_nValue;
        pToBeDeleted->m_pNext = pNext->m_pNext;

        delete pNext;
        pNext = NULL;
    }
    // 链表只有一个结点
    else if (*pHead == pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
        *pHead = NULL;
    }
    // 链表有多个结点,要删除的结点是尾结点
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != pToBeDeleted)
        {
            pNode = pNode->m_pNext;
        }

        pNode->m_pNext = NULL;
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}


// 从头到尾打印链表
void PrintList(ListNode* pHead)
{
    ListNode* pNode = pHead;
    while (NULL != pNode)
    {
        std::cout << pNode->m_nValue << "\t";
        pNode = pNode->m_pNext;
    }

    std::cout << std::endl;
}


// 从尾到头打印链表
// 1、用栈实现
// 2、递归实现
void PrintListReversingly_Iteratively(ListNode* pHead)
{
    std::stack<ListNode*> nodes;

    ListNode* pNode = pHead;
    while (NULL != pNode)
    {
        nodes.push(pNode);
        pNode = pNode->m_pNext;
    }

    while (!nodes.empty())
    {
        pNode = nodes.top();
        std::cout << pNode->m_nValue << "\t";
        nodes.pop();
    }

    std::cout << std::endl;
}


void PrintListReversingly_Recursively(ListNode* pHead)
{
    if (NULL != pHead)
    {
        if (NULL != pHead->m_pNext)
        {
            PrintListReversingly_Recursively(pHead->m_pNext);
        }
    }

    std::cout << pHead->m_nValue << "\t";
}


// 链表中倒数第 k 个结点
// 用两个指针
ListNode* FindKthToTail(ListNode* pHead, unsigned int k)
{
    if (NULL == pHead || 0 == k)
    {
        return NULL;
    }

    ListNode* pAhead = pHead;
    ListNode* pBehind = NULL;

    for (int nIdx = 0; nIdx < (int)k - 1; ++nIdx)
    {
        if (NULL != pAhead->m_pNext)
        {
            pAhead = pAhead->m_pNext;
        }
        else
        {
            return NULL;
        }
    }

    pBehind = pHead;
    while (NULL != pAhead->m_pNext)
    {
        pAhead = pAhead->m_pNext;
        pBehind = pBehind->m_pNext;
    }

    return pBehind;
}



// 链表的中间结点
ListNode* FindMidNode(ListNode* pHead)
{
    if (NULL == pHead)
    {
        return NULL;
    }

    ListNode* pAhead = pHead;
    ListNode* pBehind = pHead;

    while (NULL != pAhead->m_pNext && NULL != pAhead->m_pNext->m_pNext)
    {
        pAhead = pAhead->m_pNext->m_pNext;
        pBehind = pBehind->m_pNext;
    }

    return pBehind;
}


// 判断单链表是否有环
bool IsLoop(ListNode* pHead)
{
    bool bLoop = false;

    if (NULL == pHead)
    {
        return bLoop;
    }

    ListNode* pAhead = pHead;
    ListNode* pBehind = pHead;

    while (NULL != pAhead->m_pNext && NULL != pAhead->m_pNext->m_pNext && pAhead != pBehind)
    {
        pAhead = pAhead->m_pNext->m_pNext;
        pBehind = pBehind->m_pNext;
    }

    if (pAhead == pBehind)
    {
        bLoop = true;
    }

    return bLoop;
}


// 反转链表
// 1、迭代实现
// 2、递归实现
ListNode* ReverseList(ListNode* pHead)
{
    ListNode* pReversedHead = NULL;
    ListNode* pNode = pHead;
    ListNode* pPrev = NULL;

    while (NULL != pNode)
    {
        ListNode* pNext = pNode->m_pNext;

        if (NULL == pNext)
        {
            pReversedHead = pNode;
        }

        pNode->m_pNext = pPrev;

        pPrev = pNode;
        pNode = pNext;
    }

    return pReversedHead;
}


ListNode* ReverseList_Recursively(ListNode* pHead)
{
    if (NULL == pHead || NULL == pHead->m_pNext)
    {
        return pHead;
    }
    
    ListNode* pNode = pHead;
    ListNode* pReversedHead = ReverseList_Recursively(pNode->m_pNext);
    pNode->m_pNext->m_pNext = pNode;
    pNode->m_pNext = NULL;

    return pReversedHead;
}


// 合并两个有序链表
ListNode* MergeList(ListNode* pHead1, ListNode* pHead2)
{
    if (NULL == pHead1)
    {
        return pHead2;
    }
    else if (NULL == pHead2)
    {
        return pHead1;
    }

    ListNode* pMergeHead = NULL;
    if (pHead1->m_nValue < pHead2->m_nValue)
    {
        pMergeHead = pHead1;
        pMergeHead->m_pNext = MergeList(pHead1->m_pNext, pHead2);
    }
    else
    {
        pMergeHead = pHead2;
        pMergeHead->m_pNext = MergeList(pHead1, pHead2->m_pNext);
    }

    return pMergeHead;
}


// 两个链表的第一个公共结点
ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)
{
    int nLength1 = GetListLength(pHead1);
    int nLength2 = GetListLength(pHead2);
    
    int nLengthDif = nLength1 - nLength2;
    ListNode* pListHeadLong = pHead1;
    ListNode* pListHeadShort = pHead2;

    if (nLength1 < nLength2)
    {
        nLengthDif = nLength2 - nLength1;
        pListHeadLong = pHead2;
        pListHeadShort = pHead1;
    }

    for (int nIdx = 0; nIdx < nLengthDif; ++nIdx)
    {
        pListHeadLong = pListHeadLong->m_pNext;
    }

    while (NULL != pListHeadLong && NULL != pListHeadShort
        && pListHeadLong != pListHeadShort)
    {
        pListHeadLong = pListHeadLong->m_pNext;
        pListHeadShort = pListHeadShort->m_pNext;
    }

    // 得到第一个公共结点
    ListNode* pFirstCommonNode = pListHeadLong;

    return pFirstCommonNode;
}

 

以上是关于数据结构与算法系列:链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法什么是链表?并用代码手动实现一个单向链表

大厂面试系列:数据结构与算法等

重学数据结构与算法系列:链表及其应用

备战秋招冲击大厂Java面试题系列—数据结构与算法

数据结构与算法系列:面试题

『数据结构与算法』链表(单链表双链表环形链表):原理与Java实现