鏈表的基本操作——以及鏈表面試題

#define _CRT_SECURE_NO_WARNINGS

#include"list.h"
#include<assert.h>

void SListInit(PNode* pHead)  //鏈表初始化
{
    assert(pHead);
    *pHead = NULL;
}

PNode BuySListNode(DataType data)//申請一個結點
{
    PNode PNewNode = (PNode )malloc(sizeof(Node));
    if (PNewNode == NULL)
    {
        return NULL;
    }
    PNewNode->_pNext = NULL;
    PNewNode->_data = data;
    return PNewNode;
}

void SListPushBack(PNode* pHead, DataType data)// 尾插 
{
    assert(pHead);
    if (NULL == pHead)
    {
        /*pHead = BuySListNode(data);*/
        return;
    }
    else
    {
        PNode pCur = NULL;
        pCur = *pHead;
        while (pCur->_pNext)
        {
            pCur = pCur->_pNext;
        }
        pCur->_pNext = BuySListNode(data);
    }
}

void SListPopBack(PNode* pHead) // 尾刪 
{
    assert(pHead);
    if (NULL == *pHead) //空鏈表
        return ;

    else if (NULL == (*pHead)->_pNext) //只有一個節點
    {
        PNode TmpNode = *pHead;
        free(TmpNode);
        TmpNode = NULL;
        *pHead = NULL;
    }
    else
    {
        PNode pCur = *pHead;
        while (pCur->_pNext->_pNext)
        {
            pCur = pCur->_pNext;
        }
        pCur->_pNext = NULL;
    }
}

void SListPushFront(PNode* pHead, DataType data)// 頭插 
{
    PNode PNewNode = NULL;
    assert(pHead);

    PNewNode = BuySListNode(data);
    if (NULL == PNewNode)
        return;
    PNewNode->_pNext = *pHead;
    *pHead = PNewNode;

}

void SListPopFront(PNode* pHead)// 頭刪 
{
    PNode pDelNode = NULL;
    assert(pHead);
    if (NULL == pHead) //空鏈表
        return ;
    pDelNode = *pHead;
    *pHead = pDelNode->_pNext;
    free(pDelNode);
}

// 查找值爲data的結點,返回該結點在鏈表中的位置 
PNode SListFind(PNode pHead, DataType data)
{
    PNode pCur = pHead;
    while (pCur)
    {
        if (pCur->_data == data)
        {
            return pCur;
        }
        pCur = pCur->_pNext;
    }
    return NULL;
}

// 在鏈表pos位置後插入結點data 
void SListInsert(PNode* pHead, PNode pos, DataType data)
{
    PNode PNewNode = NULL;
    assert(pHead);
    if (NULL == *pHead || NULL == pos)
        return;

    PNewNode = BuySListNode(data);
    PNewNode->_pNext = pos->_pNext;
    pos->_pNext = PNewNode;

}

// 刪除鏈表pos位置上的結點 
void SListErase(PNode* pHead, PNode pos)
{
    assert(pHead);
    if (NULL == *pHead || NULL == pos)
        return;
    if (pos == *pHead)
    {
        SListPopFront(pHead);
    }
    else
    {
        PNode pCur = *pHead;
        while (pCur && pCur->_pNext != pos)
        {
            pCur = pCur->_pNext;
        }
            if (pCur)
        {
            pCur->_pNext = pos->_pNext;
            free(pos);
        }
    }
}

void SListClear(PNode* pHead)// 將鏈表中的結點清空
{
    PNode pDelNode = NULL;
    assert(pHead);
    while (*pHead)
    {
        pDelNode = *pHead;
        *pHead = pDelNode->_pNext;
        free(pDelNode);
    }
}

void SListDestroy(PNode* pHead)// 銷燬單鏈表 
{
    SListClear(pHead);
}

int SListSize(PNode pHead)  // 求鏈表中結點的個數 
{
    int count = 0;
    PNode pCur = pHead;
    assert(pHead);
    if (NULL == pHead)
        return 0;
    pCur = pHead;
    while (pCur)
    {
        count++;
        pCur = pCur->_pNext;
    }
    return count;
}

// 獲取鏈表中的最後一個結點,返回該結點的地址 
PNode SListBack(PNode pHead)
{
    PNode pCur = pHead;
    assert(pHead);
    while (pCur->_pNext)
    {
        pCur = pCur->_pNext;
    }
    return pCur;
}

void PrintList(PNode* pHead)//打印單鏈表  
{
    PNode pCur = *pHead;
    while (pCur)
    {
        printf("%d->", pCur->_data);
        pCur = pCur->_pNext;
    }
    printf("NULL\n");
}

以下爲鏈表面試題

// 從尾到頭打印單鏈表 
void PrintListFromTail2Head(PNode pHead)
{
    if (pHead)
    {
        PrintListFromTail2Head(pHead->_pNext);
        printf("%d--", pHead->_data);
    }
}

// 刪除無頭單鏈表的非尾結點,要求:不能遍歷鏈表 
void DeleteNotTailNode(PNode pos)
{
    PNode pDelNode = NULL;
    if (NULL == pos&&NULL == pos->_pNext)
        return;

    pDelNode = pos->_pNext;
    pos->_data = pDelNode->_data;
    pos->_pNext = pDelNode->_pNext;
    free(pDelNode);
}

// 在無頭單鏈表pos位置前插入值爲結點data的結點 (不能遍歷鏈表)
void InsertPosFront(PNode pos, DataType data)
{
    PNode pNewNode = NULL;
    if (NULL == pos)
        return;
    pNewNode = BuySListNode(pos->_data);
    pNewNode->_pNext = pos->_pNext;
    pos->_pNext = pNewNode;
    pos->_data = data;
}

// 用單鏈表模擬實現約瑟夫環 
void JosephCircle(PNode* pHead, const int M)
{
    assert(pHead);
    PNode pCur = *pHead;
    if (NULL == pHead)
        return;

    while (pCur->_pNext != pCur)
    {
        ///報數
        int count = M;
        while (--count)
        {
        pCur = pCur->_pNext;
        }
            //刪除--替換法刪除
        PNode pDelNode = pCur->_pNext;
        pCur->_data = pDelNode->_data;
        pCur->_pNext = pDelNode->_pNext;
        free(pDelNode);
    }
    *pHead = pCur;
}

// 使用冒泡排序方法對單鏈表進行排序 
void BubbleSort(PNode pHead)
{
    PNode pPreCur = NULL;
    PNode pCur = NULL;
    PNode pTail = NULL;
    if (NULL == pHead || NULL == pHead->_pNext)
        return;
    while (pHead != pTail)
    {
        int IsChange = 0;
        pPreCur = pHead;
        pCur = pPreCur->_pNext;
        while (pCur != pTail)
        {
            if (pPreCur->_data > pCur->_data)
            {
                int tmp = pPreCur->_data;
                pPreCur->_data = pCur->_data;
                pCur->_data = tmp;
                IsChange = 1;
            }
            pPreCur = pCur;
            pCur = pPreCur->_pNext;
        }
        if (!IsChange)
            return;
        pTail = pPreCur;
    }
}


// 單鏈表的逆置--三個指針 
void ReverseSList(PNode* pHead)
{
    PNode pPre = NULL;
    PNode pCur = NULL;
    PNode pNext = NULL;
    assert(pHead);
    if (NULL == *pHead || NULL == (*pHead)->_pNext)
        return;
    pCur = *pHead;
    while (pCur)
    {
        pNext = pCur->_pNext;
        pCur->_pNext = pPre;
        pPre = pCur;
        pCur = pNext;
    }
    *pHead = pPre;
}

// 單鏈表的逆置--頭插法 
PNode ReverseSListOP(PNode pHead)
{
    PNode pNewHead = NULL;
    PNode pCur = pHead;
    PNode pNext = NULL;

    if (NULL == pHead || NULL == pHead->_pNext)
        return pHead;

    while (pCur)
    {
        pNext = pCur->_pNext;
        pCur->_pNext = pNewHead;
        pNewHead = pCur;
        pCur = pNext;
    }
    return pNewHead;
}

// 合併兩個有序鏈表,合併之後依然有序 
PNode MergeSList(PNode pHead1, PNode pHead2)
{
    PNode pNewHead = NULL;
    PNode pTailNode = NULL;
    PNode pL1 = pHead1;
    PNode pL2 = pHead2;
    if (NULL == pHead1)
        return pHead2;
    if (NULL == pHead2)
        return pHead1;
    //兩個鏈表都不爲空,確定第一個節點
    if (pL1->_data < pL2->_data)
    {
        pNewHead = pL1;
        pL1 = pL1->_pNext;
    }
    else
    {
        pNewHead = pL2;
        pL2 = pL2->_pNext;
    }
    //向新鏈表中插入值
    pTailNode = pNewHead;
    while (pL1 && pL2)
    {
        if (pL1->_data < pL2->_data)
        {
            pTailNode->_pNext = pL1;
            pL1 = pL1->_pNext;
        }
        else
        {
            pTailNode->_pNext = pL2;
            pL2 = pL2->_pNext;
        }
        pTailNode = pTailNode->_pNext;
    }
    //若一個鏈表有剩餘,放在新鏈表後面
        if (pL1)
            pTailNode->_pNext = pL1;
        else
            pTailNode->_pNext = pL2;
    return pNewHead;
}

// 查找鏈表的中間結點,要求只能遍歷一次鏈表 
PNode FindMiddleNode(PNode pHead)
{
    PNode pFast = pHead;
    PNode pSlow = pHead;
    /*PNode pPre = pHead;*/
    while (pFast && pFast->_pNext)
    {
        /*pPre = pSlow;*/
        pFast = pFast->_pNext->_pNext;
        pSlow = pSlow->_pNext;
    }

    //求奇數個節點的中間節點前一個節點
    /*if (NULL == pFast)
    return pPre;*/
    return pSlow;
}

// 查找鏈表的倒數第K個結點,要求只能遍歷鏈表一次 
PNode FindLastKNode(PNode pHead, int K)
{
    PNode pFast = pHead;
    PNode pSlow = pHead; 
    if (NULL == pHead || K < 0)
        return NULL;
    //讓pFast先走K步
    while (K--)
    {
        if (NULL == pFast)//K大於節點個數
            return NULL;
        pFast = pFast->_pNext;
    }
    //兩指針同時往後走
    while (pFast)
    {
        pFast = pFast->_pNext;
        pSlow = pSlow->_pNext;
    }
    return pSlow;
}

// 刪除鏈表的倒數第K個結點,要求只能遍歷鏈表一次 
PNode DeleteLastKNode(PNode pHead, int K)
{
    PNode pFast = pHead;
    PNode pSlow = pHead;
    PNode pPre = NULL;

    if (NULL == pHead || K <= 0)
        return NULL;
    int count = K;
    //快的指針先走K步
    while (count--)
    {
        if (NULL == pFast)
            return NULL;
        pFast = pFast->_pNext;
    }
    //然後快慢指針一起走,慢指針指向的就是倒數第K個節點
    while (pFast)
    {
        pPre = pSlow;
        pFast = pFast->_pNext;
        pSlow = pSlow->_pNext;
    }
    //刪除
    pPre->_pNext = pSlow->_pNext;
    free(pSlow);

    return pHead;
}

// 判斷單鏈表是否相交?鏈表不帶環 
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
    PNode pTail1 = pHead1;
    PNode pTail2 = pHead2;
    if (NULL == pHead1 || NULL == pHead2)
        return 0;
    //找第一個鏈表的最後一個節點
    while (pTail1)
        pTail1 = pTail1->_pNext;
    //找第二個鏈表的最後一個節點
    while (pTail2)
        pTail2 = pTail2->_pNext;
    return pTail1 == pTail2;
}

// 求不帶環單鏈表相交交點 
PNode GetCrossNode(PNode pHead1, PNode pHead2)
{
    int size1 = 0, size2 = 0, gap;
    PNode pCur1 = pHead1, pCur2 = pHead2;
    if (!(IsCrossWithoutCircle(pHead1, pHead2)))
        return NULL;
    //求交點
    while (pCur1)
    {
        size1++;
        pCur1 = pCur1->_pNext;
    }
    while (pCur2)
    {
        size2++;
        pCur2 = pCur2->_pNext;
    }
    //讓長的鏈表先走差值這麼多
    gap = size1 - size2;
    pCur1 = pHead1; 
    pCur2 = pHead2;
    if (gap > 0)
    {
        while (gap--)
            pCur1 = pCur1->_pNext;
    }
    else
    {
        while (gap++)
            pCur2 = pCur2->_pNext;
    }
    while (pCur1 != pCur2)
    {
        pCur1 = pCur1->_pNext;
        pCur2 = pCur2->_pNext;
    }
    return pCur1;
}

// 判斷鏈表是否帶環 
PNode IsCircle(PNode pHead)
{
    PNode pFast = pHead;
    PNode pSlow = pHead;
    while (pFast&&pFast->_pNext)
    {
        pFast = pFast->_pNext->_pNext;
        pSlow = pSlow->_pNext;
        if (pFast == pSlow)     //帶環
            return pFast;
    }
    return 0;
}

// 求環的長度 
int GetCircleLen(PNode pHead)
{
    PNode pMeetNode = IsCircle(pHead);
    PNode pCur = pMeetNode;
    int count = 1;
    if (NULL == pMeetNode)
        return 0;
    while (pCur->_pNext != pMeetNode)
    {
        count++;
        pCur = pCur->_pNext;
    }
    return count;
}

// 求環的入口點--注意推斷過程 
PNode GetEnterNode(PNode pHead, PNode pMeetNode)
{
    PNode PH = pHead;
    PNode PM = pMeetNode;
    if (NULL == pHead || NULL == pMeetNode)
        return NULL;
    while (PH != PM)
    {
        PH = PH->_pNext;
        PM = PM->_pNext;
    }
    return PM;
}

// 判斷鏈表是否帶環,鏈表可能帶環 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2)
{
    PNode pMeetNode1 = NULL;
    PNode pMeetNode2 = NULL;
    if (NULL == pHead1 || NULL == pHead2)
        return 0;
    //判斷兩個鏈表是否帶環
    pMeetNode1 = IsCircle(pHead1);
    pMeetNode2 = IsCircle(pHead2);
    //兩個鏈表都不帶環
    if (NULL == pMeetNode1&&NULL == pMeetNode2)
    {
        //求兩個鏈表的最後一個元素,若最後一個元素相等則相交
        PNode pTail1 = pHead1;
        PNode pTail2 = pHead2;
        while (pTail1->_pNext)
            pTail1 = pTail1->_pNext;
        while (pTail2->_pNext)
            pTail2 = pTail2->_pNext;

        if (pTail1 == pTail2)
            return 1;
    }
    //兩個鏈表都帶環
    else if (pMeetNode1 && pMeetNode2)
    {
        PNode pCur = pMeetNode1;
    /*  do
        {
            if (pCur == pMeetNode2)
                return 2;
            pCur = pCur->_pNext;
        } while (pCur != pMeetNode1);*/
        while (pCur->_pNext != pMeetNode1)
        {
            if (pCur == pMeetNode2)
                return 2;
            pCur = pCur->_pNext;
        }
        if (pCur == pMeetNode2)
            return 2;
    }
    return 0;
}

// 複雜鏈表的複製 
PCListNode CopyComplexList(PCListNode pHead)
{
    PCListNode pOldNode = pHead;
    PCListNode pNewNode = NULL;
    PCListNode pNewHead = NULL;
    if (NULL == pHead)
        return NULL;
    //在原鏈表的每個節點後插入值相同的新節點
    while (pOldNode)
    {
        pNewHead = (PCListNode)malloc(sizeof(CListNode));
        pNewHead->_data = pOldNode->_data;
        pNewNode->_pNext = NULL;
        pNewNode->_pRandom = NULL;
        if (NULL == pNewNode)
            return NULL;

        pNewNode->_pNext = pOldNode->_pNext;
        pOldNode->_pNext = pNewNode;
        pOldNode = pNewNode->_pNext;
    }
    //給新插入的節點的隨機指針域賦值
    pOldNode = pHead;
    while (pOldNode)
    {
        pNewNode = pOldNode->_pNext;
        if (NULL == pOldNode->_pRandom)
            pNewNode->_pRandom = NULL;
        else
            pNewNode->_pRandom = pOldNode->_pRandom->_pNext;
        pOldNode = pNewNode->_pNext;
    }
    //將插入的新節點從鏈表中拆下來
    pOldNode = pHead;
    pNewHead = pOldNode->_pNext;
    while (pOldNode->_pNext)
    {
        pNewNode = pOldNode->_pNext;
        pOldNode->_pNext = pNewNode->_pNext;
        pOldNode = pNewNode;
    }
    return pNewHead;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章