问题描述
我有一个双链列表类,其中有一个函数使用我的类迭代器遍历集合。但是在1个特定的地方,它运行了一个额外的循环,我无法弄清楚为什么。
当前合并模板
template <typename T>
void DlList<T>::merge(SortedList& other) {
iterator it = back_->prev_;
iterator oit = other.begin();
while (oit.current_->next_ != NULL) {
std::cout << *it << " " << *oit << std::endl;
it.current_->next_ = oit.current_;
back_->prev_ = oit.current_;
//back_->prev_->next_ = back_;
//other.back_->prev_ = other.back_->prev_->prev_;
it++;
oit++;
}
}
它总是会反复执行,并且会花费额外的时间,并且在列表中添加了一个空节点,我不明白为什么。
任何见识都非常有用!
编辑添加了完整的项目示例以解释功能的意图 我正在研究模板化的数据结构类,该类是使用哨兵节点的双向链表。 该列表是基于insert()排序的,并且我正在使用合并功能,其中每个列表的节点必须组合到this-> list中。节点必须移动并且不能创建新节点。并且如果两个列表中都存在相同的值,则另一个节点值必须在当前节点值之后。
我编码了我认为是逻辑的实现,但是我得到的输出不符合预期,结果对我来说也没有意义,因此如果有人可以解释我如何获得结果,将不胜感激。
class SortedList {
struct Node {
T data_;
Node* next_;
Node* prev_;
Node(const T& data = T{},Node* nx = nullptr,Node* pr = nullptr) {
data_ = data;
next_ = nx;
prev_ = pr;
}
};
Node* front_;
Node* back_;
public:
class const_iterator {
friend class SortedList;
Node* current_;
const_iterator(Node* n)
{
current_ = n;
}
public:
const_iterator() {
//Set to safe state
current_ = nullptr;
}
const_iterator& operator++() {
current_ = current_->next_;
return *this;
}
const_iterator operator++(int) {
const_iterator old = *this;
current_ = current_->next_;
return old;
}
const_iterator& operator--() {
current_ = current_->prev_;
return *this;
}
const_iterator operator--(int) {
const_iterator old = *this;
current_ = current_->prev_;
return old;
}
bool operator==(const_iterator rhs) {
return (current_ == rhs.current_) ? true : false;
}
bool operator!=(const_iterator rhs) {
return !(*this == rhs);
}
bool operator>(const_iterator rhs) {
return current_->data_ > rhs->current_->data_;
}
const T& operator*()const {
return current_->data_;
}
};
class iterator :public const_iterator {
friend SortedList;
iterator(Node* n) :const_iterator(n) {};
public:
iterator() : const_iterator() {};
//prefix
iterator& operator++() {
this->current_ = this->current_->next_;
return *this;
}
//post-fix
iterator operator++(int) {
iterator old = *this;
this->current_ = this->current_->next_;
return old;
}
iterator& operator--() {
this->current_ = this->current_->prev_;
return *this;
}
iterator operator--(int) {
iterator old = *this;
this->current_ = this->current_->prev_;
return old;
}
T& operator*() {
return this->current_->data_;
}
const T& operator*()const {
return this->current_->data;
}
};
SortedList(); //done
~SortedList();
SortedList(const SortedList& rhs);
SortedList& operator=(const SortedList& rhs);
SortedList(SortedList&& rhs);
SortedList& operator=(SortedList&& rhs);
iterator begin() {
return iterator(front_->next_);
}
iterator end() {
return iterator(back_);
}
const_iterator cbegin() const {
return const_iterator(front_->next_);
}
const_iterator cend() const {
return const_iterator(back_);
}
iterator insert(const T& data);
iterator search(const T& data);
const_iterator search(const T& data) const;
iterator erase(iterator it);
void merge(SortedList& other);
bool empty() const;
int size() const;
};
首次合并功能尝试
template <typename T>
void SortedList<T>::merge(SortedList& other) {
iterator it = this->begin();
iterator oit = other.begin();
while (oit != other.end()) {
std::cout << *oit << " " << *it << std::endl;
if (*oit < *it) {
oit.current_->prev_->next_ = oit.current_->next_;
oit.current_->next_->prev_ = oit.current_->prev_;
oit.current_->next_ = it.current_;
oit.current_->prev_ = it.current_->prev_;
it.current_->next_ = oit.current_;
}
else {
oit.current_->prev_->next_ = oit.current_->next_;
oit.current_->next_->prev_ = oit.current_->prev_;
oit.current_->next_ = it.current_->next_;
oit.current_->prev_ = it.current_;
it.current_->prev_ = oit.current_;
}
oit++;
it++;
}
}
主测试器
int main() {
int num[] = { 3,5,1,2,6,8,9,11 };
int num2[] = { 1,4,12,7,9 };
SortedList<int> l;
SortedList<int> l2;
for (int i = 0; i < 8; i++)
{
l.insert(num[i]);
l2.insert(num2[i]);
}
SortedList<int>::iterator result;
SortedList<int>::iterator result2 = l2.begin();
result = l.begin();
while (result != l.end()) {
std::cout << *result << " " << *result2 << std::endl;
++result;
++result2;
}
l.merge(l2);
1 1
2 4
3 5
5 6
6 7
8 8
9 9
11 12
1 1
2 2
3 3
5 5
6 6
8 8
9 9
11 11
0 0
我不明白为什么我的第二个输出为* it和* oit显示相同的值,我很确定错误是我如何分配oit.current _-> next&prev,但是我不确定。
任何见解都适用。
解决方法
您似乎想将两个排序的双向链接列表合并在一起。您的方法存在一些问题,因此,我将向您展示我的代码:
#include <iostream>
using namespace std;
struct node {
node* next;
node* prev;
int val;
node(int i_val)
: next(nullptr),prev(nullptr),val(i_val)
{}
};
void connect(node* a,node* b) {
if (a != nullptr) {
if (a->next != nullptr) {
a->next->prev = nullptr;
}
a->next = b;
}
if (b != nullptr) {
if (b->prev != nullptr) {
b->prev->next = nullptr;
}
b->prev = a;
}
}
struct DlList {
node* first_node;
node* last_node;
DlList()
: first_node(nullptr),last_node(nullptr)
{}
~DlList() {
for (node* n = first_node; n != nullptr; n = n->next) {
delete n->prev;
}
delete last_node;
}
void push(int new_val) {
node* new_node = new node(new_val);
connect(last_node,new_node);
last_node = new_node;
if (first_node == nullptr) {
first_node = new_node;
}
}
void merge_sorted(DlList& other) {
node* this_node = first_node;
node* other_node = other.first_node;
node* n = nullptr; // goes through each node of the new list in order
while (this_node != nullptr || other_node != nullptr) {
node* next_n;
if (other_node == nullptr ||
(this_node != nullptr && this_node->val <= other_node->val)) {
// entered if other_node is nullptr or this_node comes before other_node
next_n = this_node;
this_node = this_node->next;
}
else {
// entered if this_node is nullptr or other_node comes before this_node
next_n = other_node;
other_node = other_node->next;
}
connect(n,next_n);
if (n == nullptr) { // first time through loop
first_node = next_n;
}
n = next_n;
}
last_node = n;
// *this takes ownership of all of other's nodes
other.first_node = nullptr;
other.last_node = nullptr;
}
};
int main() {
std::cout << "running test" << std::endl;
int num[] = { 1,2,3,5,6,8,9,11 };
int num2[] = { 1,4,7,12 };
DlList l;
DlList l2;
for (int i = 0; i < 8; i++)
{
l.push(num[i]);
l2.push(num2[i]);
}
l.merge_sorted(l2);
for (node* n = l.first_node; n != nullptr; n = n->next) {
std::cout << n->val << " ";
}
std::cout << std::endl;
}
您可以在以后添加迭代器和其他更高级别的抽象,但是现在我认为它们使逻辑变得复杂且晦涩难懂。在您的情况下,我也没有看到需要“列表的最后一个”节点,因为nullptr就足够了。当然,如果您愿意的话,可以很容易地添加这些内容,只是出于演示目的,它们被省略了。
请注意,我是如何制作一个专用的connect
函数来完成所有指针分配的,因为它们应该在两个节点上完成。它也处理一堆nullptr大小写的组合,因此您不必担心在函数外部检查null指针。 (请注意,第一次通过合并循环如何将null指针连接到next_n)。现在,您几乎不必担心指针分配了,只需说“连接这两个节点”就更清楚了。
我的合并功能遍历新创建的列表中的每个节点。它从* this和other的两个可用节点中选择下一个节点。然后,它将当前节点连接到下一个节点,并将当前节点前进到下一个节点。当列表中的一个或另一个用完(this_node或other_node变为nullptr)时,它会进行特殊处理,这确实发生在给定的测试用例中。请注意将first_node和last_node分配在正确的位置,并在合并后清除其他位置,以防止出现双重所有权问题。