Sottoinsiemi disgiunti E’ dato un insieme V e una collezione C di sottoinsiemi di V fra loro disgiunti C = {C1, C2, …,Cr} Ci V (i = 1,…,r) Ci Cj = (i j) Vogliamo poter creare sottoinsiemi di un solo elemento v (MakeSet) sapere a che sottoinsieme appartiene l’elemento v(FindSet) fondere due sottoinsiemi in uno solo (Union)
Applicazioni dei sottoinsiemi disgiunti Perché ci interessa? le componenti connesse di un grafo sono sottoinsiemi disgiunti l’algoritmo di Kruskal per l’albero ricoprente minimo deve sapere quali vertici sono già connessi ConnectedComponents(G,c) For v = 1 to n do MakeSet(v) For each [u,v] E do r = FindSet(u) s = FindSet(v) If r s then Union(r,s)
Rappresentazione a liste L’idea più spontanea è rappresentare ogni sottoinsieme con una lista • C • F • • A • B • D • E •
Rappresentazione a liste Ogni sottoinsieme ha un elemento rappresentativo (scelto ad arbitrio) Ogni elemento del sottoinsieme punta l’elemento rappresentativo (FindSet ha complessità O(1)) Ogni elemento del sottoinsieme punta il successivo Per fondere due sottoinsiemi, occorre accodare una lista all’altra (O(1)): meglio la più corta modificare tutti i puntatori all’elemento rappresentativo della prima lista (O(n)) (Union ha complessità O(n))
Rappresentazione a foresta La funzione Union si eseguirà al più n-1 volte Una sequenza di n-1 Union fatte accodando la lista più corta alla più lunga non costa O(n2), ma O(n log n) Ma si può migliorare ancora... Ogni elemento punta indirettamente all’elemento rappresentativo, cioè l’elemento rappresentativo è solo il termine di una catena di puntatori Per fondere due liste, basta che l’elemento rappresentativo della seconda punti quello della prima
Rappresentazione a foresta B A C D F E X = {[A,B], [C,F], [E,D], [A,D] [B,E] [A,E]} C • F • D • E • A • B • Si accelera Union da O(n) a O(1) Si rallenta FindSet da O(1) a O(d) dove d è la lunghezza della catena (quasi O(1)!)
Rappresentazione a foresta MakeSet(v) p[v] = v rank[v] = 0 FindSet(v) While p[v] v do v = p[v] p[v] è l’elemento puntato da v rank[v] il numero di livelli sotto v Union(r,s) If rank[r] < rank[s] then p[r] = s else p[s] = r If rank[r] = rank[s] rank[r]++