Реализация сбалансированного SkipList
От: gronvladimir  
Дата: 16.12.06 14:35
Оценка:
Реализация сбалансированного SkipList.

Статьи по реализации SkipList есть, но почти нет ничего по реализации сбалансированного SkipList.
В статье http://eternallyconfuzzled.com/tuts/skip.html приводится такая реализация — вот
если бы еще понять ее. Сам автор статьи по интересующему меня вопросу выразился так: "Удаление в
балансированном skip list, мягко говоря, боль в заднице." И он полностью убедил меня в этом.

Ниже я привожу минимально необходимый код — определения структур, функцию вставки jsw_insert и
функцию удаления jsw_remove.

#include <limits.h>

/* Max key for signed integers */
#define MAX_KEY INT_MAX

struct jsw_node
{
int data;
struct jsw_node *r;
struct jsw_node *d;
};

struct jsw_skip
{
struct jsw_node *head;
struct jsw_node *bottom;
struct jsw_node *tail;
};

jsw_node* new_node(int key, jsw_node *right, jsw_node *down)
{
jsw_node* node = new jsw_node;
if( !node ) return NULL;
node -> data = key;
node -> r = right;
node -> d = down;
return node;
}

struct jsw_skip *new_skip()
{
struct jsw_skip *skip = new jsw_skip;

if( skip == NULL ) return NULL;

skip -> bottom = new_node( MAX_KEY, NULL, NULL );
skip -> tail = new_node( MAX_KEY, NULL, NULL );
skip -> head = new_node( MAX_KEY, skip -> tail, skip -> bottom );

skip -> bottom -> r = skip -> bottom;
skip -> bottom -> d = skip -> bottom;
skip -> tail -> r = skip -> tail;

return skip;
}

int jsw_insert(jsw_skip *skip, int key )
{
jsw_node *it;

/* Set search params for insertion */
skip -> bottom -> data = key;

for(it = skip -> head; it != skip -> bottom; it = it -> d ) // цикл идет по уровням
{
while( key > it -> data ) it = it -> r;

/* Raise column
if( it -> data > it -> d -> r -> r -> data )
{
it -> r = new_node( it -> data, it -> r, it -> d -> r -> r );
it -> data = it -> d -> r -> data;

}
else if( it -> d == skip -> bottom ) return 0;
}

/* Grow list if necessary */
if( skip -> head -> r != skip -> tail )
skip -> head = new_node( MAX_KEY, skip -> tail, skip -> head );

return 1;
}

struct j_walker
{
struct jsw_node *it; /* Current item */
struct jsw_node *prev; /* Previous gap */
struct jsw_node *next; /* Next gap */
struct jsw_node *save; /* Temporary holder */
int lastb; /* Previous key bottom */
int lastu; /* Previous key up */
};

static struct j_walker w; /* Variables for deletion */

static void fix_gap (struct jsw_skip *skip )
{
w.save = w.it -> r;

if(w.save -> data == w.save -> d -> r -> data || w.next == skip -> bottom)
{
/* Lower next column */
w.it -> r = w.save -> r;
w.it -> data = w.save -> data;
free( w.save );
}
else
{
/* Raise first of next gap, lower next column */
w.it -> data = w.save -> d -> data;
w.save -> d = w.save -> d -> r;
}
}

static void last_gap(struct jsw_skip *skip )
{
if ( w.prev -> data <= w.prev -> d -> r -> data )
{
/* Lower prev column */
if( w.next == skip -> bottom ) w.lastb = w.prev -> data;

w.prev -> r = w.it -> r;
w.prev -> data = w.it -> data;
free( w.it );
w.it = w.prev;
}
else
{
/* Raise last of prev gap, lower prev column */
if( w.prev -> data == w.prev -> d -> r -> r -> data )
w.save = w.prev -> d -> r;
else
w.save = w.prev -> d -> r -> r;

w.prev -> data = w.save -> data;
w.it -> d = w.save -> r;
}
}

static int rebalance(struct jsw_skip *skip )
{
w.next = w.it -> d;

if( w.it -> data == w.next -> r -> data )
{
if( w.it -> data != w.lastu ) fix_gap( skip );
else last_gap( skip );
}
else if( w.next == skip -> bottom ) return 0;

w.lastu = w.it -> data;

return 1;
}

int jsw_remove(struct jsw_skip *skip, int key)
{
/* Set search params for deletion */
skip -> bottom -> data = key;
w.lastu = skip -> head -> data;
w.it = skip -> head -> d;

for ( ; w.it != skip -> bottom; w.it = w.next)
{
while( key > w.it -> data )
{
w.prev = w.it;
w.it = w.it -> r;
}

if( rebalance( skip ) == 0 ) return 0;
}

/* Fix columns taller than 1 */
w.it = skip -> head -> d;

for ( ; w.it != skip -> bottom; w.it = w.it -> d )
{
while ( key > w.it -> data ) w.it = w.it -> r;

if ( key == w.it -> data ) w.it -> data = w.lastb;
}

/* Shrink if necessary */
if( skip -> head -> d -> r == skip -> tail )
{
w.save = skip -> head;
skip -> head = w.save -> d;
free( w.save );
}

return 1;
}

Все мои вопросы связаны с функцией удаления — jsw_remove.

1) Что делает в функции last_gap следующий фрагмент кода:

else
{
/* Raise last of prev gap, lower prev column */
if( w.prev -> data == w.prev -> d -> r -> r -> data )
w.save = w.prev -> d -> r;
else
w.save = w.prev -> d -> r -> r;

w.prev -> data = w.save -> data;
w.it -> d = w.save -> r;
}

2) Что делает в функции jsw_remove следующий фрагмент кода:

/* Fix columns taller than 1 */
w.it = skip -> head -> d;

for ( ; w.it != skip -> bottom; w.it = w.it -> d )
{
while ( key > w.it -> data ) w.it = w.it -> r;

if ( key == w.it -> data ) w.it -> data = w.lastb;
}

3) Почему нужны переменные lastb и lastu ?

Совершенно замечательный алгоритм вставки — просто конфетка ! Но вот удаление!
Я себе плешь проел, пытаясь понять авторский вариант функции удаления jsw_remove.
На ветвь else в фунции last_gap я вообще не смог попасть.

Может кто нибудь подсобит или подскажет источник
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.