跳过列表C++分段错误
Skip List C++ segmentation fault
我正在尝试使用这篇文章实现跳过列表。
法典:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<limits>
using namespace std;
template<class T>
class SkipList{
private:
class SkipNode{
public:
T* key; //Pointer to the key
SkipNode** forward; //Forward nodes array
int level; //Node level
//SkipNode constructor
SkipNode(T* key, int maxlvl, int lvl){
forward = new SkipNode*[maxlvl];
this->key=key;
level=lvl;
}
//Method that print key and level node
print(){
cout << "(" << *key << "," << level << ") ";
}
};
SkipNode *header,*NIL; //Root and End pointers
float probability; //Level rate
int level; //Current list level
int MaxLevel; //Maximum list levels number
//Function that returns a random level between 0 and MaxLevel-1
int randomLevel(){
int lvl = 0;
while( (float(rand())/RAND_MAX < probability) && (lvl < MaxLevel-1) )
lvl++;
return lvl;
}
public:
//SkipList constructor
SkipList(float probability, int maxlvl){
this->probability = probability;
MaxLevel = maxlvl;
srand(time(0));
header=new SkipNode(NULL,MaxLevel,0); //Header initialization
T* maxValue = new T;
*maxValue = numeric_limits<T>::max(); //Assign max value that T can reach
NIL = new SkipNode(maxValue,0,0); //NIL initialization
level=0; //First level
for(int i=0; i<MaxLevel; i++){ //Every header forward node points to NIL
header->forward[i]=NIL;
}
}
//SkipList destructor
~SkipList(){
delete header;
delete NIL;
}
//Method that search for a key in the list
SkipNode* search(T* key){
SkipNode* cursor = header;
//Scan the list
for(int i=level; i>=0; i--)
while(*(cursor->forward[i]->key) < (*key))
cursor=cursor->forward[i];
cursor=cursor->forward[0];
if(*(cursor->key) == *key)
return cursor;
return NULL;
}
//Method that insert a key in the list
SkipList* insert(T* key){
SkipNode* cursor = header;
SkipNode* update[MaxLevel]; //Support array used for fixing pointers
//Scan the list
for(int i=level; i>=0; i--){
while(*(cursor->forward[i]->key) < *(key))
cursor=cursor->forward[i];
update[i]=cursor;
}
cursor=cursor->forward[0];
if(*(cursor->key) == *(key)){ //Node already inserted
return this;
}
int lvl = randomLevel(); //New node random level
if(lvl > level){ //Adding missing levels
for(int i=level+1; i<=lvl; i++)
update[i]=header;
level=lvl;
}
SkipNode* x = new SkipNode(key,MaxLevel,lvl); //New node creation
for(int i=0; i<=lvl; i++){ //Fixing pointers
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
return this;
}
//Method that delete a key in the list
SkipList* erase(T* key){
SkipNode* cursor = header;
SkipNode* update[MaxLevel]; //Support array used for fixing pointers
//Scan the list
for(int i=level; i>=0; i--){
while(*(cursor->forward[i]->key) < *(key))
cursor=cursor->forward[i];
update[i]=cursor;
}
cursor=cursor->forward[0];
if(*(cursor->key) == *(key)){ //Deletetion of the founded key
for(int i=0; i<=level && update[i]->forward[i] == cursor; i++){
update[i]->forward[i] = cursor->forward[i];
}
delete cursor;
while(level>0 && header->forward[level]==NIL){
level=level-1;
}
}
return this;
}
//Method that print every key with his level
SkipList* print(){
SkipNode* cursor = header->forward[0];
int i=1;
while (cursor != NIL) {
cursor->print();
cursor = cursor->forward[0];
if(i%15==0) cout << endl; i++;
}
cout << endl;
return this;
}
};
main(){
SkipList<int>* list = new SkipList<int>(0.80, 8);
int v[100];
for(int i=0; i<100; i++){
v[i]=rand()%100;
list->insert(&v[i]);
}
list->print();
cout << endl << "Deleting ";
for(int i=0; i<10; i++){
int h = rand()%100;
cout << v[h] << " ";
list->erase(&v[h]);
}
cout << endl;
list->print();
cout << endl;
for(int i=0; i<10; i++){
int h = rand()%100;
cout << v[h] << " ";
if(list->search(&v[h]))
cout << " is in the list" << endl;
else
cout << " isn't in the list" << endl;
}
delete list;
}
它给了我第 59 行的分段错误(插入上的 for 周期),但我不明白为什么。你能帮我吗?我将接受您建议的任何其他改进。我的截止日期是两天,这就是我寻求帮助的原因。
编辑: 我已经用bebidek建议更正了代码(谢谢)。现在第一级是0。它似乎正在工作,但有时某些节点未正确插入,搜索结果不佳。
最后编辑: 它有效,感谢所有人
再编辑一次: 在代码中添加了注释,如果您有任何建议,欢迎您
代码中最大的问题可能是NIL=new SkipNode(numeric_limits<T*>::max());
首先,我怀疑您希望key
指针指向包含最大可能int
值的内存地址。 但这不是这里实际发生的事情。相反,key
指针指向可能的最大内存地址,该地址很可能不适用于您的进程。 此外,forward
属性可能包含一系列垃圾指针。
然后,当执行insert
方法中的第一个循环时,这会导致 2 个问题:
while(*(cursor->forward[i]->key) < *(key))
会将键值与无效指针进行比较cursor=cursor->forward[i];
会将光标重新分配给无效指针
我首先建议你改变设计,让 SkipNode 保留一个值来T
而不是指针:
class SkipNode{
public:
T key;
SkipNode* forward[100];
这将使许多与指针相关的代码变得不必要,并使代码更简单,因此不太可能遇到访问冲突。
此外,使用实际的NULL
(或事件更好的nullptr
)值而不是虚拟NIL
值来指示列表的末尾可能更干净。
因此,第一个问题是当您创建 NIL 节点时:
NIL=new SkipNode(numeric_limits<T*>::max());
作为参数,您应该使用指向现有变量的指针,例如:
T* some_name = new T;
*some_name = numeric_limits<T>::max();
NIL = new SkipNode(some_name);
请注意,我在numeric_limits
中使用了T
而不是T*
。当然,您必须记住在析构函数中删除此变量。
第二个问题是,代码中的level
变量有时是包含的(我的意思是级别号level
存在),如第 61 行,有时是排他性的(级别号level
不存在),如第 71 行。你必须保持一致。
第三个问题在第 52 行。你可能的意思是cursor=cursor->forward[1];
,但在循环 i = 0 之后,forward[0]
在你的代码中没有任何意义。
编辑: 第四和第五个问题是擦除功能。
cursor->~SkipNode();
它不会删除您的节点,而只会运行空析构函数。请改用delete cursor;
。
在循环中,您可能想写update[i]->forward[i] == cursor
而不是!=
.
再编辑一次: 你还没有实现任何 SkipList 的析构函数,而且你忘记了 main() 末尾的delete list;
。这两个会给你一个内存泄漏。
另一个编辑:
srand(time(0));
这一行应该在 main 的开头执行一次,仅此而已。如果你在每次随机生成之前执行它,你每次都会得到相同的结果(因为 time(0) 只计算秒,你的程序可以每秒运行函数randomLevel()
多次)。
您还忘记了在SkipList
的构造函数中重写precision
变量。
下次编辑: 在insert
函数中,您没有水平随机化。我的意思是,您无法插入级别低于整个跳过列表级别的节点。这不是错误会使程序崩溃或给出错误的结果,而是结构中查询的时间复杂度是O(n)而不是O(log n)。
您应该在插入函数的此循环中使用lvl
而不是level
:
for(int i=1; i<level; i++){
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
而且你的随机函数randomLevel
的最小结果应该是 1 而不是 0,因为你不希望节点女巫级别=0。
- 在某些循环内使用vector.push_back时出现分段错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当我的阵列太大时出现分段错误
- 分段错误当我试图运行程序时出错
- 在c++中初始化矩阵时出现分段错误(核心转储)
- 尝试使用集合函数时出现分段错误
- 我无法缩小此分段错误的原因
- g++的分段错误(在NaN上使用to_string两次时)
- 我是如何在这段代码中出现分段错误的
- 创建结构的数组时遇到分段错误
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- 在 c++ 中实现 Trie 时出现分段错误
- 为什么 fstream 在打开带有格式的文件时会导致分段错误?
- 为什么我遇到分段错误?
- 动态类的分段错误(家庭作业问题)
- 分段错误 - 读取初始化指针的数组
- 如何摆脱C ++中的分段错误错误?
- 使用 CTYPE 时出现分段错误
- 为什么代码给出分段错误?