1. 程式人生 > >逆置單鏈表、替換法之無頭單鏈表的插入與刪除

逆置單鏈表、替換法之無頭單鏈表的插入與刪除

1. 從尾到頭列印單鏈表

我們知道,單鏈表只能夠通過前面結點來找到後一個結點,不能直接通過後一個結點來找前一個結點,所以如何先列印後面的元素,在列印前面的元素。可以想到運用遞迴,設頭結點為first 第一次函式呼叫:first->next 第二次函式呼叫:first->next->next 第三次函式呼叫:first->next->next->next ······ ······ 依次下去,然後倒著輸出就可以了

    void BackToFrontPrintRec(Node **ppfirst)
    {
        assert(ppfirst);
        assert(*ppfirst
); Node *cur = *ppfirst; if (cur == NULL) { return; } if (cur->next == NULL) { printf("%d ", cur->data); return; } BackToFrontPrintRec(&cur->next); printf("%d ", cur->data); }

那麼不用遞迴又該如何輸出尼?我們可以使用last指標,第一次讓他指向NULL,第二次讓他指向倒數第一個結點,第三次讓他指向倒數第二個結點,依次類推,並將其數值列印即可

    void BackToFrontPrint(Node **ppfirst)
    {
        assert(ppfirst);
        assert(*ppfirst);
        Node *last = NULL;
        Node *cur = *ppfirst;
        while (cur != last)
        {
            while
(cur->next != last) { cur = cur->next; } printf("%d ", cur->data); last = cur; cur = *ppfirst; } }

2. 逆置單鏈表

我們很容易想到在建立一個連結串列進行操作,定義一個result指標為空(作為逆置後的尾結點的next),只需要讓原連結串列頭刪,然後在新連結串列頭插即可 這裡寫圖片描述

    void Reserve1(Node **ppfirst)
    {
        assert(ppfirst);
        assert(*ppfirst);
        Node *result = NULL;
        Node *cur = *ppfirst;
        Node *node = NULL;
        while (cur != NULL)
        {
            //上面頭刪
            node = cur;
            cur = cur->next;
            //下面頭插
            node->next = result;
            result = node;
        }
    }

第二種方法和第一種方法思想實際上是一樣的,但實現過程不一樣,p1指向要移動的結點,p2指向p1的下一個結點,p1實際就是上一中方法的result 這裡寫圖片描述

    void Reserve2(Node **ppfirst)
    {
        assert(ppfirst);
        assert(*ppfirst);
        Node *p1 = NULL;
        Node *p2 = *ppfirst;
        Node *p3 = p2->next;
        while (p2 != NULL)
        {
            p2->next = p1;
            p1 = p2;
            p2 = p3;
            if (p3 != NULL)
            {
                p3 = p3->next;
            }
        }
    }

注:不管是哪種方法,都需要注意判斷條件,可以只照三個結點,按照上述步驟操作一下,就知道判斷條件怎樣設定比較好,當然,判斷條件不是唯一的

3. 刪除一個無頭單鏈表的非尾結點(不能遍歷連結串列)

我們只到,要刪除一個結點,我們可以從頭到尾找,然後刪除。但這個不知道頭結點,也就不能夠開始遍歷。這時候我們就要換一種思想——替換法,設要刪除的結點為node,我們可以把node->next->data放在node->data中,然後讓node指向node->next->next,這時候釋放的是node->next,而不是node。 這裡寫圖片描述

    void RemoveNoHeadNotTail(Node *node)
    {
        assert(node);
        Node *next = node->next;
        node->data = next->data;
        node->next = next->next;
        free(next);
    }

4. 在無頭單鏈表的一個結點前面插入一個結點(不能遍歷)

這個和上一道題的思想是一樣的,我們無法找到node結點的前一個結點,只能講node和newNode裡面的資料進行交換,然後再將newNode插入即可(交換之後,就要將newNode插入到node的後面而不是前面了) 這裡寫圖片描述

    void InsertNoHeadNotTail(Node *node, DataType data)
    {
        assert(node);
        Node *newNode = CreateNewNode(data);
        newNode->data = node->data;
        newNode->next = node->next;
        node->data = data;
        node->next = newNode;
    }

注:替換法刪除不能刪除尾結點,替換法插入適用於任何結點。