Я занимаюсь разработкой своего собственного шаблона шаблона скиплиста. Ниже приведены его характеристики: Iterator
класс содержит копию отдельного списка пропуска. Итераторы Head и Tail всегда пусты, а tail итератору присвоено значение tail, равное TRUE
,
class RandomHeight
{
public:
RandomHeight(int maxLvl, float prob);
~RandomHeight() {}
int newLevel(void);
private:
int maxLevel;
float probability;
};
RandomHeight::RandomHeight
(int maxLvl, float prob)
{
srand (time(NULL));
maxLevel = maxLvl;
probability = prob;
}
int RandomHeight::newLevel(void)
{
int tmpLvl = 1;
// Develop a random number between 1 and
// maxLvl (node height).
while ((((rand()%1000000)*1.0/1000000) < probability) &&
(tmpLvl < maxLevel))
tmpLvl++;
return tmpLvl;
}
template <typename Key_T, typename Mapped_T, size_t MaxLevel> class SkipList;
template <typename Key, typename Obj>
class Iterator
{
typedef std::pair<Key, Obj> ValueType;
template <typename Key1, typename Obj1, size_t MaxLevel1> friend class SkipList;
public:
// Iterator(const Iterator &);
//virtual Iterator& operator=(const Iterator &);
Iterator &operator++();
Iterator operator++(int);
//virtual ValueType &operator*() const;
//virtual ValueType *operator->() const;
Iterator(Key, Obj, int,bool);
Iterator(int,bool);
~Iterator();
Key getKey(void) {return key;};
Obj getObj(void) {return obj;};
int getHgt(void) {return nodeHeight;};
bool isTail(void) {return tail;};
private:
int nodeHeight;
Key key;
Obj obj;
bool tail; // holds non null value
Iterator<Key,Obj>** fwdNodes;
};template <typename Key, typename Obj>
Iterator<Key,Obj>::~Iterator()
{
delete [] fwdNodes;
}
template <typename Key, typename Obj>
Iterator<Key,Obj>::Iterator(Key k,Obj o, int h,bool t = false) : nodeHeight (h) , key (k) , obj (o) , tail(t)
{
fwdNodes = new Iterator<Key,Obj>* [h+1];
for ( int x = 1; x <= nodeHeight; x++ )
fwdNodes[x] = (Iterator<Key,Obj>*) NULL;
}
template <typename Key, typename Obj>
Iterator<Key,Obj>::Iterator(int h,bool t = false) : nodeHeight (h) , key ((Key) NULL) , obj ((Obj) NULL) , tail(t)
{
fwdNodes = new Iterator<Key,Obj>* [h+1];
for ( int x = 1; x <= nodeHeight; x++ )
fwdNodes[x] = (Iterator<Key,Obj>*) NULL;
}
template <typename Key_T, typename Mapped_T, size_t MaxLevel = 5>
class SkipList
{
typedef std::pair<Key_T, Mapped_T> ValueType;
public:
SkipList();
~SkipList();
SkipList(const SkipList &);
SkipList &operator=(const SkipList &);
size_t size() const;
Iterator<Key_T,Mapped_T> begin();
Iterator<Key_T,Mapped_T> end();
//ConstIterator begin() const;
//ConstIterator end() const;
//virtual void clear();std::pair<Iterator<Key_T,Mapped_T>, bool> insert(const ValueType &);
template <typename IT_T>
void insert(IT_T range_beg, IT_T range_end);
void erase(Iterator<Key_T,Mapped_T> pos);
//virtual void erase(Iterator<Key_T,Mapped_T> range_beg, Iterator<Key_T,Mapped_T> range_end);
private:
Iterator<Key_T,Mapped_T>* head;
Iterator<Key_T,Mapped_T>* tail;
float probability;
size_t maxHeight;
size_t curHeight;
RandomHeight* randGen;
};
template <typename Key_T, typename Mapped_T, size_t MaxLevel>
SkipList<Key_T,Mapped_T,MaxLevel>::SkipList() : curHeight (1), maxHeight(MaxLevel) , probability (1.0/MaxLevel)
{
randGen = new RandomHeight(MaxLevel,probability);
// Create head and tail and attach them
head = new Iterator<Key_T,Mapped_T> (maxHeight);
tail = new Iterator<Key_T,Mapped_T> (maxHeight,true);
for ( int x = 1; x <= maxHeight; x++ )
head->fwdNodes[x] = tail;
}
template <typename Key_T, typename Mapped_T, size_t MaxLevel>
SkipList<Key_T,Mapped_T,MaxLevel>::~SkipList()
{
// Walk 0 level nodes and delete all
Iterator<Key_T,Mapped_T>* tmp;
Iterator<Key_T,Mapped_T>* nxt;
tmp = head;
while ( tmp )
{
nxt = tmp->fwdNodes[1];
delete tmp;
tmp = nxt;
}
delete randGen;
}
Моя проблема в функции вставки ниже:
template <typename Key_T, typename Mapped_T, size_t MaxLevel>
std::pair<Iterator<Key_T,Mapped_T>, bool> SkipList<Key_T,Mapped_T,MaxLevel>::insert(const ValueType &input)
{
Key_T k = input.first;
Mapped_T o = input.second;
int lvl = 0, h = 0;
Iterator<Key_T,Mapped_T>** updateVec = new Iterator<Key_T,Mapped_T>* [maxHeight+1];
Iterator<Key_T,Mapped_T>* tmp = head;
Key_T cmpKey;
// Figure out where new node goes
for ( h = curHeight; h >= 1; h-- )
{
cmpKey = tmp->fwdNodes[h]->getKey();
while ( !tmp->fwdNodes[h]->isTail() && cmpKey < k )
{
tmp = tmp->fwdNodes[h];
cmpKey = tmp->fwdNodes[h]->getKey();
}
updateVec[h] = tmp;
}
tmp = tmp->fwdNodes[1];
cmpKey = tmp->getKey();
// If dup, return false
if ( !tmp->isTail() && cmpKey == k )
{
delete updateVec;
return std::pair<Iterator<Key_T,Mapped_T>, bool> ( NULL,false);
}
else
{
// Perform an insert
lvl = randGen->newLevel();
if ( lvl > curHeight )
{
for ( int i = curHeight + 1; i <= lvl; i++ )
updateVec[i] = head;
curHeight = lvl;
}
// Insert new element
tmp = new Iterator<Key_T,Mapped_T>(k, o, lvl);
for ( int i = 1; i <= lvl; i++ )
{
tmp->fwdNodes[i] = updateVec[i]->fwdNodes[i];
updateVec[i]->fwdNodes[i] = tmp;
}
delete updateVec;
return std::pair<Iterator<Key_T,Mapped_T>, bool> (*tmp , true);
}
delete updateVec;
return std::pair<Iterator<Key_T,Mapped_T>, bool> ( NULL,false);
}
Что с этим не так? Я не мог разобраться после долгой отладки. Следующий код выдает ошибку дампа памяти!
std::pair < Iterator<int,float>,bool> a = s.insert(std::pair<int,int>(1,1));
s.insert(std::pair<int,int>(2,1));
s.insert(std::pair<int,int>(3,2));
Ваша реализация итератора нарушает Правило трех. Если вы создадите копию или назначите итератор, вы получите 2 итератора с fwdNodes
указывая на ту же область памяти. Как только один из них будет удален, другой получит fwdNodes
указывая на уже освобожденную память.
Других решений пока нет …