Czasy (na herze) dla struktur danych (wszystkie testy odpalone sprawdzarką dude'a):
| Struktura | Czas |
|---|---|
| RBT (drx, c++) | 25.81 s |
| SkipList (ekg2, C) | 29.09 s |
| AVL (dude, C) | 32 s |
| AVL (tr) | 32.98 s |
Ja mam na RBT i działa szybko. Podejrzewam, że AVL działałyby podobnie szybko (AVL mają wysokość <1.44log(n) vs <2log(n) RBT; mają więc szybszy Upper i Lower, ale wolniejszy Insert i Delete) jeśli rozkład I+U jest podobny jak U+L, co zależy od testów.
Swoją drogą ciekawią mnie drzewa van Emde Boasa, które mają operacje słownikowe w O(log log n). Co prawda ilość elementów jest mała – maksymalnie 50000; log(50000) = 15.6, ale log(36) = 5.2, więc drzewa vEB mogą być nawet sześć razy szybsze. — drx 2010/05/23 18:16
Moje (dj3500) i Damiana czasy, testowane za pomocą:
time for i in `seq 1 10`; do ./program < test$i.in > test$i.tempout; done
| Struktura | Czas |
|---|---|
| Treap (dj3500, c++) | 27.31 s |
| Splay (DS, c++) | 39.34 s |
| RBT z STLa (dj3500, c++) | 28.04 s |
| trwałe RBT (dj3500, ocaml, dostaje głównie TLE, wyłazi też poza 4MB) | 61.24 s |
Warto też może nadmienić, że treap ma 102 linijki, a cały program 3.5 kB kodu więc jeśli nie widać różnicy to po co przepłacać ;) dj3500
http://www.ii.uni.wroc.pl/~mbi/dyd/aisd_10s/wyniki_E.html - wyniki
0 oznacza brak poprawnej odpowiedzi na jakiś test
pierwsza kolumna to suma czasów
11304: Mik Kali 13336: Kon Wypy 13492: Luk Syno 14248: Luk Zapa 14272: Pio Pole 14444: Krz Kusi 14484: Daw Jurc 14620: Mar Ocze 14824: Mic Karp 15028: Wik Jana 15060: Mag Sara 15128: Kac Krol 15188: And Kaje 15204: Pio Bzow 15260: Paw Muri 15460: Dam Rusa 15500: Krz Parj 15696: Krz Ziel (test) 15716: Kar Kona 15848: Jak Tarn 15960: Pio Posa 16008: Mar Kola 16100: Dam Stra 16160: Pio Krze 16312: Pio Ryba 16408: Dan Blas 16828: Krz Nowi 16884: Krz Ziel 17036: Iza Bicz 17440: Mar Janu 17468: Pio Rzep 17936: Mic Mazu 18008: Adr Dyli 18052: Paw Kacp 18408: Pio Gajo 18660: Mic Roza 19072: Pio Walk 19932: Mac Maty 26812: Mic Soko 0: Ark Goch 0: Raf Kowa 0: Mic Kras 0: Dam Piąt 0: Mac Wiec 0: Ada Kacz 0: Ale Gali 0: Bla Sala 0: Dam Wiec 0: Dom Brul 0: Dom Rusa 0: Fil Slom 0: J L (test) 0: Kam Miel 0: Luc Fran 0: Luk Toma 0: Luk Wrza 0: Mac Pacu 0: Mar Janc 0: Pat Urba 0: Paw Kali 0: Paw Kime 0: Sla Step 0: Szy Lasz 0: Tom Luch 0: Wal Augu (test)
#include <stdio.h>
#define SEARCH_BRAK (2LL<<60)
#define MAX_ELEMS 50010
#define LMAX 1000000000L
typedef signed long long T;
inline void putll (T & x)
{
signed long l = x / LMAX,
r = x % LMAX;
if (l != 0)
printf("%ld%09ld\n", l,(r<0)?-r:r);
else
printf("%ld\n", r);
}
typedef struct node
{
T data;
int prio;
struct node *left, *right, *up;
} node;
node * root;
/* Własny alokator pamięci. */
unsigned short nextFreeBlock[MAX_ELEMS]; // następna wolna komórka za bieżącą wolną (0 to kolejna)
node Block[MAX_ELEMS]; // pula pamięci
unsigned short firstFreeBlock = 1; // bo zero to specjalna wartosc
unsigned int index;
#define allocate(X) X = &Block[firstFreeBlock]; \
if (nextFreeBlock[firstFreeBlock] == 0) \
firstFreeBlock++; \
else \
firstFreeBlock = nextFreeBlock[firstFreeBlock];
#define free(X) index = X - &Block[0]; \
nextFreeBlock[index] = firstFreeBlock; \
firstFreeBlock = index;
/****/
inline void rotate_left (node * n)
{
node *x = n->right;
x->up = n->up;
if (x->up != NULL)
{
if (x->up->left == n)
x->up->left = x;
else
x->up->right = x;
}
n->right = x->left;
if (n->right != NULL)
n->right->up = n;
n->up = x;
x->left = n;
}
inline void rotate_right (node * n)
{
node *x = n->left;
x->up = n->up;
if (x->up != NULL)
{
if (x->up->left == n)
x->up->left = x;
else
x->up->right = x;
}
n->left = x->right;
if (n->left != NULL)
n->left->up = n;
n->up = x;
x->right = n;
}
void ins (T & e)
{
T ret = 0;
node *n = root,
*p = NULL;
static int next = 1;
// p - ojciec e
while (n != NULL)
{
p = n;
ret = e - (n->data);
if (ret < 0)
n = n->left;
else if (ret > 0)
n = n->right;
else
return; // duplikat
}
allocate(n);
n->left = n->right = NULL;
n->up = p;
n->data = e;
if (p == NULL)
root = n;
else if (ret < 0)
p->left = n;
else
p->right = n;
next = next * 1103515245 + 12345;
n->prio = (unsigned)(next/65536) % 32768;
// rebalance
while (n->up != NULL &&
(n->up->prio) > (n->prio))
if (n->up->right == n)
rotate_left (n->up);
else
rotate_right (n->up);
if (n->up == NULL)
root = n;
}
void del (T & e)
{
node *n = NULL,
*m = root;
// znajdź poprzednika e - n.
while (m != NULL)
if (e < m->data)
m = m->left;
else
{
n = m;
m = m ->right;
}
if ((n == NULL) || (n->data != e))
{
fputs_unlocked ("BRAK\n", stdout);
return;
}
/* rotuj do liścia */
while (n->left != NULL || n->right != NULL)
{
if (n->left != NULL)
{
if (n->right == NULL || n->left->prio < n->right->prio)
rotate_right (n);
else
rotate_left (n);
}
else
rotate_left (n);
if (root == n)
root = n->up;
}
if (n->up == NULL)
root = NULL;
else
if (n->up->left == n)
n->up->left = NULL;
else
n->up->right = NULL;
free(n);
fputs_unlocked ("OK\n", stdout);
}
inline void lower (node * t, T & k)
{
T ret = SEARCH_BRAK;
while (t != NULL)
{
if (t->data == k) {
putll (k);
return;
}
if (k < t->data)
t = t->left;
else
{
ret = t->data;
t = t->right;
}
}
if (ret == SEARCH_BRAK)
fputs_unlocked ("BRAK\n", stdout);
else
putll ( ret);
}
inline void upper (node * t, T & k)
{
T ret = SEARCH_BRAK;
while (t != NULL)
{
if (t->data == k)
{
putll ( k);
return;
}
if (k < t->data)
{
ret = t->data;
t = t->left;
}
else
t = t->right;
}
if (ret == SEARCH_BRAK)
fputs_unlocked ("BRAK\n", stdout);
else
putll ( ret);
}
int main (void)
{
setvbuf (stdout, NULL, _IOFBF, 2 << 10);
T sign, n;
char op, ch;
int oper;
root = NULL;
oper = getchar_unlocked() - '0';
while ((ch = getchar_unlocked ()) >= '0')
oper = oper * 10 + (ch - '0');
while (oper --> 0)
{
sign = 1;
n = 0;
op = getchar_unlocked (); // operacja
getchar_unlocked (); // spacja
ch = getchar_unlocked ();
if (ch == '-')
sign = -1;
else
n = ch - '0';
while ((ch = getchar_unlocked ()) >= '0')
n = n * 10 + (ch - '0');
n *= sign;
switch (op)
{
case 'I': ins (n); break;
case 'D': del (n); break;
case 'L': lower (root, n); break;
default: upper (root, n);
}
}
return 0;
}