【问题标题】:C++ Linked list destroy functionC++链表销毁函数
【发布时间】:2009-12-04 23:15:05
【问题描述】:

这是我上一个关于链表的question 的继续。我在这方面做了更多的工作,但我陷入了一些我需要实现的功能。我现在有疑问的是 destroy() 函数。

它应该释放每个 list_item 的内存。方法是从头到尾递归删除每个 list_item,直到找到 NULL。但是由于某种原因,它只会从结构中删除键值。节点仍然存在。

这是代码 我在 list_destroy() 中评论 delete(my_ this) 的原因是为了检查 list_item 是否被删除。

#include <iostream>

using namespace std;

struct list_item
{
    int key;                // identifies the data
    double value;           // the data stored
    struct list_item* next; // a pointer to the next data
};

// Why do you need this? And why would you want it anyway?
struct my_list
{
    struct list_item* first; // a pointer to the first element of the list
};

//+-----------------------------------------------------
//| Module:      list_init
//| Description: Initiate the list to an empty list
//| Input:       A pointer to the uninitialized list
//| Result:      The list is empty
//| Conditions:  Assumes the list is uninitialized
//+-----------------------------------------------------
void list_init(struct my_list* my_this)
{
    // ADD YOUR CODE HERE (approx 1 line)
    //set the list NULL at beginning
    my_this->first = NULL;
}

//+-----------------------------------------------------
//| Module:      list_add
//| Description: Insert a new key, value pair in a sorted list
//| Input:       The list to insert in and the key, value to insert
//| Result:      The list is sorted according to keys and include the
//|              new key, value pair
//| Conditions:  The list is assumed to be sorted before the insert
//|              Duplicate keys are allowed. The order of duplicate
//|              keys is undefined
//+-----------------------------------------------------
void list_add(struct my_list* my_this, int key, double value)
{
    // ADD YOUR CODE HERE (approx 23 lines)

    //create new list_item node
    list_item* new_node;

    //allocate memory to it
    new_node = new list_item;

    //adding values
    new_node->key = key;
    new_node->value = value;

    if ( my_this->first != NULL)
    {
        new_node->next = my_this->first;
    }
    else
    {
        new_node->next = NULL;
    }
    my_this->first = new_node;

}

//+-----------------------------------------------------
//| Module:      list_remove
//| Description: Remove the value with key from a sorted list
//| Input:       The list to remove from and the key of the value to remove
//| Result:      The list is sorted and do not contain a value with that key
//| Conditions:  The list is assumed to be sorted before the insert
//|              If duplicates of the key to remove exist only is removed.
//|              It is undefined which of the duplicates that are removed.
//+-----------------------------------------------------
void list_remove(struct my_list* my_this, int key)
{
    // ADD YOUR CODE HERE (approx 23 lines)
    list_item *curr;

    //allokera minne
    curr = new list_item;
    curr = my_this->first;

    list_item *prev = new list_item;

    for(int i=0; i<key;i++)
    {
      prev = curr;
      curr = curr->next;

    }
    prev->next = curr->next;
    delete(curr);
}

//+-----------------------------------------------------
//| Module:      destroy
//| Description: First destroy any next list item, then release the
//|              memory of the specified list item.
//|              This will recursively destroy an list starting on this item.
//| Input:       The list item to relese memory for (delete)
//| Result:      The memory used by the list item, and any linked items,
//|              are reclaimed by the OS
//|              Further use of the list item is invalid
//| Conditions:  The item is a pointer allocated with new and not
//|              deleted before
//+-----------------------------------------------------
void destroy(struct list_item* item)
{
    // ADD YOUR CODE HERE (approx 5 lines)
    list_item *temp = new list_item;


    if(item)
    {
        temp = item;
        item = temp->next;
        delete(temp);
        destroy(item);
    }


}

//+-----------------------------------------------------
//| Module:      list_destroy
//| Description: Free the memory of an entire list.
//| Input:       The list to destroy.
//| Result:      All memory used by the list is reclaimed by the OS.
//|              The list will become a valid but empty list.
//| Conditions:  The list is initiated and valid.
//+-----------------------------------------------------
void list_destroy(struct my_list* my_this)
{
  // ADD YOUR CODE HERE (approx 2 lines)
  destroy(my_this->first);
//  delete(my_this);
}

//+-----------------------------------------------------
//| Module:      clone
//| Description: First create a new copy of the specified list
//|              then append to the new item a clone of the next.
//|              This will recursively create a copy of a entire
//|              list starting on this item.
//| Input:       The list item to clone.
//| Result:      A copy of the specified item and any linked items.
//| Conditions:  The item is valid.
//+-----------------------------------------------------
struct list_item* clone(struct list_item* item)
{
  // ADD YOUR CODE HERE (approx 10 lines)

  return item;
}

//+-----------------------------------------------------
//| Module:      list_copy
//| Description: Copy an entire list
//| Input:       The list to copy
//| Result:      A new and valid list that are an independent copy
//| Conditions:  The list is initiated and valid.
//+-----------------------------------------------------
struct my_list list_copy(struct my_list* my_this)
{
    // ADD YOUR CODE HERE (approx 3 lines)
    my_list *copy = new my_list;
    copy = my_this;
    return *copy;

}


struct my_iterator
{
   struct list_item* current; // a pointer to the "current" list element
};

//+-----------------------------------------------------
//| Module:      list_begin
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
struct my_iterator list_begin(struct my_list* my_this)
{
  struct my_iterator i;
  i.current = my_this->first;
  return i;
}

//+-----------------------------------------------------
//| Module:      iterator_end
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
bool iterator_end(struct my_iterator* i)
{
  return i->current == NULL;
}

//+-----------------------------------------------------
//| Module:      iterator_next
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
void iterator_next(struct my_iterator* i)
{
  i->current = i->current->next;
}

//+-----------------------------------------------------
//| Module:      iterator_get_key
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
int iterator_get_key(struct my_iterator* i)
{
  return i->current->key;
}

//+-----------------------------------------------------
//| Module:      iterator_get_value
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
double iterator_get_value(struct my_iterator* i)
{
  return i->current->value;
}

//+-----------------------------------------------------
//| Module:      main
//| Description:
//| Input:
//| Result:
//| Conditions:
//+-----------------------------------------------------
int main()
{
    // ADD YOUR CODE HERE (approx 50 lines)
    my_list*list = NULL;
    list = new my_list;

    list_init(list);
    //list->first = NULL;


    int key = 0;
    double value = 0;

    int i =0;
    while(i <5)
    {
        ++i;
        cin>> value;
        value = (int) value;
        key = (int) value;

        list_add(list,key,value);
        cout << "Adding" << endl;


    }
//    my_list *list2 = new my_list;
//    list_init(list2);
//    list2 = list_copy(list);


    //destroy the list and its content
    list_destroy(list);

    list_remove(list, 3);
    cout << endl << "Print list" << endl;
    for(my_iterator i = list_begin(list); !iterator_end(&i); iterator_next(&i))
    {
        cout << iterator_get_key(&i) << " " << iterator_get_value(&i) << endl;
    }



    list_destroy(list);
    cout << endl << "Print list" << endl;
    for(my_iterator i = list_begin(list); !iterator_end(&i); iterator_next(&i))
    {
        cout << iterator_get_key(&i) << " " << iterator_get_value(&i) << endl;
    }

//    list_destroy(list2);
    return 0;
}

【问题讨论】:

  • 你为什么不想使用std::list?每次有人发明一个新列表。
  • 我怀疑这是家庭作业 - 所以给海报提示会比为他做他的工作或将他推荐给 std::list 更有帮助...
  • @Alexey:我敢打赌这是为了教育目的......
  • @Alexey,写一个链表是一种很好的学习体验,通常是很多课程的家庭作业。它教授算法复杂性、指针操作、界面设计等。实际上在实际应用中使用自己的链表实现而不是 std::list 通常不是一个好主意。
  • @Alexey,是的,它是出于教育目的。所以使用 std::list 是不可能的

标签: c++ linked-list


【解决方案1】:

好的。您不应该在销毁函数中分配新的列表项。 相反,我会这样做:


void destroy(struct list_item* item)
{
    // ADD YOUR CODE HERE (approx 5 lines)
    if(item)
    {
        list_item *temp = item;
        item = temp->next;
        delete temp;
        destroy(item);
    }

删除操作符不是一个函数,所以你可以去掉括号。 将其作为递归函数执行也有点不寻常。没有错,但是代码更像:


void destroy(struct list_item* item)
{
    // ADD YOUR CODE HERE (approx 5 lines)
    while(item)
    {
        list_item *temp = item;
        item = temp->next;
        delete temp;
    }

【讨论】:

    【解决方案2】:

    删除所有节点后,需要将first指针设置为NULL。由于您没有这样做,因此您的代码在 destroy 操作之后访问已释放的内存。

    【讨论】:

      【解决方案3】:

      destroy() 函数的主要内容几乎是正确的 - 唯一真正的错误是分配 new list_item 写入 temp 并在 item 参数不是 NULL 时立即覆盖.为什么你认为当你对它们调用delete 时列表项没有被删除? (注意:delete 调用并未将指针设置为 NULL,但指向的对象仍然被删除。)请澄清!

      顺便说一句,您销毁整个列表的递归方法仅适用于达到一定长度的列表 - 对于长列表,您可能会收到 Stack overflow 错误,因为有太多的 destroy() 嵌套调用。最好为此使用循环。

      【讨论】:

      • 当我要求删除时,list_item 实际上并没有被删除,只是指向它的指针?那么 list_item 会发生什么,它是否仍然存在于内存中,只是会话丢失了指向它的指针?
      • list_item 被删除,但指针仍然“指向”list_item 曾经存在的内存。您在问题中说“它只会删除键值,但不会删除节点”-您是如何得出这个结论的?
      【解决方案4】:

      以下应该可以解决问题:

      void destroy(struct list_item* item)
      {
        struct list_item *temp;
        while (item)
        {
           temp = item;
           item = temp->next;
           delete(temp);
        }
      }
      

      或者,如果您更喜欢递归解决方案:

      void destroy(struct list_item* item)
      {
        if (item) {
          destroy(item->next);
          delete(item);
        }
      }
      

      【讨论】:

      • 不喜欢递归解决方案。除非它被优化为非递归,否则大列表将导致堆栈溢出异常(在 C++ 中通常会导致您的程序消失得无影无踪)。你唯一会使用它的时候是当你的老板/老师对局部变量有仇视时(不幸的是,我没有编造这个)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      • 2016-11-10
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 2017-03-15
      • 2012-03-15
      相关资源
      最近更新 更多