【发布时间】:2015-07-24 00:56:47
【问题描述】:
当 main 使用 dlring 类型的 构造 变量操作时,使用这个模板类工作得非常好,但我的目标是允许 动态分配,所以我可以处理非预定义数量的双向链接循环列表,以允许使用以下功能:
- 通过使用节点位置(通过
迭代)或值输入。 - 同样适用于将两个列表链接为一个具有单个头/尾的列表 对。
- 节点从一个列表(实例)导出到另一个。
- 等
我很确定有一个我还不知道的优雅的解决方法,但是如果您没有足够的努力来解决,我认为向社区提出问题并不是一件好事。 (检查谷歌
因此,为了实现这个目标,我应该使用某种指针对指针 AFAIK 动态分配内存(通过构造函数调用)。如果有更聪明的方法来实现这些,请告诉我。我的解决方案尝试在这个 sn-p 的末尾给出。随意批评以下所有内容。
双向链表类头(简体)
template <typename T>
class dlring
{
struct node
{
T data;
node* prev;
node* next;
node(T t, node* p, node* n) : data(t), prev(p), next(n) {}
};
node* head;
node* tail;
public:
dlring():head(nullptr), tail(nullptr){}
bool empty() const { return ( !head || !tail ); }
//operator bool() const { return !empty(); }
void Push(T);
T pop_back();
~dlring()
{
while(head)
{
node* temp(head);
head=head->next;
delete temp;
}
}
};
我应该使用注释掉的 operator bool 重载吗?
pop_back 和 Push 方法:
template <typename T>
void dlring<T>::Push(T data)
{
head = new node(data, tail, head);
if( head->next )
{
head->next->prev = head;
tail->next = head;
}
if( empty() )
{
tail = head;
head->next=tail;
head->prev=tail;
tail->next=head;
tail->prev=head;
}
}
template<typename T>
T dlring<T>::pop_back()
{
if( empty() )
std::cout<<"List empty";
node* temp(tail);
T data( tail->data );
tail = tail->prev ;
if (tail != temp)
{
tail->next->next = head;
head->prev = tail;
}
else
{
head = nullptr;
tail = nullptr;
}
delete temp;
temp = nullptr;
return data;
}
我的尝试没有正确的行为:当我尝试通过迭代显示所有列表时,代码失败,在 head->dlist 的数据访问尝试上出现段错误[0] ,其中 0 是 k 的迭代。这是sn-p:
int main()
{
int k;
std::cout<<"Rings count?"<<std::endl;
std::cin>>k;
dlring<int>* dlist = new dlring<int>[k]; //I suppose I'm allocating *k*
//dlring<int> elements. this line is not confirmed to call the constructor.
(dlist[0]).Push(10);
(dlist[0]).Push(13);
(dlist[1]).Push(99);
/*{
while(!dlist[0].empty())
std::cout<<(dlist[0]).pop_back()<<" ";
std::cout<<std::endl;
while(!dlist[1].empty())
std::cout<<(dlist[1]).pop_back()<<" ";
}*/
//this section works perfectly fine, while this
for(int i=0;i<k;i++)
{
while(!dlist[k].empty())
std::cout<<(dlist[k]).pop_back()<<" ";
std::cout<<std::endl;
}
//is causing a segmentation fault while attempting to access dlist[*0*].tail->data.
std::cout<<(dlist[0]).head->data;
//line was checked and is confirmed to be functional,
//I suppose dlist[variable] has some trick I don't know yet.
//what I wish to look like an instance call would be *
return 0;
}
最好的问候。同样,请随意批评我的代码/逻辑任何。
【问题讨论】:
-
在谷歌漫游时发现这个: // 重载操作符 // Selector T* operator->() { return m_obj; } // 地址访问 T& operator* () { return *m_obj;有什么帮助吗?
-
我认为
pop_back中tail的设置不正确:tail->next->next = head;此时tail已经指向new tail,所以我'd settail->next = head; -
@dyp 是的,但要制作 new tail->next=head 我通过 new 引用 old tail i> 尾部-> 下一个。希望我没有弄错。
-
也许我误解了
tail的目的,但我就是不明白:难道head->prev == tail && tail->next == head不能保证所有非空列表(当然,在成员函数之外)?如果是这样,为什么需要两个数据成员? -
如果你牺牲一点空间并使用头节点(它不会成为集合的一部分),那么你的代码会更简单更快,因为极端情况(头和尾) 可从标头节点访问。而且您不必担心边界条件(push() 为空列表或 pop_back() 为一个元素的列表)。此外,如果您使用 pop_back() 直到列表变为空,您的析构函数也更简单、更安全。
标签: c++11 linked-list segmentation-fault dynamic-programming