C語言實現單鏈表的基本操做及其部分面試題


    //單鏈表的基本數據類型及其結構
ide


    typedef int DataType;函數

    typedef struct LinkNodespa

    {指針

        DataType data;排序

        struct LinkNode *next;遞歸

    }LinkNode,*pLinkNode,*pLinkList;it


    //單鏈表的初始化   ast

    void InitLinkList(pLinkList* pHead)//初始化class

    {變量

        assert(pHead);

        *pHead = NULL;

    }


    //當尾插,頭插,插入時都須要創建一個新的結點,爲方便創建一個建立結點的函數

    pLinkNode BuyNode(DataType d)//建立一個結點

    {

        pLinkNode newNode = (pLinkNode)malloc(sizeof(LinkNode));

        newNode->data = d;

        newNode->next = NULL;

        return newNode;

    }

    

    //單鏈表的銷燬,即把單鏈表中全部的結點都釋放掉    

    void Destory(pLinkList* pHead)//銷燬

    {

        if(*pHead == NULL)

        {

        return;

        }

        else

        {

            pLinkNode cur = *pHead;

            while (cur)

            {

                pLinkNode del = cur;

                cur = cur->next;

                free(del);

                del = NULL;

            }

        }

    }


    //在當前單鏈表的末尾插入一個結點   

    void PushBack(pLinkList* pHead,DataType d)//尾插

    {

        pLinkNode cur = *pHead;

        pLinkNode newNode = BuyNode(d);

        assert(pHead);

        if(cur == NULL)

        {

        *pHead = newNode;

        return ;

        }

        while(cur->next)

        {

            cur = cur->next;

        }

        cur->next = newNode;

    }


    //把當前單鏈表的最後一個結點刪除掉

    void PopBack(pLinkList* pHead)//尾刪

    {

        pLinkNode cur = *pHead;

        assert(pHead);

        if(*pHead == NULL)

        {

            return;

        }

        else if((*pHead)->next == NULL)

        {

            free(*pHead);

            *pHead = NULL;

        }

        else

        {

            pLinkNode del;

            while (cur->next->next)

            {

                cur = cur->next;

            }

            del = cur->next;

            cur->next = NULL;

            free(del);

            del = NULL;

        }

    }


    //在當前單鏈表的頭部插入一個結點

    void PushFront(pLinkList* pHead,DataType d)//頭插

    {

        pLinkNode newNode = BuyNode(d);

        pLinkNode cur = *pHead;

        assert(pHead);

        if(cur == NULL)

        {

            *pHead = newNode;

            return;

        }

        else 

        {

            newNode->next = *pHead;

            *pHead = newNode;

        }

    }


    //將單鏈表的第一個結點刪除掉

    void PopFront(pLinkNode* pHead)//頭刪

    {

        assert(pHead);

        if(*pHead == NULL)

        {

            return;

        }

        else

        {

            pLinkNode del = *pHead;

            *pHead = (*pHead)->next;

            free(del);

            del = NULL;

        }

    }


    //獲取單鏈表的長度,增長一個計數器,將單鏈表遍歷一遍 

    int GetListLength(pLinkList* pHead)//求單鏈表的長度

    {

pLinkNode cur = *pHead;

int count = 0;

assert(pHead);

while(cur)

{

count++;

cur = cur->next;

}

return count;

    }


    //給定單鏈表的一個結點,在該結點的位置插入一個新的節點,遍歷單鏈表,只要(cur->next==pos),使新結點的next指向pos,再將新結點賦給cur->next。

    void InsertList(pLinkList* pHead,pLinkNode pos,DataType d)//插入

    {

pLinkNode newNode = BuyNode(d);

pLinkNode cur = *pHead;

assert(pHead);

assert(pos);

if(*pHead == pos)

{

newNode->next = *pHead;

*pHead = newNode;

}

else

{

while (cur->next != pos)

{

cur = cur->next;

}

newNode->next = cur->next;

cur->next = newNode;

}

    }


    //遍歷單鏈表,只要某結點的值與要找的值相等,則返回該結點,不然返回NULL

    pLinkNode Find(pLinkList* pHead,DataType d)//查找

    {

pLinkNode cur = *pHead;

assert(pHead);

while(cur)

{

if(cur->data == d)

{

return cur;

}

cur = cur->next;

}

return NULL;

    }


    //方法1 利用Find函數找到須要刪除的結點pos,遍歷單鏈表,只要(cur->next == pos),將pos->next賦給cur->next,再將pos釋放掉。

    void Remove(pLinkList* pHead,DataType d)//刪除結點

    {

pLinkNode pos = Find(pHead,d);

pLinkNode cur = *pHead;

pLinkNode del = NULL;

assert(pHead);

if(*pHead == pos)

{

del = *pHead;

*pHead = (*pHead)->next;

free(del);

del = NULL;

}

else

{

while (cur->next != pos)

{

cur = cur->next;

}

del = cur->next;

cur->next = del->next;

free(del);

}

    }


    //方法2 不須要已有函數Find,原理與方法1同樣

    void Remove(pLinkList* pHead,DataType d)//刪除結點

    {

pLinkNode cur = *pHead;

pLinkNode del = NULL;

pLinkNode prev = NULL;

assert(pHead);

if(cur == NULL)

{

return;

}

while(cur)

{

if(cur->data == d)

{

del = cur;

if(cur == *pHead)

{

*pHead = (*pHead)->next;

}

else

{

prev->next = cur->next;

}

free(del);

break;

}

prev = cur;

cur = cur->next;

}

    }


    //刪除單鏈表中全部相同的結點,首先,遍歷單鏈表,找到第一個要刪除的結點,刪除並釋放掉,同時增長一個指向該結點下一個結點的指針,以此位置向後遍歷單鏈表,刪除相同結點,以此類推。

    void RemoveAll(pLinkList* pHead,DataType d)//刪除全部相同結點

    {

pLinkNode cur = *pHead;

pLinkNode del = NULL;

pLinkNode prev = NULL;

assert(pHead);

while(cur)

{

if(cur->data == d)

{

del = cur;

if(cur == *pHead)

{

*pHead = (*pHead)->next;

cur = *pHead;

}

else

{

prev->next = cur->next;

cur = prev->next;

}

free(del);

}

else

{

prev = cur;

cur = cur->next;

}

}

    }


    //刪除指定位置的結點,需找到要刪除結點的上一個結點,將該結點的下一個結點賦給該結點的next,刪除並釋放該結點。

    void Erase(pLinkNode* pHead,pLinkNode pos)//刪除指定位置的結點

    {

pLinkNode cur = *pHead;

pLinkNode del = NULL;

assert(pHead);

if(*pHead == NULL)

{

return;

}

else if(*pHead == pos)

{

free(*pHead);

*pHead =NULL;

}

else

{

while(cur->next)

{

if(cur->next == pos)

{

del = cur->next;

cur->next = del->next;

free(del);

del = NULL;  

}

cur = cur->next;

}

}

    }


    //刪除無頭單鏈表的非尾結點,首先給出一個指針del記錄pos->next,將pos->data賦給pos->data,再將del->next賦給pos->next,最後只需把del釋放便可

    void EraseNotTail(pLinkNode pos)//刪除無頭單鏈表的非尾結點

    {

pLinkNode del = pos->next;

pos->data = del->data;

pos->next = del->next;

free(del);

del = NULL;

    }


    //單鏈表的逆序,把第一個結點取出來,他的next恆等於NULL,而後再把其餘結點依次取出來利用頭插的方法插入,完成逆序。

    void ReverseList(pLinkList* pHead)//反轉(逆序)

    {

pLinkNode pNewHead = NULL;

pLinkNode cur = *pHead;

pLinkNode prev = NULL;

assert(pHead);

if((cur == NULL)&&(cur->next == NULL))

{

return;

}

while(cur)

{

prev = cur;

cur = cur->next;

prev->next = pNewHead;

pNewHead = prev;

}

*pHead = pNewHead;

    }


    //冒泡排序

    void BubbleSort(pLinkList* pHead)//排序鏈表(冒泡)

    {    

pLinkNode cur = *pHead;

assert(pHead);

while(cur)

{

pLinkNode pos =cur->next;

while(pos)

{

if(cur->data  > pos->data)

{

DataType tmp = cur->data;

cur->data = pos->data;

pos->data = tmp;

}

pos = pos->next;

}

cur = cur->next;

}

    }


    //在當前結點前插入一個結點,首先在pos位置後插入一個結點,而後再交換pos->data和newNode->data便可

    void InsertFrontNode(pLinkNode pos,DataType d)//在當前結點前插入一個數據

    {

pLinkNode NewNode = BuyNode(d);

DataType tmp = 0;

assert(pos);

NewNode->next = pos->next;

pos->next = NewNode;

tmp = pos->data;

pos->data = NewNode->data;

NewNode->data = tmp;

    }


    //合併兩個有序鏈表(非遞歸)

    pLinkNode Merge(pLinkList l1,pLinkList l2)

    {

pLinkNode newHead = NULL;

pLinkNode cur = NULL;

if(l1 == l2)

{

return l1;

}

if((l1 != NULL)&&(l2 ==NULL))

{

return l1;

}

if((l1 == NULL)&&(l2 != NULL))//肯定頭節點

{

return l2;

}

if(l1->data < l2->data)

{

newHead = l1;

l1 = l1->next;

}

else

{

newHead =l2;

l2 = l2->next;

}

cur = newHead;

while ((l1)&&(l2))

{

if(l1->data < l2->data)

{

cur->next = l1;

l1 = l1->next;

}

else

{

cur->next = l2;

l2 = l2->next;

}

cur = cur->next;

}

if(l1)

{

cur->next = l1;

}

else

{

cur->next =l2;

}

return newHead;

    }


    //利用遞歸實現鏈表的合併

    pLinkNode _Merge(pLinkList plist1,pLinkList plist2)

    {

pLinkNode newHead = NULL;

if((plist1 == NULL) &&(plist2 == NULL))

{

return NULL;

}

else if((plist1 != NULL)&&(plist2 == NULL))

{

return plist1;

}

else if((plist1 == NULL)&&(plist2 != NULL))

{

return plist2;

}

if(plist1->data < plist2->data)

{

newHead = plist1;

newHead->next = _Merge(plist1->next,plist2);

}

else

{

newHead = plist2;

newHead->next = _Merge(plist1,plist2->next);

}

return newHead;

    }


    //利用快慢指針,快指針走兩步,慢指針走一步,返回慢指針,即爲中間結點

    pLinkNode FindMidNode(pLinkList* pHead)//查找鏈表的中間結點

    {

pLinkNode fast = *pHead;

pLinkNode slow = *pHead;

while (fast && fast->next)

{

fast = fast->next->next;

slow = slow->next;

}

return slow;

    }


    //利用快慢指針,快指針先走k-1步後,兩指針同時走,慢指針即爲倒數第k個結點,而後再利用刪除無頭單鏈表的非尾結點中的方法刪除慢指針的下一個結點。

    void DelKNode(pLinkList *pHead,int k)//刪除單鏈表的倒數第k(k>1)個結點

    {

pLinkNode fast = *pHead;

pLinkNode slow = *pHead;

pLinkNode del = NULL;

assert(*pHead);

assert(k>1);

while (--k)

{

fast = fast->next;

}

while(fast->next)

{

fast = fast->next;

slow = slow->next;

}

del = slow->next;

slow->data = slow->next->data;

slow->next = slow->next->next;

free(del);

    }


    //約瑟夫環,n我的圍成一圈,從某我的開始報數,報到m的那我的退出,而後m的下一我的繼續從1開始報數,報到m的那我的退出,以此類推,最後剩下的那我的勝出。

    //設置一個指針變量指向第一個結點,從第一個結點先走(num-1)步,利用刪除單鏈表的無頭非尾結點的方法,刪除num結點的下一個結點,依次類推。

    pLinkNode JosephCycle(pLinkList *pHead,int num)

    {

pLinkNode cur = *pHead;

pLinkNode del = NULL;

int count = 0;

assert(pHead);

while(1)

{

count = num;

if(cur->next == cur)

{

break;

}

while(--count)

{

cur = cur->next;

}

printf("%d ",cur->data);

del = cur->next;

cur->data = cur->next->data;

cur->next = cur->next->next;

free(del);

}

*pHead = cur;

return cur;

    }


    //利用快慢指針,快指fast針走兩步,慢指針slow走一步,只要(fast == slow),返回slow,則單鏈錶帶環,不然不帶環。

    pLinkNode CheckCycle(pLinkList pList)//判斷鏈表是否帶環

    {

pLinkNode fast = pList;

pLinkNode slow = pList;

while (fast && fast->next)

{

slow = slow->next;

fast = fast->next->next;

if(fast == slow)

{

return slow;

}

}

return NULL;

    }


    //增長一個計數器,從相遇結點在遍歷一遍環便可求的環的長度

    int GetCircleLength(pLinkNode meet)//若帶環則根據相遇結點求環的長度

    {

int count = 0;

pLinkNode pos = meet;

do

{

pos = pos->next;

count++;

}while (pos != meet);

return count;

    }


    //增設兩個指針,一個指向單鏈表的第一個結點,一個指向相遇結點,只要二者不等,同時各走一步,終有一次二者相等,則返回環的入口結點

    pLinkNode GetCycleEntryNode(pLinkList pList,pLinkNode meetNode)//獲取環的入口結點

    {

pLinkNode entry = pList;

pLinkNode meet = meetNode;

while (entry != meet)

{

entry = entry->next;

meet = meet->next;

}

return entry;

    }

相關文章
相關標籤/搜索