【问题标题】:Recursively Delete Even Items from Doubly Linked List C++从双向链表 C++ 中递归删除偶数项
【发布时间】:2017-07-28 02:45:05
【问题描述】:

这是我要问的同一个问题: deleting even nodes from a doubly link list c++

不同之处在于,我想了解我的代码有什么问题。我不想在不理解我的代码为什么不起作用的情况下就接受完全不同的方法。这是我的代码的两个版本,我想知道两者都有什么问题。他们都给我分段错误。

int removeEven(node *&head)
{
if(!head)               //Base case: end of list reached
    return 0;
int count = removeEven(head->next);     //Recurse to end of list
if(head->data % 2 != 0)
    return count;
else{
    ++count;
    if(head->next){
        head->next->previous = head->previous;
    }
    if(head->previous){
        head->previous->next = head->next;
    } if(!(head->previous)){
        node* temp = head;
        head = head->next;
        delete temp;
    }
    else
        delete head;
}
return count;
}

第二个将 count = 0 作为默认参数。

int removeEven(node *&head, int count)
if(head && head->data % 2 != 0) //not null, not even
{
    removeEven(head->next, count);
}
else if(head != NULL){      //not null, yes even
   ++count;
    if(head->next)
        head->next->previous = head->previous;
    if(head->previous)
        head->previous->next = head->next;
    node* temp = head;
    head = head->next;
    delete temp;
   removeEven(head, count);
}
    return count;       //base case: null
}

【问题讨论】:

    标签: c++ recursion gdb


    【解决方案1】:
    int removeEven(node *&head)
    {
      if(!head)               //Base case: end of list reached
        return 0;
      int count = removeEven(head->next);     //Recurse to end of list
      if(head->data % 2 != 0)
        return count;
      else{
        ++count;
        // CORRECT WAY!!! copy the old pointer in a temp
        node *t = head;
        if(head->next){
          head->next->previous = head->previous;
        }
        if(head->previous){
          // WARNING!!! here you are ACTUALLY modifying head to nullptr
          head->previous->next = head->next;
        }
        // CORRECT WAY!!! delete the temp pointer
        delete t;
        // WARNING!!! here you are trying to access a nullptr in head
        // if(!(head->previous)){
        //   node* temp = head;
        //   head = head->next;
        //   delete temp;
        // }
        // else
        //   delete head;
      }
      return count;
    }
    

    我已经通过 valgrind 和 gdb 得到了根本原因的提示

    valgrind ./a.out 
    ==2729== Memcheck, a memory error detector
    ==2729== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==2729== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
    ==2729== Command: ./a.out
    ==2729== 
    [9] [8] [7] [6] [5] [4] [3] [2] [1] [0] 
    ==2729== Invalid read of size 8
    ==2729==    at 0x4008F5: removeEven(node*&) (list1.cpp:26)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x400AFD: main (list1.cpp:81)
    ==2729==  Address 0x10 is not stack'd, malloc'd or (recently) free'd
    ==2729== 
    ==2729== 
    ==2729== Process terminating with default action of signal 11 (SIGSEGV)
    ==2729==  Access not within mapped region at address 0x10
    ==2729==    at 0x4008F5: removeEven(node*&) (list1.cpp:26)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x40087A: removeEven(node*&) (list1.cpp:15)
    ==2729==    by 0x400AFD: main (list1.cpp:81)
    ==2729==  If you believe this happened as a result of a stack
    ==2729==  overflow in your program's main thread (unlikely but
    ==2729==  possible), you can try to increase the size of the
    ==2729==  main thread stack using the --main-stacksize= flag.
    ==2729==  The main thread stack size used in this run was 8720384.
    ==2729== 
    ==2729== HEAP SUMMARY:
    ==2729==     in use at exit: 240 bytes in 10 blocks
    ==2729==   total heap usage: 10 allocs, 0 frees, 240 bytes allocated
    ==2729== 
    ==2729== LEAK SUMMARY:
    ==2729==    definitely lost: 24 bytes in 1 blocks
    ==2729==    indirectly lost: 0 bytes in 0 blocks
    ==2729==      possibly lost: 0 bytes in 0 blocks
    ==2729==    still reachable: 216 bytes in 9 blocks
    ==2729==         suppressed: 0 bytes in 0 blocks
    ==2729== Rerun with --leak-check=full to see details of leaked memory
    ==2729== 
    ==2729== For counts of detected and suppressed errors, rerun with: -v
    ==2729== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
    
    Compilation segmentation fault at Fri Jul 28 09:46:51
    

    【讨论】:

    • 请查看有关错误的 cmets 以及正确的处理方法。
    • 不幸的是,它仍然无法正常工作。它说 ./main double free 或损坏中的错误,并给了我一个回溯和内存映射。 GDB 给 SIGABRT
    • 而且,我不明白这里有什么区别: node *t = head;如果(头->下一个)头->下一个->上一个=头->上一个;如果(头->上一个)头->上一个->下一个=头->下一个;删除 t;删除 t 与删除 head 有何不同?分配 t = head 后,head 没有被修改。
    • 在 if(head->previous) 语句中,让我们考虑 head 何时是最后一个元素。在这种情况下 head->next = nullptr,而 head->previous->next 实际上就是 head 本身。所以通过这个分配 head->previous->next = head->next;您正在将 nullptr 分配给 head。在下一个表达式中 head->previous 您尝试访问 nullptr 并获得有效的分段错误。
    【解决方案2】:

    我使用以偶数项开头的列表测试了您的代码,但它失败了。教授提供的所有测试用例都以偶数项开头。 这是解决方案:

    int removeEven(node *&head)
    {
    if(!head)               //Base case: end of list reached
        return 0;
    int count = removeEven(head->next);     //Recurse to end of list
    if(head->data % 2 != 0)
        return count;
    else{
        ++count;
        node *t = head;
        if(head->next)
            head->next->previous = head->previous;
        if(head->previous)
            head->previous->next = head->next;
        if(head && !head->previous)
            head = head->next;
        delete t;
    }
    return count;
    }
    

    问题是如果头节点被删除,实际的原始头指针会丢失。现在我检查我们是否在实际的头部,因为 head->previous 应该为 NULL,然后我在删除之前将实际的头部指针设置为列表中的下一个节点。

    【讨论】:

      猜你喜欢
      • 2016-10-09
      • 1970-01-01
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 2016-06-11
      • 1970-01-01
      相关资源
      最近更新 更多