2014-10-28 3 views
0

Эта функция предназначена для удаления элементов из связанного списка. В настоящее время это делает работу, однако, с дальнейшим тестированием я узнал, что я получаю ошибку сегментации после использования функции примерно в 2-3 раза. Например, скажем, listA содержит 1 2 3 4 4 5, когда я сделаю remove listA 4, а затем распечатаю элементы listA, выход должен быть 1 2 3 5, и это так. Однако, когда я использую функцию удаления еще 1-2 раза в списке, он просто перестает работать, и я продолжаю получать ошибки сегментации. Я не знаю, почему .. Любая помощь будет оценена!функция не работает несколько раз?

void mylist::remove(int z) 
      {  
       Node *currP, *prevP; 

       prevP = NULL; 
       for (currP = head; 
        currP != NULL; 
        prevP = currP, currP = currP->next) { 

       if (currP->key == z) { 
        if (prevP == NULL) { 
        head = currP->next; 
        } else{ 
        prevP->next = currP->next; 
        } 
        delete currP; 
        currP=prevP; 
        numberofnodes--; 
       } 
       } 
       return; 
     } 
+0

Вы были близки к точному, но: * «когда я использую функцию удаления еще 1-2 раза в списке, он просто перестает работать» * опустил мяч. Посмотрите на [«Минимальный, полный, проверяемый пример»] (http://stackoverflow.com/help/mcve). Покажите свой точный ввод и программу, которая компилирует, которую любой может скопировать-вставить в компилятор («полный») и может повторно («verifably») давать неверный вывод. Проверьте основные случаи, такие как удаление «1» из списка, содержащего только 1. Вы можете найти свою собственную проблему в процессе ... – HostileFork

+0

Просто измените инструкцию update в цикле for, получите доступ к следующему элементу из currP, только если он не равен NULL. –

ответ

2

Вы не обрабатываете случай, когда список форм первого узла удален, так как prevP будет иметь значение null. После удаления currP вы назначаете currP=prevP;. В следующей итерации, когда prevP = currP, currP = currP->next будет выполнен для следующей итерации для цикла, это приведет к ошибке сегментации.

Вы можете использовать время цикл вместо этого, как:

void mylist::remove(int z) 
     {  
      Node *currP, *prevP, *temp; 

      prevP = NULL; 
      currP = head; 
      while(currP != NULL){ 

      if (currP->key == z) { 
       if (prevP == NULL) { 
       head = currP->next; 
       } else{ 
       prevP->next = currP->next; 
       } 
       temp = currP; 
       currP = currP->next; 
       delete temp; 
       numberofnodes--; 
      } 
      else 
      { 
       prevP = currP; 
       currP = currP->next; 
      } 
      } 
      return; 
    } 
0

delete currP; currP = prevP;

Это вызывает потерю сегментации, при первом итерации prevP имеет значение null, поэтому если выполняется в случае, если итерация prevP не является нулевой.

+0

в порядке, имеет смысл. Как я могу изменить свой код, чтобы сделать это? не уверен. – sam696969

+0

prevPcurrentP; delete currP; –

1

Рассмотрите, что происходит, когда вы удаляете первую запись в списке: вы устанавливаете head = currP->next, но вы оставляете prevP как NULL. Когда код достигнет currP=prevP, currP станет NULL, а затем вы получите ошибку, пытающуюся получить доступ к currP->next на итерации. Чтобы избежать этого, вам нужно будет реорганизовать свой цикл.

1

Вашего управление указателем на переход к следующей итерации для цикла неверно. Когда для currP установлено значение NULL при удалении первого элемента, вы будете разыскивать NULL на шаге приращения итерации цикла for.

Честно говоря, for-loop не является самой горячей идеей для этого алгоритма в первую очередь, но если вы действительно хотите сделать это с минимальными усилиями, то решение с указателем на указатель делает короткую работу над этой задачей:

void mylist::remove(int z) 
{ 
    Node **pp = &head; 
    while (*pp) 
    { 
     if ((*pp)->key != z) 
     { 
      pp = &(*pp)->next; 
     } 
     else 
     { 
      Node *victim = *pp; 
      *pp = victim->next; 
      delete victim; 
      --numberofnodes; 
     } 
    } 
} 

Как это работает

указатель к указателю pp содержит адрес указателя интересующие нас проверку на матч. Первоначально он содержит адрес указателя head.

Node **pp = &head; 

С каждым неигровые мы переходим по адресу next указателя текущего узла:

if ((*pp)->key != z) 
{ 
    pp = &(*pp)->next; 
} 

, но, когда мы обнаруживаем спичкой значение указателя, адрес которого удерживается в pp сохраняется временное:

Node *victim = *pp; 

затем , что указатель (который может быть head, если это первый элемент в списке), обновляется до значения указателя next указателя на узел.

*pp = victim->next; 

И наконец, отсоединенный узел теперь отбрасывается.

delete victim; 

Примечания:

Существует НЕТ движение next, когда мы отказываемся матч. Мы уже переместились туда, загрузив *pp со значением указателя, содержащимся в своем собственном указателе next перед удалением. Кроме того, это (надеюсь, очевидно) критический, что указатель head должен быть NULL, если список пуст, а последний узел next указатель NULL, чтобы прервать список. Я знаю, это стандартный связанный список, но это важно и поэтому упоминается.

Удачи.

1

Рассмотрите возможность удаления 1 в своем списке. prevP = NULL; , тогда вы удаляете currP и назначаете его с prevP, ведьма NULL. конец этого цикла. Затем он переходит в часть: prevP = currP, currP = currP-> next; последний случай проблема, потому что currP NULL. Вы получаете доступ к NULL-> next.

Смежные вопросы