【问题标题】:Linked List : remove() and search() methods do not work properly when value not in list链表:当值不在列表中时,remove() 和 search() 方法无法正常工作
【发布时间】:2013-12-17 20:23:06
【问题描述】:

所以我试图在 C++ 中创建一个模板链接列表类。一切都很完美,包括有问题的 remove() 和 search(),除非我对不在 LinkList 中的值调用这两种方法。理想情况下,我希望方法在发现值不在 list 之后返回,但是,我觉得这些方法会继续并尝试进一步删除或搜索值,因为当我运行可执行文件时,我得到“分段错误(核心转储)”错误。如果在空列表上调用方法,程序将打印正确的错误。

列表与头单独链接,并使用“智能节点”(即包含自己的方法以补充匹配的类方法的节点,而不是不包含任何方法并要求类方法的“哑节点”来​​实现)创建指向节点的临时指针并遍历列表)。

这里是 search() 和 remove() 的实现。当然,如果需要,我可以提供更多代码:

//==========================REMOVE================================

template <class T>
void TLinkedList<T> :: remove(T value){
  if(!head){                               //if there is no head
    std::cerr << "Error: List is Empty" << std::endl;  // The list is empty
    return;
  }
  if(head->data == value){
    listSize--;     //decremenets listSize since a node is removed
    node * temp = head;
    head = head->next;
    delete head;
    return;
  }
  else{
    if(head->remove(value)){  //If something was removed as a result of the node's remove()
      listSize--;
      return;                 //decrement listSize since something was removed
    }
    else{                     //else if nothing removed
      std::cerr << "Error : Value not in list" << std::endl;
      return;
    }
  }
}

template <class T>
bool TLinkedList<T> :: node :: remove(T value ){  //returns a bool. If something was removed, returns true. If nothing was removed, returns false
  if(next-> data == value){
    node * temp = next;
    next = next->next;
    delete temp;
    return true; //something removed
  }
  if(!next){
    return false;
  }
  else{
    return next -> remove(value);
  }
}


//==============SEARCH===================
template <class T>
T TLinkedList<T> :: search(T value){
   if(!head){
    std::cerr << "Error: List is empty" << std::endl;
    return 0;
  }
  if(head->data == value){  //If head's data is the value searched for
    return head->data;      //return head's data
  }
  else{
    return head->search(value);
  }

}

template <class T>
T TLinkedList<T> :: node :: search(T value){
  if(data == value){
    return data;
  }
  if(!next){
    std::cerr << "Error: Value not in list" << std::endl;
    return 0;
  }
  else{
    return next->search(value);
  }
}

所以,对于 main(),例如:

int main(){

    TLinkedList ll;
    ll.prepend(5); //adds 5 to list
    ll.remove(4); // value of 4 not in list
    // OR ll.search(4);
    return 0;
}

cerr 没有发生,并且给出了“Segmentation Fault (core dumped)”错误。

非常感谢任何帮助。谢谢!

编辑:另外,在 search() 方法中,您可能会注意到我返回 0;发生错误时。此实现是在遇到错误时尝试停止该方法;理想情况下,如果遇到错误,我宁愿搜索不返回任何内容

【问题讨论】:

  • 您应该让您的搜索函数返回包含正在搜索的元素的节点,如果未找到该元素,则返回nullptr。然后你的删除将简单地调用搜索然后删除元素

标签: c++ linked-list


【解决方案1】:

代码在几个地方被破坏。以下是我发现的:

  1. 如果要删除第一个节点,则删除新的头而不是第一个节点。您可能打算使用

    delete temp;
    

    而不是

    delete head;
    
  2. 如果列表中只有一个节点与该值不匹配,...::node::remove() 函数将访问一个不存在的节点。您需要检查 next 在访问其值之前是否指向某些东西。实际上,由于最终列表将只有一个元素的尾部,这解释了您的崩溃之一。你可能想要类似的东西

    if (!next) { /* error goes here */ }
    else if (next->value == value) { /* successful return goes here */ }
    else { /* recursion goes here */ }
    
  3. ...::node::search() 函数有同样的问题,解释了你的另一个崩溃。不过,这个函数似乎有一个相当无意义的接口:您搜索一个值,如果找到一个值,则返回搜索到的值。否则返回0,这意味着您可以与search() 方法一起使用的所有类型T 需要有一个接受0 的构造函数。这似乎是一个相当严厉的限制。您可能希望将迭代器返回到找到的对象或返回到列表末尾的迭代器。

请注意,管理列表的递归方法在 C++ 中肯定不能很好地工作。这些函数的编写方式允许尾递归,但我不认为 C++ 有任何保证尾递归实际实现的保证,即在遍历长列表时很容易耗尽堆栈空间。

【讨论】:

    【解决方案2】:

    据我所知,错误可能来自您的preprend() 方法。此外,正如其他人在他们的帖子中所说,您的实施缺乏检查和安全性。

    为什么不用STLBoost 链接列表,它们已经存在并且通常满足目的?

    【讨论】:

      【解决方案3】:

      根据我上面的评论,您的搜索功能应该是这样的:

      //==============SEARCH===================
      template <class T>
      T TLinkedList<T>::search(T value){
          if(!head){
              std::cerr << "Error: List is empty" << std::endl;
              return 0;
          }
          else if(head->data == value){  //If head's data is the value searched for
              return head->data;      //return head's data
          }
      
          typename TLinkedList<T>::node *temp = head->search(value);
          if (temp)
              return temp->data;
          return 0;
      }
      

      节点::搜索

      template <class T>
      typename TLinkedList<T>::node *TLinkedList<T> :: node:: search(T value) {
          if(data == value){
              return this;
          }
          else if(!next){
              std::cerr << "Error: Value not in list" << std::endl;
              return nullptr;
          }
          return next->search(value);
      }
      

      TLinkedList::remove(T)

      //==========================REMOVE================================
      
      template <class T>
      void TLinkedList<T> :: remove(T value){
          if(!head) {                               //if there is no head
              std::cerr << "Error: List is Empty" << std::endl;  // The list is empty
              return;
          }
          else if(head->data == value){
              listSize--;     //decremenets listSize since a node is removed
              node *tmp = head;
              head = head->next;
              delete tmp;
              return;
          }
      
          node *tmp = head->search(value);
      
          if (tmp != nullptr) {
              listSize--;     //decremenets listSize since a node is removed
              node *tmp2 = tmp;
              tmp = tmp->next;
              delete tmp2;
          }
          else std::cerr << "Error : Value not in list" << std::endl;
      }
      

      【讨论】:

        【解决方案4】:

        让我们从您的方法 remove 包含几个错误开始。首先考虑方法void TLinkedList&lt;T&gt; :: remove(T value); 在这段代码中,sn -p 你删除了列表的头部

          if(head->data == value){
            listSize--;     //decremenets listSize since a node is removed
            node * temp = head;
            head = head->next;
            delete head;
            return;
          }
        

        必须

          if(head->data == value){
            listSize--;     //decremenets listSize since a node is removed
            node * temp = head;
            head = head->next;
            delete temp; // <==
            return;
          }
        

        在函数bool TLinkedList&lt;T&gt; :: node :: remove(T value );你不检查数据成员next是否等于0。所以这段代码有未定义的行为

          if(next-> data == value){ <== next can be equal to 0
        

        你应该改变这些条件的顺序

          if(!next){
            return false;
          }
          if(next-> data == value){
            node * temp = next;
            next = next->next;
            delete temp;
            return true; //something removed
          }
        

        对于方法搜索,我将按以下方式定义它们

        template <class T>
        TLinkedList<T>::node * TLinkedList<T>::search( const T &value ) const
        {
            return ( head == nullptr ? nullptr : head->search( value ) );
        }
        
        template <class T>
        TLinkedList<T> :: node * TLinkedList<T>::node::search( const T &value ) const
        {
           if ( data == value ) return this;
        
           return  ( next == nullptr ? nullptr : next->search( value ) );
        }
        

        【讨论】:

          猜你喜欢
          • 2014-03-24
          • 1970-01-01
          • 2021-05-21
          • 1970-01-01
          • 2021-08-10
          • 1970-01-01
          • 1970-01-01
          • 2013-03-31
          相关资源
          最近更新 更多