我使用模板编写跳过列表。当我运行它时,我在调用函数insert
时遇到了分段错误。我用gdb调试它告诉我问题原因因为调用std::less<int>::operator()
。我看到了example,但我仍然为什么我错了。
的 skiplist.h:
#include <iostream>
#include <cstring>
namespace IceCity{
const double DEFAULT_PROBILITY = 1/4;
const int DEFAULT_MAXSIZE = 16;
//node base
template <typename KeyValue,typename Value>
struct sklist_node
{
KeyValue key;
Value value;
sklist_node<KeyValue,Value>** forward;
};
template <typename KeyValue,typename Value,
typename KeyCmp = std::less<KeyValue> ,
typename ValueCmp = std::equal_to<Value> >
class sklist
{
public:
sklist (int limitlevel = DEFAULT_MAXSIZE, double pro = DEFAULT_PROBILITY) :
_M_limitlevel(limitlevel), _M_pro(pro)
{
_M_maxlevel = 0;
_M_header = make_node(limitlevel, 0, 0);
}
virtual ~sklist ()
{
//TODO:free
_M_NodePointer x = _M_header;
_M_NodePointer tmp = x->forward[0];
while (tmp != nullptr)
{
delete x;
x = tmp;
tmp = tmp->forward[0];
};
}
//Data member
private:
typedef sklist_node<KeyValue,Value> _M_Node;
typedef sklist_node<KeyValue,Value>* _M_NodePointer;
typedef Value* _M_ValuePoiner;
int _M_limitlevel;
double _M_pro;
_M_NodePointer _M_header;
KeyCmp _M_keycmp;
ValueCmp _M_valuecmp;
int _M_maxlevel;
//private member function
private:
/****
* make a node with level and key *
****/
inline _M_NodePointer
make_node(int level, KeyValue key, Value value)
{
_M_NodePointer res = new _M_Node;
res->key = key;
res->value = value;
res->forward = new _M_NodePointer [level+1];
return res;
}
/****
* creat an rand number [0.0,1.0) *
****/
inline double
random_pro()
{
return static_cast<double>(rand())/RAND_MAX;
}
/****
* get the level for a node *
****/
int
random_level()
{
int level = 0;
while ( random_pro() < _M_pro && level < _M_limitlevel )
{
level++;
}
return level;
}
public:
/****
* insert an node in skiplist *
****/
void
insert(KeyValue key, Value NewValue)
{
_M_NodePointer x = _M_header;
_M_NodePointer update[_M_limitlevel+1];
memset( update, 0, _M_limitlevel+1 );
for(int i = _M_maxlevel; i >=0 ; --i)
{
while (x->forward[i] != nullptr && _M_keycmp(x->forward[i]->key, key))
{
x = x->forward[i];
}
update[i] = x;
}
x = x->forward[0];
/****
* if x->key equal to search key update it
* else insert it*
****/
if ( _M_keycmp(x->key, key) )
{
x->value = NewValue;
}
else
{
int level = random_level();
if ( level > _M_maxlevel )
{
for(int i = _M_maxlevel+1; i <= level; ++i)
{
update[i] = _M_header;
}
// update maxlevel
_M_maxlevel = level;
}
x = make_node( level, key, NewValue );
for( int i = 0; i <= level; ++i )
{
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
}
}
};
}
#endif /* ifndef IC_BASE_LIST */
skiplist.cpp:
#include "base_list.h"
#include <iostream>
int main(int argc, char *argv[])
{
IceCity::sklist<int, int> ss;
for (int i = 0; i < 20; ++i) {
ss.insert(i, i*10);
}
return 0;
}
wroing message :
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401894 in std::less<int>::operator()(int const&, int const&) const ()
[0] from 0x0000000000401894 in std::less<int>::operator()(int const&, int const&) const
(no arguments)
[1] from 0x0000000000401286 in IceCity::sklist<int, int, std::less<int>, std::equal_to<int> >::insert(int, int)
(no arguments)
答案 0 :(得分:0)
问题与std::less<>
无关。在此时的第一次insert()
来电:
if ( _M_keycmp(x->key, key) )
x
是一个空指针。它解除引用会导致分段错误,而不是调用_M_keycmp
中的任何内容。
附注:所有成员名称都是C ++中的保留字。来自[lex.name]:
每个包含双下划线
__
的标识符或以下划线开头后跟大写字母的标识符都保留给实现以供任何使用。