我不确定该如何描述。我必须遍历通过指针相互连接的对象,但是第一个元素不应仅在指向下一个元素的指针中存储值。
我想出了一个小类层次结构。如果我那样使用它,则必须将基类转换为派生元素。它似乎只能与肮脏的演员一起使用。
有更好的解决方案吗?
下面是示例代码:
#include <iostream>
struct Basenode {
Basenode* next;
};
struct Skipnode : Basenode {
Skipnode(int in_key, int in_value);
int key;
int value;
};
Skipnode::Skipnode(int in_key, int in_value)
: key{ in_key }, value{ in_value }
{
}
int main()
try {
Basenode head; // no key and value
Skipnode first(4, 2); // key and value
Skipnode second(8, 2);
Basenode* p = &head;
head.next = &first; // fine
first.next = &second; // fine
// p = p->next->key; // not accesible because is Basenode not derrived Skipnode
std::cout << static_cast<Skipnode*>(p->next)->key; // fine but diryt cast slicing ?
std::cin.get();
}
catch (std::runtime_error& e) {
std::cerr << e.what() << "\n";
std::cin.get();
}
catch (...) {
std::cerr << "unknown error " << "\n";
std::cin.get();
}
编辑:有人问我为什么我需要此注释。我想我举了一个有限的例子。
我需要它来实现一个跳过列表。它的许多算法都要求从第一个元素之前的一个元素开始。头元素。我可以将其设为普通节点,并为这些值输入虚拟值,但似乎不正确。因此,现在我从您的建议中提出了这个丑陋的解决方案,从头开始。
此处以复制构造函数为例。
class Skiplist {
public:
//...
Skiplist(const Skiplist& other); // copy constructor
//...
private:
struct Skipnode; // forward declaration so Basenode can have Skiplist*
struct Basenode { // Empty node, mainly created to represent head element.
// Is there a way to get a empty head with no key / values without using this ?
Basenode(int in_level);
Basenode(const std::vector<Skipnode*>& in_next);
std::vector <Skipnode*> next;
};
struct Skipnode : Basenode { // derived so with Basenode* we can start the iteration of the node on head
Skipnode(value_type val, int in_level);
Skipnode(value_type val, const std::vector<Skipnode*>& in_next);
value_type value; // first key / second mapped type = value
//key_type key;
//mapped_type value;
};
Basenode head{ 0 }; // element before first element containg pointers to all the first elements of each level
//...
};
Skiplist::Skiplist(const Skiplist& other) // copy constructor
:head{ other.head }, top_level{ other.top_level }, random_engine{ other.random_engine }
// on the first level let the other Skiplist present its elements and make a deep copy of them
// now still the higher levels point to the other node so this is fixed in the second part
// then the next level pointers are installed linked to the elements of the new node
{
if (top_level == 0) return; // no elements are present so dont bother to allocate nodes
{
// installment of lowest level, each element is located here
Skipnode* other_node = other.head.next[0];
Basenode* current_position = &head;
while (other_node != nullptr) {
Skipnode* new_node = new Skipnode{ other_node->value,other_node->next };
current_position->next[0] = new_node;
current_position = current_position->next[0];
other_node = other_node->next[0];
}
current_position->next[0] = nullptr;
}
// installment of the other levels
for (size_type curr = 1; curr < top_level; ++curr) {
Basenode* current_position = &head; // the current position of the level[curr]
Skipnode* next_position = current_position->next[curr]; // next position after curr containing still pointers to the other skiplist
Basenode* lowest_position = &head; // lowest level position used to find the new pointers and attach them "behind" current
while (lowest_position != nullptr && next_position != nullptr) {
if (lowest_position->next[0]->value.first == next_position->value.first) { // check by unique key, address of next pos is still of the other skiplist
current_position->next[curr] = lowest_position->next[0]; // lowest is the valid address of new node
current_position = current_position->next[curr];
next_position = next_position->next[curr]; // go to next element of other node
if (next_position == nullptr) { // case end is reached
current_position->next[curr] = nullptr;
current_position = current_position->next[curr];
}
}
else { // forward position of lowest level until other key == next position key
lowest_position = lowest_position->next[0];
}
}
}
}
请参阅此处以获取有关如何组织跳过列表的基本说明: https://en.wikipedia.org/wiki/Skip_list
整个代码在codereview上: https://codereview.stackexchange.com/questions/197752/non-generic-skip-list-implementation-in-c-version-2
答案 0 :(得分:2)
@SomeProgrammerDude所说的所有内容,或者:
我根本不需要课程BaseNode
。为什么我们不能拥有(在所有其他条件都相等的情况下):
SkipNode *head = &first;
...
或者更好的是一个叫做SkipNodeList
的类,它处理SkipNode
列表中管理和迭代的所有方面。
当然,这总有点愚蠢,只需使用std::list
(或std::forward_list
)并从STL的所有优点中受益。
或者您可以从其中之一派生以添加自己的功能(例如,互斥体以使列表具有线程安全性或跟踪列表中当前元素的数量,如@iMajuscule所建议)。
答案 1 :(得分:1)
是的,有更好的方法:
向前声明Skipnode
,然后在BaseNode
中使用指向SkipNode
的指针,这样就不必强制转换:
struct Skipnode;
struct Basenode {
Skipnode* next;
};
另外,为了说明从Skipnode
继承Basenode
的设计如何有意义(与评论中的讨论有关),我们可以想象在Basenode
中有一个成员来计算接下来是许多元素(计算next
成员及其后继者中的一个)