1

I am working on a function that would delete a node of a doubly-linked list. Here is my header file:

class LinkedList
{
private:
      struct Node
      {
         int data;
         Node *next;
         Node *previous;
      };

      int count;
      Node *head;
      Node *tail;

public:
      LinkedList() {head = NULL; tail = NULL; count = 0;} //Constructor

      void insert(const int );
      bool remove(const int );
      bool contains(const int );

      size_t lenght() {return count;}
};

My other functions work fine, but its my remove function that breaks on run-time. When i run my code i get a segmentation fault, and after 2 days of trying to figure out the flaw in my logic I am turning to the community for some help. I would be grateful for any feed-back at this point, thank you. Here is my remove function:

bool LinkedList::remove(const int item)
{//if the list is empty returns false
if(head == NULL) {return false;}

Node *hptr = head;
Node *tptr = tail;

if((hptr -> data) == item)
{//if the node is at the head of the list
  hptr = hptr -> next;
  delete head;
  hptr -> previous = NULL;
  head = hptr;
  --count;
  return true;

} else if((tptr -> data) == item) {
 //if the node is at the tail of the list
  tptr = tptr -> previous;
  delete tail;
  tail = tptr;
  tptr -> next = NULL;
  --count;
  return true;

} else {//if the node is in he middle of the list
  Node *ptr_head = head;   Node *ptr_headp = NULL;
  Node *ptr_tail = tail;   Node *ptr_tailp = NULL;

  while((ptr_head -> data) != item || (ptr_tail -> data) != item)
  {//pointers pass each other then data was not found
     if((ptr_tail -> data) < (ptr_head -> data)) {return false;}
   //traversing the list from the head and tail simultaniously
     ptr_headp = ptr_head;
     ptr_head = ptr_head -> next;

     ptr_tailp = ptr_tail;
     ptr_tail = ptr_tail -> previous;
  }

  if((ptr_head == ptr_tail) && ((ptr_tail -> data) == (ptr_head -> data)))
  {//the item is at the intersection of both head and tail pointers
     ptr_headp -> next = ptr_tailp;
     ptr_tailp -> previous = ptr_headp;
     delete ptr_head;
     delete ptr_tail;
     --count;
     return true;
  }

  if((ptr_head -> data) == item)
  {//the item is before middle node
     ptr_headp -> next = ptr_head -> next;
    (ptr_head -> next) -> previous = ptr_headp;
     delete ptr_head;
     --count;
     return true;
  }

  if((ptr_tail -> data) == item)
  {//the item is after the middle node
     ptr_tailp -> previous = ptr_tail -> previous;
    (ptr_tail -> previous) -> next = ptr_tailp;
     delete ptr_tail;
     --count;
     return true;
  }
}

return false;
}
4

2 に答える 2

2

これは、データ構造を少し変更することで、別のケースを統合することでロジックを大幅に単純化できる状況の一般的な例*です。

ロジックの主な問題は、チェックする条件がたくさんあることです。

  • 後に他のノードがある最初のノードを削除する
  • 他のノードが先行する最後のノードの削除
  • 唯一のノードの削除
  • 途中のノードを削除する

これらの 4 つの条件は、ノードの左側と右側に常にノードがあることを確認することで、最後の条件と同じにすることができます。これを行う方法は次のとおりです。

class LinkedList
{
private:
      struct Node
      {
         int data;
         Node *next;
         Node *previous;
      };

      int count;
      // The change begins here
      Node headTail;
      // End of the change

public:
      LinkedList() {head = NULL; tail = NULL; count = 0;} //Constructor

      void insert(const int );
      bool remove(const int );
      bool contains(const int );

      size_t lenght() {return count;}
};

headポインターはheadTailですnexttailポインターはそのですprevious。next と previous は両方とも、空のリストで自分自身を指しています。

dataのが使用されていないため、これは少し非効率的headTailです。リストは循環し、常に 1 つのノードが存在します。このノードを配置すると、中間のノードを安全に削除し、前のポインターと次のポインターを別のオブジェクトに属しているかのように更新できます。


*ここでは、目前の問題とは直接関係ありませんが、このアプローチの哲学を理解するのに非常に役立つ優れた読み物へのリンクを示します。

于 2013-09-25T15:48:29.337 に答える
1
// Locate the item to remove
Node* to_remove = head;
while(to_remove && to_remove->data != item)
  to_remove = to_remove->next;

// Do the removal if we found it
if(to_remove)
{
  // If it was at the head, advance the head to the next item
  if(to_remove == head)
    head = head->next;
  // If it was at the tail, advance the tail to the previous item
  if(to_remove == tail)
    tail = tail->previous;

  // Remove from the list
  if(to_remove->next)
    to_remove->next->previous = to_remove->previous;
  if(to_remove->previous)
    to_remove->previous->next = to_remove->next;

  // Free the removed node
  delete to_remove;
  count--;
  return true;
}

return false;
于 2013-09-25T15:41:50.957 に答える