【问题标题】:Accessing and Changing Objects in Linked List c++访问和更改链表 c++ 中的对象
【发布时间】:2016-08-08 19:50:14
【问题描述】:

我已经找到了关于从链表中插入和删除对象的问答。但我的问题是从链接列表访问和更新这些对象。

以下代码是学校项目的一部分,我需要在其中制作工资单对象的链接列表。我需要能够插入、删除、按特定参数搜索以及更新员工工资单信息。我在插入和删除时没有问题。但是我对如何搜索和访问这些对象以与它们的变量进行交互有点迷茫。

在 InList 函数中,我传递了一个链表和一个 int,创建 Payroll 对象并将该 int 分配为员工编号变量。然后我使用 P 的搜索函数并将该工资单对象作为参数传递。

void InList(const orderedLinkedList<Payroll>& P, int employee_number)
{
    Payroll payListEmpNum;
    payListEmpNum.setEmployeeNumber(employee_number);

    if (P.search(payListEmpNum) == 1)
    {
        payListEmpNum.printPayroll();//this is just printing my local employee_number.
    }
    else 
    {
        cout << "Sorry, that employee was not found.\n" << endl;
    };
}

这是我的有序链接列表类的搜索功能。它遍历列表,并根据我发送的对象测试每个对象的员工编号。我可以将当​​前指针发送到我的 Payroll 类以打印记录,但这并不能让我访问数据。

template <class Type>
bool orderedLinkedList<Type>::search(const Type& searchItem) const
{
    bool found = false;
    nodeType<Type> *current; //pointer to traverse the list


    current = first;  //start the search at the first node

    while (current != NULL && !found)
        if (current->info >= searchItem)
            found = true;
        else
            current = current->link;

    if (found) {
        found = (current->info == searchItem); //test for equality
    }
    return found;
}//end search

但是,由于搜索函数不返回任何数据,InList 只打印我的局部变量,employee_number,并且为所有其他变量打印 null。

我不确定如何访问我的对象的变量。我应该写一个不同的函数来处理这个吗?这是指针问题吗?

谢谢!

【问题讨论】:

  • 在设计链表时应该注意这一疏忽。如果用户无法获取存储在其中的信息,那么链表(或任何其他数据结构)有什么用?对字符串类进行成像,您无法从中取出字符串。是否有意义?所以你应该做的可能就是做STL做的事情,那就是返回一个指向找到的数据的指针,如果没有找到,则为NULL。
  • 我同意一个名为search 的成员函数不应该返回布尔值,而是返回指向找到的第一个元素的指针(如果找到的话),以及指向 null 的指针(如果没有找到的话)。
  • template &lt;class T&gt; const T *find( const orderedLinkedList&lt;T&gt;&amp; list, std::function&lt;bool(const T&amp;)&gt; predicate ) 看起来不错。如果您的列表按某个键排序,则无需重新排序就无法修改该键。对于其他条目,您当然可以更改。那么上述函数的非常量版本就可以工作了。
  • 嗯,这个链表类是由我用于该类的书提供的。所以,不是我写的,而是必须要用的。

标签: c++ pointers object linked-list


【解决方案1】:

因为这是一个学校项目,所以一切都是关于学习的。所以这里提到了几点,它们可以帮助您解决这个问题和未来的类似问题:

  • 您编写的列表名称是orderedList&lt;T&gt;。因此,人们会假设列表是按某个键排序的,这可能是T 的一部分。因此,如果搜索该键,人们会假设它不是线性搜索,而是使用一些更快的搜索算法find() or search() 以及 exists() 函数。
  • 另一方面,如果需要按用于对列表进行排序的键以外的条件搜索列表,线性搜索是可以的,但find 函数应该允许按任意条件搜索。
  • 问题中显示的代码的一个小缺点可能是(除非在未显示的部分代码中变得很明显),哪个键用于对列表进行排序。因此,提供一个返回非常量元素的search() 函数是危险的,因为用户可能会不小心修改返回元素的键,从而破坏列表的排序。
  • 现在已经不是什么大秘密了,例如,C++ 标准库中已经有一个列表std::list。那么,与其为普通函数发明新名称,为什么不简单地查找标准类的函数并重用这些名称呢? 2 好处: 1. 了解标准类型的用户,可以更快地使用你的代码。 2. 当他们开始使用标准库时,您和其他人将学到一些他们可以重用的东西。
  • 正如我们所见,更改列表中的元素可能是危险的、致命的,还有其他选择:删除找到的元素,更改/复制它,修改它并重新插入到列表中。这样,您可以确保不会损害列表的实现。

因此,我建议选择不可变的一面,并提供类似于下面的功能用于普通搜索目的。顺便说一句,请注意,在 std 库中完成的迭代器概念将有助于将此函数重用于其他用例。

template <class T>
const T* find(const orderedList<T> & list, std::function<bool(const T&)> predicate)
{
     const nodeType<T> *current = list.head(); 
     while( nullptr != current )
     {
         if( predicate(current->info) ) // assuming info is of type T...
             return &current->info;
         current = current->link;
     }
     return nullptr;
}

出于变异目的,您可以考虑如下函数:

template <class T>
bool replace( orderedList<T>& list, std::function<bool(const T&)> predicate, 
    std::function<void(T&)> modifier )
{
     // pseudocode:
     // 1. find node (nodeeType<T>), like in find() above.
     // 2. remove that node from the list.
     // 3. call modifier(node->info)
     // 4. re-insert node into list, using insert() or similar.
     // 5. return true, if a replacement has been done, false if element 
     // was not found and list did not change.
}

显然,我选择了独立函数而不是列表类的成员函数。特别是如果列表已经完成,与其一遍又一遍地修改它,不如简单地编写使用列表类型但不是列表成员的算法函数。

// Sample application code:
#include <functional>
#include <orderedList>
#include <cstdint>

struct Payroll
{
    uint32_t employee_id;
    float salary;
};

typedef orderedList<Payroll> PayrollList;

bool change_salary( PayrollList& list, uint32_t emp_id, float newSalary )
{
    return replace( list, [&]( const Payroll& payroll ) -> bool {
            if( emp_id == payroll.employee_id )
                 return true;
            return false;
        }, [&](Payroll& payroll) {
             payroll.salary = newSalary;
        });
}

【讨论】:

    【解决方案2】:

    你应该有一个函数,如果它存在则返回指向该项目的指针,否则返回 nullptr。

    template <class Type>
    const Type* orderedLinkedList<Type>::search(const Type& searchItem) const
    {
        bool found = false;
        nodeType<Type> *current; //pointer to traverse the list
    
        current = first;  //start the search at the first node
    
        while (current != nullptr)
        {
            if (current->info == searchItem)
                return &current->info;
            current = current->link;
        }
        return nullptr;
    }
    

    如果你还想拥有true / false的功能,可以使用上面的:

    template <class Type>
    bool orderedLinkedList<Type>::exists(const Type& searchItem) const
    {  return search(searchItem) != nullptr; }
    

    请注意,在search 中,我们返回一个指向实际数据的指针,而不是指向nodeType 的指针。原因是如果这个函数是public,而nodeType是链表的一个实现细节,返回nodeType对用户来说可能没有意义。

    用户不应该知道或关心nodeType 是什么或其用途。有意义的是用户存储在链表中的数据,这就是返回的数据。

    【讨论】:

      【解决方案3】:

      您需要返回一个指向在搜索函数中找到的对象的指针。如果未找到,则返回无效 (NULL)。

      模板

      nodeType<Type> * orderedLinkedList<Type>::search(const Type& searchItem) const
      {
          bool found = false;
          nodeType<Type> *current; //pointer to traverse the list
      
      
          current = first;  //start the search at the first node
      
          while (current != NULL && !found)
              if (current->info >= searchItem) {
                  if (current->info == searchItem)
                      return current;
                  else 
                      return nullptr;
              }
              else
                 current = current->link;
      
      
          return nullptr;
      }//end search
      

      【讨论】:

      • 在现代 C++ 中,我们不应该使用NULL,而应该使用nullptr
      • @antiHUMAN 使用现代 C++,我们将使用 std::list 等,而不是编写我们自己的列表;)
      • 我说的是核心语言,而不是选择使用或不使用哪些库。 NULL 属于 int 类型,在比较或将其分配给指针地址时没有多大意义。 nullptr 是指针类型,编译器可以识别。虽然它通常无关紧要,但有时它确实会产生歧义,当我们拥有这个新关键字时,最好使用它。当它更正确时,为什么使用它?
      • 您返回的是nodeType,而不是实际数据,因此调用者可能无法理解如何处理nodeTypenodeType 是客户端不应该知道或关心的链表的实现细节。
      • @PaulMcKenzie 作者可能需要nodeType在列表中做一些操作。
      猜你喜欢
      • 2017-02-02
      • 2011-09-27
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 2020-03-31
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      相关资源
      最近更新 更多