# Strutture Dati
:::danger
da completare
:::
## Vettori
**Se il vettore di lunghezza n non è ordinato**
- search, max, min, succesor -> $\mathcal{O}(n)$
- insert, delete -> $\mathcal{O}(n)$
**Se il vettore è ordinato**
- minimo e massimo -> $\mathcal{O}(1)$
- search, succesor -> $\mathcal{O}(\log(n))$
- insert,delete -> $\mathcal{O}(n)$
**inserire in un vettore pieno**
- rifiutati in $\mathcal{O}(1)$ (se teniamo conteggio)
- riallocazione in $\mathcal{O}(n)$
## linked list
**code**
```c
struct El {
int data;
struct El *prox;
} Elemento;
```
**se la lista non è ordinata**
- search,min,max, succesor -> $\mathcal{O}(n)$
- insert -> $\mathcal{O}(1)$
- delete (without reference) -> $\mathcal{O}(n)$
- delete (with reference) -> $\mathcal{O}(1)$
**se la lista è ordinata**
- uno tra max e min è $\mathcal{O}(1)$, l'altro $\mathcal{O}(n)$
- se ho reference ad entrambi $\mathcal{O}(1)$
- search , successor -> $\mathcal{O}(n)$
- insert, delete -> $\mathcal{O}(n)$
## Stack
**code**
```c
//todo
```
**funzioni**
- Push(S,e) -> aggiunge e in cima alla pila $\mathcal{O}(1)$
- Pop(S) -> return la cima della pila e la elimina dalla pila $\mathcal{O}(1)$
- Empty(S) -> controlla se il succ della testa è NULL $\mathcal{O}(1)$
## Queues
**code**
```c
//todo
```
**funzioni**
- Enqueue(Q,e) -> aggiunge e alla fine della coda
- Dequeue(Q) -> restituisce il primo della coda, lo elimina della coda
- Empty(Q) -> return true se la coda è vuota
**realizzazione con vettore**
- vettore lungo l con indice iniziale in 0
- uso due indici *tail * & *head*
- indici incrementati mod l
- Enqueue(Q,e) : se n < l inserisco in A[tail] , n++, tail++. $\mathcal{O}(1)$
- Dequeue(Q): se n>0 restituisci A[head], n--, head++. $\mathcal{O}(1)$
- Empty(S): return true se n==0 . $\mathcal{O}(1)$
- Reallocare costa $\Theta(n)$
**realizzazione con lista**
- usiamo un puntatore tail, oltre a quello head
- Enqueue(Q,e) : inserisci l'elemento in coda alla lista, aggiorna tail. $\mathcal{O}(1)$
- Dequeue(Q): return l'elemento puntato da head, aggiorno head. $\mathcal{O}(1)$
- Empty(Q) : return true if head=tail. $\mathcal{O}(1)$
## Dizionari
contiene elementi accessibili direttamente con la loro **chiave**.
Per ottimizzare lo spazio calcolo una funzione della chiave h(k) -> funzione di **hash**
**Indirizzamento chiuso (open hashing)**
- ogni riga della tabella, chiamata *bucket*, contiene la testa di una lista.
- nell'eventualità di una collisione l'elemento viene aggiunto alla lista in $\mathcal{O}(1)$
- per fare search calcolo la chiave k e cerco nell'intero bucket h(k)
**Indirizzamento aperto (closed hashing)**
- in caso di collisione si seleziona un altro bucket in modo deterministico
- se non si trovano bucket
- rifiuta in $\Theta(n)$
- si rialloca e si hasha di nuovo tutto in $\Theta(n)$
- nella ricerca si deve implementare la stessa regola deterministica
- per la cancellazione si usa una *tombstone*, che non corrisponde a nessuna chiave
## Alberi binari di ricerca (BST)
per essere BST deve valere per ogni nodo x che
- se y è nel sottoalbero sinistro x -> y.key < x.key
- se y è nel sottoalbero destro x -> y.key > x.key
è importante progettare funzioni che preservino queste proprietà
## Heap
- Struttura ad albero con la chiave del nodo padre sempre maggiore - +nel caso di max-heap+ - di quella dei figli
- Le funzioni su un max-heap sono: Max, Inserisci, Cancella-Max, Costruisci-max-heap, Max-heapify
#### Costruisci-Max-Heap
la funzione costruisce un heap a partire da un array A e un'indice n
``` c
Costruisci-Max-Heap(A){
A.heapsize <- A.length
for i <- floor(A.length/2) downto 1
Max-Heapify(A,i)
Max-Heapify(A,n)
1 l LEFT(n)
2 r RIGHT(n)
3 if l A:heapsize and A[l] > A[n]
4 posmax l
5 else posmax n
6 if r A:heapsize and A[r] > A[posmax]
7 posmax r
8 if posmax 6= n
9 Swap(A[n];A[posmax])
10 Max-Heapify(A; posmax)
```