【问题标题】:C++ Linked list copy and clone functionC++链表复制克隆功能
【发布时间】:2010-12-23 14:38:36
【问题描述】:

这也是我的链表questions的延续

我没有得到关于删除的答案。调用delete时是删除了实际值还是只是指向它的指针?

这次我的问题是关于 clone() 和 list_copy() 函数。我想用这些功能做的是;

  1. 首先调用列表 _copy() 将一个结构复制到一个新结构中。

  2. list _copy() 调用 clone() 将递归克隆所有节点

我现在使用该功能的问题是它会复制。但是,我只得到一个指向相同值的新结构,而不是一个独立的新结构。不知道是什么问题?

#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)
    if(item)
    {
        list_item *temp = item;
        item = temp->next;
        cout << "Destroy item" << endl;
        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);
  cout << "Destroy list" << endl;
  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)

    list_item *new_node = new list_item;

    if(item != NULL)
    {
        new_node->key = item->key;
        new_node->value = item->value;
        new_node->next = item->next;

        cout <<"Clone "<< item->key << ". " << item->value << endl;
        clone(item->next);
    }
    else
    {
        new_node->next = NULL;
        cout << "END" << endl;
    }

    return new_node;
}

//+-----------------------------------------------------
//| 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)

    //copy of the list which will be returned
    my_list *foo = new my_list;


    list_item *temp = new list_item;
    list_item *temp2 = new list_item;


    temp = my_this->first; //head

    temp2 = clone(temp);

    foo->first = temp2;

    //this is to check whether clone() worked
    while(temp2)
    {
        cout << "Did it work? " << temp2->value << endl;
        temp2=temp2->next;
    }

    return *foo;

}


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);




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



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


    cout << endl << endl;


    list_destroy(list);

    cout << endl << "Print list1" << 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;
}

【问题讨论】:

  • 您提供的代码更接近于纯 C 而不是 C++(除了使用 iostreams 之外,其余部分几乎可以立即在 C 中编译)。您想学习 C 还是 C++?如果您想学习 C++,我建议您正确实现类并从构造函数和析构函数开始,RAII 是一种强大的技术,应该从一开始就学习。
  • @dribeas。 C++,但是我在 Internet 上找到了这个链表任务。下一个任务是使用类来实现这个链表。所以我想在继续使用类之前先了解这一点。
  • 顺便说一句,我认为您要么误解了 list_add 函数,要么实现有问题。您总是在列表的最开头插入新节点,而不是在它们应该根据键顺序的位置。

标签: c++ linked-list


【解决方案1】:

这里有很多代码。很难看到每一件事

new_node->next = item->next;

next 是一个指针。所以你在这里所做的是复制指针的值(地址到内存中),而不是值。因此,两个结构(原始结构和克隆结构)都指向同一个位置。

键和值不是指针,因此它们的值将被复制并实际克隆数据。

请注意,在您的 clone 函数中调用 clone 时,没有指向内存分配的指针。所以你将无法对其调用 delete ,并且会出现内存泄漏。

编辑这可能是一个解决方案:

list_item* clone(list_item* item)
{
    list_item *new_node = new list_item;

    if(item != NULL)
    {
        new_node->key = item->key;
        new_node->value = item->value;
        //NOTE: this is probably what you want
        new_node->next = clone(item->next);
        cout <<"Clone "<< item->key << ". " << item->value << endl;
    }

    // NOTE: the clone of NULL should be NULL, not a new list item !
    return new_node;
}

但是,由于它是出于教育目的(否则您将使用 std::list),请尝试使用 C 而不是 C++ 进行开发。每次添加新函数或成员时,运行 valgrind 以确保没有问题。然后再去实现一个新功能。

【讨论】:

  • 但是我克隆的值 new_node->key = item->key;新节点->值=项目->值;不是源结构的副本吗?
  • 是的,它们是副本。但是你为什么要做 clone(item->next); ?这将返回一个指向新分配的东西的指针。也许您应该从从 C 切换到真正的 C++ 开始。只为下一项使用成员函数、析构函数和指针(并且仅在列表中添加新项时使用关键字“new”)您的代码将更小、更自然且更易于理解。你就是不能扔 200 行代码就问哪里出了问题。
  • clone(item->next) 获取要克隆的值行中的下一个。是的,我插入了整个代码,以防有人想运行它。但我的问题只集中在两个功能上。所以它更像是 20 行代码。
【解决方案2】:

我将从纯粹的 C++/面向对象的角度回答这个问题(这个问题被标记为 C++),即使您的代码更接近 C 并且您可能期待 C 解决方案。从 cmets 看来,这是您正在尝试实施的某种练习,而 cmets 似乎是针对 C 课程的。

我没有得到关于删除的答案。调用delete时是删除了实际值还是只是指向它的指针?

当你delete 一个指针时,所指向的实例的析构函数(对于类类型)被调用,然后内存被释放。对于您没有为其提供析构函数的任何类(结构也是类),编译器将为您生成一个。

隐式生成的析构函数将调用每个子对象的析构函数(如果存在),但它不会删除任何内容(也就是说,不会释放内存)。

如果您的类需要管理资源(包括内存),您应该使用 RAII 技术。两种最简单的方法是实现自己的析构函数,或者将资源存储在 RAII 对象(通常是智能指针)中。

在 C 中,没有析构函数之类的东西,也没有 RAII……但同样的事实也适用:它不会为您释放列表的其余部分,您必须手动删除列表的其余部分列表中的元素。

我现在使用该功能的问题是它会复制。但是,我只得到一个指向相同值的新结构,而不是一个独立的新结构。不知道是什么问题?

最简单的答案是您应该提供一个复制构造函数来复制列表的尾部。

【讨论】:

    【解决方案3】:

    假设您有一些小纸条。你的朋友在上面写信拼写创意信息。当他向您询问一些单据时,就像打电话给new 操作员一样。当他完成并将它们还给您时,那就是delete。没有任何东西被破坏:这是所有权问题。

    在他归还它们之后,您的朋友可能仍然能够识别出他正在使用的特定纸条。这就像有指向那张纸条的指针,但你可以把它交给其他人。不能保证他写的信在他还给你之后会一直留在那里。

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-25
      • 1970-01-01
      • 1970-01-01
      • 2011-06-30
      • 2017-07-22
      相关资源
      最近更新 更多