C++ 中的双链表

Posted

技术标签:

【中文标题】C++ 中的双链表【英文标题】:Double Linked Lists in C++ 【发布时间】:2010-12-25 13:07:47 【问题描述】:

我有一个任务要求我们实现一个双向链表类。出于某种原因,他们将节点 struct 定义如下:

struct node 
  node   *next;
  node   *prev;
  T      *o;
;

在我看来,如果结构成员“数据”不是指针,编写类会容易得多。不用说我无法改变它,所以我将不得不解决它。我尝试实现将元素添加到列表开头的方法,如下所示:

template <typename T>
void Dlist<T>::insertFront(T *o) 
    node *np = new node;
    T val = *o;

    np->o = &val;
    np->prev = NULL;
    np->next = first;

    if (!isEmpty()) 
        first->prev = np;
     else 
        last = np;
    
    first = np;

在使用 ddd 进行调试时,我意识到第一次插入数字时一切正常,但第二次时一切都搞砸了,因为一旦将 'val' 设置为新元素,它就会“覆盖”第一个元素因为使用了 val 的内存地址。我尝试做其他事情,而不是让 'val' 变量执行以下操作:

T *valp = new T;
T val;
valp = &val;
val = *o;

np->o = valp

这似乎也不起作用。我认为这是因为它几乎只是我上面所做的更复杂的形式,只是额外的内存泄漏:)

任何正确方向的想法/指针都会很棒。

【问题讨论】:

+1 荣誉作业免责声明。 看看这个,第一个答案可能会帮助你理解问题:***.com/questions/5727/… 如果有机会也可以看看这个:***.com/questions/599308/… -- 堆栈和堆分配之间的区别。 【参考方案1】:

您创建的T val 是一个自动变量。您的错误是将地址存储到该堆栈变量中。

正如您所怀疑的,您应该使用new 在堆上分配空间,但您的数据指针需要直接指向new 返回的地址。

你最近一次尝试的错误在这里:

valp = &val;

您正在将valp 更改为指向其他地方(val 的地址),而您可能试图复制 val 的数据,而不是其地址。

应将传递给您的函数的数据复制到valp 指向的新内存中。

【讨论】:

啊。这对于为什么我在尝试读取值时返回值 -1074723840 是有道理的。这有帮助,尽管我想我仍然不太确定如何解决这个问题?你能给我一些可能对我的搜索有帮助的关键字吗?谢谢。 只是吹毛求疵:val 不是临时的。它是一个“自动”变量,也就是堆栈变量。否则,很好的答案。 已编辑,希望能回答您的评论。 完全正确,丹。而且不吹毛求​​疵。我在那里用错了术语。【参考方案2】:

认为指针有效负载不方便。但也许该列表旨在用于在现有对象之上创建一个链接,例如:

struct A  int i; ;
A as[10] =  1,2,3,4,5,6,7,8,9,10 ;

LinkedList primes_in_my_data;
insertFront( primes_in_my_data, &as[1] );
insertFront( primes_in_my_data, &as[2] );
insertFront( primes_in_my_data, &as[3] );
insertFront( primes_in_my_data, &as[5] );
insertFront( primes_in_my_data, &as[7] );

// now I have a linked list of primes, and caused no extra memory allocation
// (except for the list overhead)

【讨论】:

【参考方案3】:

我认为你不应该这样做:

T val = *o;

由于节点结构中的o 成员是一个指针,而insertFront 的参数也是一个指针,你的导师可能打算让你把你给的指针存储在列表中,不要复制对象并存储指向该对象的指针。只需将传递给insertFronto 指针存储为节点的o 成员就可以了。

【讨论】:

我完全同意。应该是np-&gt;data = o; 不一定。应该有一些 cmets 解释传入的 T* 是否是动态分配的,以及 DList 是否应该拥有它或是否应该制作副本。如果您不知道这些问题的答案,除非靠运气,否则您不可能正确实施。 @Sammy,你怎么知道它不应该是np-&gt;data = new(*o); 对不起,我把结构复制到 SO 后修改了,忘了在其他地方更改。【参考方案4】:

您的代码不符合您对node 的定义——在node 中您定义了一个data 成员,但在您的代码中您使用的是o

在任何情况下,您都必须进行两次动态分配来添加每个节点——一次分配给节点本身,另一次分配给它要指向的数据对象。当您分配该数据对象时,您不妨将new 的返回值直接分配给节点中的指针。然后,您需要将指针传递到您刚刚分配的数据对象中的数据对象复制到节点中的指针所指向的数据对象中。

【讨论】:

好收获。我将结构复制到 SO 后修改了它,忘记在其他地方更改它。【参考方案5】:
 T val = *o;

    np->o = &val;

这部分是可疑的。提示是,一旦函数超出范围,在函数堆栈上分配的内存将不可用。

【讨论】:

以上是关于C++ 中的双链表的主要内容,如果未能解决你的问题,请参考以下文章

c++学习笔记_c++实现双链表

c++,在哈希表中显示内容的方法。使用双链表

c++双链表构造函数运算符重载析构函数增删查改及逆置等

深度解析数组单链表和双链表

C++实现双向链表的所有操作,包括逆置双链表(三种方法)

有序的双链表的实现