【问题标题】:Deleting every odd positioned node in a linked list in C删除C中链表中每个奇数位置的节点
【发布时间】:2017-07-01 22:55:54
【问题描述】:

我试图在 C 中创建一个删除每个奇数定位节点的函数。例如1,2,3,4 变为2,4

这是我尝试过的,但它似乎不起作用。 我在谈论deletee 函数。我修改了它,但列表似乎没有改变。

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int val;
    struct node *next;
} node;

typedef struct ll {
    node *head;
} ll;

ll *newll() {
    ll *k = malloc(sizeof(ll));
    k->head = NULL;
    return k;
}

void insert(ll *l, int vl) {
    node *tmp = malloc(sizeof(node));
    tmp->next = NULL;
    tmp->val = vl;
    if (l->head == NULL) {
        l->head = tmp;
        return;
    }
    node *s = l->head;
    while (s->next != NULL)
        s = s->next;
    s->next = tmp;
}

void printll(ll *l) {
    node *s = l->head;
    while (s != NULL) {
        printf("%d ", s->val);
        s = s->next;
    }
}

void deletee(ll *l) {
    node *k = l->head;
    while (k != NULL && k->next != NULL) {
        node *tmp = k->next->next;
        k = tmp;
    }
}

int main() {
    ll *ll1 = newll();
    insert(ll1, 5);
    insert(ll1, 6);
    insert(ll1, 8);
    insert(ll1, 9);
    insert(ll1, 10);
    insert(ll1, 11);
    deletee(ll1);
    printll(ll1);
    return 0;
}

【问题讨论】:

    标签: c pointers linked-list


    【解决方案1】:

    我们需要同时更新ll.headnode.next,因此指向node 的指针不够好,除非您想对头部进行特殊处理。相反,让我们使用指向我们要更新的指针的指针。

    void delete_node(node** node_ptr_ptr) {
       node* to_delete = *node_ptr_ptr;
       *node_ptr_ptr = to_delete->next;
       free(to_delete);
    }
    
    void delete_every_second(ll* l) {
       node** node_ptr_ptr = &( l->head );
       while (1) {
          if (*node_ptr_ptr == NULL) break;
          delete_node(node_ptr_ptr);
          if (*node_ptr_ptr == NULL) break;
          node_ptr_ptr = &( (*node_ptr_ptr)->next );
       }
    }
    

    假设您从以下内容开始:

    +------+      +------+      +------+      +------+
    | head ------>| val  |  +-->| val  |  +-->| val  |
    +------+      +------+  |   +------+  |   +------+
                  | next ---+   | next ---+   | next --->NULL
                  +------+      +------+      +------+
    

    node** node_ptr_ptr = &amp;( l-&gt;head );之后:

    +------+      +------+      +------+      +------+
    | head ------>| val1 |  +-->| val2 |  +-->| val3 |
    +------+      +------+  |   +------+  |   +------+
        ^         | next ---+   | next ---+   | next --->NULL
        |         +------+      +------+      +------+
        |
        +-----+
              |
    +------+  |
    | ptr ----+
    +------+
    

    node* to_delete = *node_ptr_ptr;之后:

                  +------+
                  | del ----+
                  +------+  |
                            |
                     +------+
                     |
                     v
    +------+      +------+      +------+      +------+
    | head ------>| val1 |  +-->| val2 |  +-->| val3 |
    +------+      +------+  |   +------+  |   +------+
        ^         | next ---+   | next ---+   | next --->NULL
        |         +------+      +------+      +------+
        |
        +-----+
              |
    +------+  |
    | ptr ----+
    +------+
    

    *node_ptr_ptr = to_delete-&gt;next; free(to_delete);之后:

    +------+                    +------+      +------+
    | head -------------------->| val2 |  +-->| val3 |
    +------+                    +------+  |   +------+
        ^                       | next ---+   | next --->NULL
        |                       +------+      +------+
        |      
        +-----+
              |
    +------+  |
    | ptr ----+
    +------+
    

    node_ptr_ptr = &amp;( (*node_ptr_ptr)-&gt;next );之后:

    +------+                    +------+      +------+
    | head -------------------->| val2 |  +-->| val3 |
    +------+                    +------+  |   +------+
              +---------------->| next ---+   | next --->NULL
              |                 +------+      +------+
              |
    +------+  |
    | ptr ----+
    +------+
    

    【讨论】:

    • 谢谢它终于工作了:))))。如果您能解释一下您对这些指针的指针做了什么,那就太好了,但是如果您没有时间,我可以理解。
    • 补充说明
    【解决方案2】:

    在你的这段代码中:

    while(k!=NULL)
    {
        if(k->next!=NULL && k->next->next!=NULL)
        k->next=k->next->next;
    }
    

    你在那里有一个无限循环,因为你没有在循环中更改k 的值。

    另外:您必须先删除/释放 k-&gt;next 的内存,否则会发生内存泄漏。

    我会简单地改写如下:

    void deletee(ll *l)
    {
      if (l->head == NULL)
        return;
    
      node* tmp = l->head;
      l->head = l->head->next; // skip first item
      free(tmp);
      node* k=l->head;
      while(k!=NULL && k->next!=NULL)
      {
        tmp = k->next;
        k->next = k->next->next;
        free(tmp);
        k = k->next;
      }
    }
    

    结果(如预期):

    6 9 11
    
    • tmp 存储下一个值以供将来删除
    • 我们将下一个元素设置为待删除元素的下一个元素,以便后者取消链接
    • 我们免费tmp
    • 然后我们跳到新的下一个元素并继续

    【讨论】:

    • 感谢您的帮助,但它仍然无法正常工作:C
    • 另外:删除l-&gt;root=k;,因为它使您的根为NULL!
    • free(k-&gt;right);k = k-&gt;right-&gt;right; 很危险,因为您在释放 k-&gt;right 后使用它。 tmp = k-&gt;right-&gt;right; free(k-&gt;right); k = tmp; 会更好。
    • @aragaer 谢谢。小风险,但仍然是错误的(要找到的最讨厌的错误)。固定!
    • 对不起,它只是不想工作。我在我的链表实现中复制并粘贴了您的代码,并尝试打印出新列表。我的屏幕充满了数字,但它并没有终止。
    【解决方案3】:

    您更改了 deletee 函数的代码,但仍然不正确:

    void deletee(ll *l) {
        node *k = l->head;
        while (k != NULL && k->next != NULL) {
            node *tmp = k->next->next;
            k = tmp;
        }
    }
    

    您根本没有修改列表。

    这里有一个解决方案,带有指向指针的指针,以避免出现空列表和列表中第一个节点的特殊情况。 k 指向删除节点时必须更新的链接,每次删除后它都会推过保留节点,但列表末尾除外:

    void deletee(ll *l) {
        node **k = &l->head;
        while (*k != NULL) {
            /* delete the node */
            node *tmp = *k;
            *k = (*k)->next;
            free(tmp);
            if (*k != NULL) {
                /* skip the preserved node */
                k = &(*k)->next;
            }
        }
    }
    

    【讨论】:

    • 谢谢先生。你能解释一下你使用的技术吗?为什么你使用指向指针的指针?
    • @asddf:我使用指向指针的指针来避免出现空列表和第一个节点的特殊情况。 k 指向删除节点时必须更新的链接,每次删除后它都会被推过保留节点,但列表末尾除外。这是链表的经典技术。
    猜你喜欢
    • 2016-07-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    相关资源
    最近更新 更多