Linus:利用二级指针删除单向链表

今天在网上看到一篇利用二级指针删除单向链表中部分节点的文章,发现对二级指针的理解还不够深刻。

http://www.linuxeden.com/html/news/20130204/135356.html

http://wordaligned.org/articles/two-star-programming

以下内容基本来自上面两个链接。

假如有一个单向链表:

struct node {
    int val;
    struct node* next;
    node():val(0),next(0) {}
    node(int v) : val(v), next(0) {}
};

若想删除链表中节点的val为偶数的点,需要怎么做呢?

常见的做法,为了链表的连续性,在判断当前节点 current 时,需要维持前一个节点 pre 的指针。判断后,若当前节点需要删除,则 pre->next = current->next。

struct node* remove(struct node* head)
{
    struct node* pre = NULL, *cur = head;
    
    while (cur != NULL)
    {
        struct node* next = cur->next;
        if ((cur->val % 2) == 0)
        {
            if (!pre)
                head = next;
            else
                pre->next = next;
            free(cur);
        }
        else
            pre = cur;
        cur = next;
    }
    return head;
}

但是如果利用二级指针需要怎么实现呢。

void remove1(struct node** head)
{
    for (struct node** curr = head;*curr;)
    {
        node* entry = *curr;
        if (entry->val % 2 == 0)
        {
            *curr = entry->next;
            free(entry);
        }
        else
            curr = &entry->next;
    }
}

此处的node** head 与上面的node* head不同,此处的head是一个二级指针,指向头指针的地址。程序看起来简洁不少。

该做法的主要思路就是:

若利用二级指针指向一个一级指针,不但能操作二级指针指向哪个一级指针,同时还能操作其指向的一级指针的值(也就是说一级指针指向哪个具体的元素)。

以下是完整测试代码:

#include <iostream>
using namespace std;

struct node {
    int val;
    struct node* next;
    node():val(0),next(0) {}
    node(int v) : val(v), next(0) {}
};

void output(node* head)
{
    while (head)
    {
        cout << head->val << " ";
        head = head->next;
    }
    cout << endl;
}

struct node* remove(struct node* head)
{
    struct node* pre = NULL, *cur = head;
    
    while (cur != NULL)
    {
        struct node* next = cur->next;
        if ((cur->val % 2) == 0)
        {
            if (!pre)
                head = next;
            else
                pre->next = next;
            free(cur);
        }
        else
            pre = cur;
        cur = next;
    }
    return head;
}

void remove1(struct node** head)
{
    for (struct node** curr = head;*curr;)
    {
        node* entry = *curr;
        if (entry->val % 2 == 0)
        {
            *curr = entry->next;
            free(entry);
        }
        else
            curr = &entry->next;
    }
}

int main()
{
    struct node* head = NULL, *cur = NULL, *next = NULL;
    for (int i = 0;i < 10;++i)
    {
        if (cur == NULL)
        {
            cur = new struct node(i);
            head = cur;
        }
        else
        {
            next = new struct node(i);
            cur->next = next;
            cur = next;
        }
    }
    //head = remove(head);
    struct node** p = &head;
    remove1(p);
    output(head);
}

注:测试中还发现,通过new申请的对象,即使是连续调用new,中间没有其他的操作,申请的地址也不是连续的。

在本例中就是这样。


你可能感兴趣的:(Linus:利用二级指针删除单向链表)