SkipList
SkipList é uma estrutura descrita em 1989 por William Pugh que se baseia em balancear de forma probabilística atalhos de um item a outro com objetivo de alcançar complexidade O(log(n)), sendo assim um substituto para árvores AVL. O objetivo deste projeto é de implementar uma Skip List em Rust, e dada a complexidade de desenvolvimento devido o gerenciamento de memória, foi decidido a implementação de estruturas intermediárias.
Plano de desenvolvimento
- Stack: Entender o processo de substituição de um item por outro na cabeça da pilha (link)
- Linked List: Inserir um item entre outros dois itens da lista (link)
- SkipList: Em cada nível inserir entre dois itens um novo item
Complexidade temporal
Um nível
Iniciando em uma lista simples ordenada a complexidade temporal média de busca é O(n)
Dois níveis
Vamos então incluir acima uma lista com atalhos a cada dois itens.
A complexidade temporal pode ser calculada por:
Generalização
Incluindo mais um nível a complexidade se torna
Para k níveis temos uma complexidade . O que aconteceria se tivessemos log(n) níveis? O resultado final, incrivelmente, é O(log(n))
Randomização da estrutura
Manter uma estrutura onde o nível acima é sempre a metade do nível anterior é muito custoso. Como solução temos a randomização dos níveis. Quando um novo nó é inserido na skiplist seu nível é randomizado, tendo uma probabilidade P de obter uma promoção de nível e probabilidade P^k de obter o nível máximo.
Implementação
Stack
- Inserir na pilha
pub fn push(&mut self, value: T) {
let old_head = self.head.take();
let new_head = Item {
value,
next: old_head,
};
self.head = Some(Box::new(new_head));
}
- Remover da pilha
pub fn pop(&mut self) -> Option<T> {
let old_head = self.head.take();
match old_head {
Some(item) => {
self.head = item.next;
Some(item.value)
}
None => None,
}
}
- Olhar o topo da pilha
pub fn peek(&self) -> Option<&T> {
match &self.head {
Some(item) => Some(&item.as_ref().value),
None => None,
}
}
Linked List
- Pesquisa recursiva retornando referência de nó
fn get_node_ref<'a>(&self, cursor: &'a Link<T>, key: &T) -> &'a Link<T> {
if let Some(node) = cursor.as_ref() {
if let Some(next_node) = node.next.as_ref() {
if next_node.value < *key {
return self.get_node_ref(&node.next, key);
}
}
}
cursor
}
- Inserir um novo nó recursivamente
fn recursive_insert(cursor: &mut Link<T>, value: T) {
if let Some(node) = cursor {
if let Some(next_node) = &mut node.next {
if next_node.value < value {
return LinkedList::recursive_insert(&mut node.next, value);
}
}
let mut new_node = Node { value, next: None };
let old_value = mem::take(&mut node.next);
new_node.next = old_value;
node.next = Some(Box::new(new_node));
}
}
- Remover um nó recursivamente
fn recursive_delete(cursor: &mut Link<T>, value: T) {
if let Some(node) = cursor {
if let Some(next_node) = &mut node.next {
if next_node.value == value {
let old_value = mem::take(&mut node.next);
node.next = old_value.unwrap().next;
}
else if next_node.value < value {
LinkedList::recursive_delete(&mut node.next, value);
}
}
}
}