简体   繁体   中英

Recursively Delete Even Items from Doubly Linked List C++

Here is the same question I am asking: deleting even nodes from a doubly link list c++

The difference is, I want to understand what is wrong with my code. I don't want to have to just accept a completely different approach without understand why my code doesn't work. Here are two versions of my code I would like to know what is wrong with both. Both of them give me segmentation fault.

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;
}

This second one takes count = 0 as a default arg.

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
}
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;
}

I have got the hint of the root cause by valgrind and 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

I tested your code with a list beginning with an even item, and it fails. All the test cases the professor provides begin with an even item. Here is the solution:

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;
}

The issue was the actual original head pointer would get lost if the head node was deleted. Now I check to see if we are at the actual head because head->previous should be NULL, and then I set the actual head pointer to the next node in the list before deleting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM