Sei sulla pagina 1di 22

------ALGORITMI DA IMPARARE:------

-->CAPITOLO 1: ALGORITMI
1)ALGORITMI DI RICERCA SU VETTORI:

A)RICERCA LINEARE:

int LinSearch(int v[],int l,int r, int key){


int i=l;
int found=0;

while(i<=r && found == 0){


if(key=v[i])
found=1;
else
i++;
}
if(found==0)
return -1;
return i;
}
__COMPLESSITA': n;
---------------------------------------------------------------------
b)RICERCA BINARIA su vettore ORDINATO:

int BinSearch(int v[], int l,int r, int key){


int m;

while(l<=r){
m=l+(r-l)/2;
if(v[m]==key)
return m;
if(v[m]<key)
l=m+1;
if(v[m]>key)
r=m-1;
}
return -1;
}
__COMPLESSITA': log(n)
----------------------------------------------------------------------

c)INSERTION SORT:

void InsertionSort(int A[], int l, int r){

int i,j,x;
for(i=l+1;i<=r;i++){
x=A[i];
j=i-1;
while(j>=l && x<A[j]){
A[j+1]=A[j];
j--;
}
A[j+1]=x;
}
}
__COMPLESSITA': caso peggiore: n^2; caso migliore: n;
____________________________________________________________________________________________
--->CAPITOLO 2: COMPLESSITA'

ONLINE CONNECTIVITY:

1)QUICK FIND:

inizialmente id[i]=i //nessuna connessione; l'elemento del vettore id corrisponde al suo indice
se p e q sono connessi, id[p]=id[q]
algoritmo:
1. leggi la coppia (p,q)
2.se id[p]==id[q] non fare nulla e passa alla coppia successiva,
altrimenti connette la coppia scandendo il vettore e cambiando gli elementi che valgono p in q

FIND: costo unitario


UNION: costo lineare (scansione del vettore)

#define N 1000;
nel main:

int i,t,p,q,id[N];
for(i=0;i<N;i++) id[i]=i; //inizializza tutti gli elementi del vettore uguali al loro indice
printf("Leggi p,q");
while(scanf("%d %d",&p,&q)==2){

if(id[p]==id[q])
//stampa che sono già connessi
else{
for(t=id[p],i=0;i<N;i++)
if(id[i]==t)
id[i]=id[q];
//stampa che p e q non sono ancora connessi
}
}
--------------------------------------------------------------------------------------------------
2)QUICK UNION:

inizialmente id[i]=i;
//ogni oggetto punta o a un oggetto cui è connesso o a se stesso (no cicli)
//indicando con (id[i])* =id[id[id[...id[i]]]]
se oggetti i e j connessi, (id[i])*=(id[j])*

algoritmo:
1. leggi coppia p,q
2. se (id[i])*=(id[j])* non fare nulla perchè già connessa e passa a quella dopo;
altrimenti id[(id[p])*]=(id[q])* //connetti la coppia

FIND: percorrimento a catena, lineare


UNION: unitario

int i,j,p,q,id[1000];
for(i=0;i<N;i++) id[i]=i;
while(//leggi p,q correttamente){
for(i=p;i!=id[i];i=id[i]);
for(j=q;j!=id[j];j=id[j]);
if(i==j)
//gia connesse
//altrimenti
id[i]=j;
}
--------------------------------------------------------------------------------------------------
3)WEIGHTED QUICK UNION
//riduco la lunghezza della catena
si mantiene traccia del numero di elementi di ciascun albero (array sz) e si
collega l'albero più piccolo a quello più grande

int i,j,p,q,id[1000],sz[1000];
for(i=0;i<N;i++) {id[i]=i,sz[i]=1};
while(//leggi p,q correttamente){
for(i=p;i!=id[i];i=id[i]);
for(j=q;j!=id[j];j=id[j]);
if(i==j)
//gia connesse
//altrimenti
if(sz[i]<sz[j]){
id[i]=j;
sz[j]+=sz[i];}
else{ id[j]=i; sz[i]+=sz[j]}
}

FIND: al massimo è logaritmico


UNION: unitario;

____________________________________________________________________________________________________

----> CAPITOLO 3: ORDINAMENTI ITERATIVI:

1)BUBBLE SORT ottimizzato col flag:

//2 sottov: dx ordinato, inizialmente vuoto; sx disordinato, inizialmente A;

void optBubbleSort(Item A[], int l, int r){


int i,j;
Item temp;
int flag=1;
for(i=l;i<r && flag==1;i++){
flag=0;
for(j=l;j<r-i+l;j++){ //i-l=numero di caselle a destra già ordinato
if(greater(A[j],A[j+1])){
flag=1;
temp=A[j];
A[j]=A[j+1];
A[j+1]=temp;
}
}
}
return;
}
___IN LOCO, STABILE; complessità scambi/confronto = n^2;
----------------------------------------------------------------------------------------------------

2)SELECTION SORT

//2 sottovet: dx disordinato, inizialmente A; sx ordinato, inizialmente vuoto;


//passo iesimo: il minimo del sottovet dx è assegnato a A[i], incremento poi i;

void SelectionSort(Item A[],int l,int r){


int i,j,min;
Item temp;
for(i=l;i<r;i++){
min=i;
for(j=i+1;j<=r;j++){
if(less(A[j],A[min]))
min=j;
}
temp=A[i];
A[i]=A[min];
A[min]=temp;
}
return;
}
___IN LOCO, NON STABILE; scambio nel caso peggiore: lineare; confronto peggiore: n^2;
----------------------------------------------------------------------------------------------------------

3)INSERTION SORT: //guardare capitolo 1


___IN LOCO, STABILE; scambio/confronto= n^2;
-----------------------------------------------------------------------------------------------------------

4)SHELLSORT:

//confronta e scambia elementi a distanza h tra loro (modifica dell'insertion che scambia solo
adiacenti)
//definisce una sequenza decrescente di interi h che termina con 1

void ShellSort(Item A[],int l,int r){


int i,j,h=1,n=r-l+1;
Item temp;
while(h<n/3)
h=3*h+1;
while(h>=1){
//Insertion sort su ogni sottosequenza, i cui elementi sono distanti h tra loro
for(i=l+h;i<=r;i++){
j=i;
temp=A[i];
while(j>=l+h && less(temp,A[j-h])){
A[j]=A[j-h];
j-=h;
}
A[j]=temp;
}
h=h/3;
}
return;
}
___IN LOCO, NON STABILE; complessità che dipende dalla sequenza: knuth=N^(3/2), originale shell
degenera in n^2;
-----------------------------------------------------------------------------------------------------------
5) COUNTING SORT:
//ordinamento per calcolo
//3 vettori:
A[0..n-1] di partenza
B[0...n-1] risultato
C[0...k-1] occorrenze, k interi se i dati sono nell'intervallo [0...k-1]
1. occorrenze semplici
C[i]=numero di elementi di A pari ad i;
2. occorrenze multiple
C[i]= numero di elementi di A <=i;
3. per ogni j
C[A[j]]=numero di elementi <=A[j]
posizione finale A[j] in N:
B[C[A[j]]]=A[j]

#define MAX 100


void CountingSort(Item A[],int l,int r, int k){
int i,n,C[MAX];///dinamicamente: int *C
Item B[MAX]; ///oppure allocati dimanicamente *B
n=r-l+1;
//dinamicamente: *B=malloc(n*sizeof(Item)); C=malloc(k*sizeof(int));

for(i=0;i<k;i++)
C[i]=0;
for(i=l;i<=r;i++)
C[A[i]]++;
for(i=1;i<k;i++)
C[i]+=C[i-1];
for(i=r;i>=l;i--){
B[C[A[i]]]=A[i];
C[A[i]]--;
}
for(i=l;i<=r;i++)
A[i]=B[i];
return;
}
___STABILE,NON IN LOCO, CONVENIENTE PER POCHI ELEMENTI, lineare;
_________________________________________________________________________________________________________________
_____________
---->CAPITOLO 5: RICORSIONE:
1)MASSIMO DI UN VETTORE:
//se n=1, l'unico elemento è il massimo
//n>1: divido il vettore in due sottovett a metà e ricerco il massimo di entrambi;
confronto i due risultati e restituisco il più grande

int max(int a[],int l,int r){


int u,v;
int m= (l+r)/2;
if(l==r)
return a[l]; //terminazione
u=max(a,l,m);
v=max(a,m+1,r;
if(u>v)
return u;
return v;
}
-----------------------------------------------------------------------------------------------------------------
--------------

2)RICERCA BINARIA su vettore ordinato

int BinSearch(int v[], int l, int r,int k){


int m;
if((r-l)==0)
if(v[l]==K)
return l;
else
return -1;
m=(l+r)/2;
if(v[m]>=k)
return(BinSearch(v,l,m,k));
return(BinSearc(v,m+1,r,k));
}
-----------------------------------------------------------------------------------------------------------------
-------------
3)Numero nodi/ ALTEZZA ALBERO BINARIO
typedef struct node *link;
struct node{
char *name;
link l,r;
};//definiti tramite lista

//h= puntatore alla redice (head)


//z=nodo sentinella fittizio

int count(link h,link z){


if(h==z)
return 0;
return count(h->l,z)+count(h->r,z)+1;
}

int height(link h, link z){

int u,v;
if(h==z)
return -1;
u=heigh(h->l,z);
v=heigh(h->r,z);
if(u>v)
return u+1;
return v+1;
}
_________________________________________________________________________________________________________________
____________

----> CAPITOLO 6: ORDINAMENTI RICORSIVI:

1)MERGE SORT:

//divisione: due sottov dx e sx rispetto al centro del vettore


//Ricorsione:
-merge sort su vett sx
-merge sort su vtt dx
-condizione di terminazione con 1 (l==r) o 0 (l>r) elementi il vtt è ordinato
//Ricombinazione: fonde i sottovett ordinati in un vtt ordinato

void MergeSort(Item *A,int N){


int l=0,r=N-1;
Item *B =(Item *)malloc(N*sizeof(Item)); //vettore ausiliario della stessa dim di A
MergeSortR(A,B,l,r);
}

void MergeSortR(Item *A, Item *B, int l, int r){

int q=(l+r)/2; //indice medio del vettore


if(r<=l) //vettore di 1 o 0 elementi, quindi ordinato, caso di terminazione
return;

MergeSortR(A,B,l,q); //ricorsiva su vtt sx


MergeSortR(A,B,q+1,r);//ricorsiva vtt dx
Merge(A,B,l,q,r);
}

void Merge(Item *A, Item *B, int l,int q,int r){


int i,j,k;
i=l;
j=q+1;
for(k=l;k<=r;k++){

if(i>q)
B[k]=A[j++];
else if(j>r)
B[k]=A[i++];
else if(less(A[i],A[j])|| eq(A[i],A[j]))
B[k]=A[i++];
else
B[k]=A[j++];
}
for(k=l;k<=r;k++){
A[k]=B[k];
}
return;
}
_____STABILE NON IN LOCO; linearitmico;
--------------------------------------------------------------------------------------------

2)BOTTOMUP MERGESORT (ITERATIVO)

//parte da sottovettori di lunghezza 1 (ordinati), applica il merge per ottenere


//ad ogni passo sottovettori di lunghezza doppia. Termina quando si raggiunge la
//dimensione del vettore originale
int min(int A,int B){
if(A<B)
return A;
return B;
}

void BottomUpMergeSort(Item *A, int N){

int i,m,l=0,r=N-1;
Item *B=(Item *)malloc(N*sizeof(Item));
for(m=1;m<=r-l;m=m+m) //raddoppio della dimensione del vettore ordinato
//coppie di sottovettori ordinati di dimensione m
for(i=l;i<=r-m;i+=m+m)
Merge(A,B,i,i+m-1,min(i+m+m-1,r));
}
------------------------------------------------------------------------------------------------------------

3)QUICKSORT

//partiziona il vettore in due sottv dx e sx


//dato un elemento pivot x=A[q]
//sx contiene tutti gli elementi <x
//dx contiente tutti gli elementi >x
//A[q] si trova al posto giusto
//divisione non necessariamente a metà (come invece nel mergesort)

//Quicksort su sx, quick su dx; terminazione: vettore di 1 elemento; ricombinazione nulla;

////PARTITION A' LA HOARE


-pivot x=A[r]
-individua A[i] e A[j] elementi fuori posto:
-ciclo discentente j fino a trovare un elemento minore del pivot x;
-ciclo ascendente su i fino a trovare un elemento maggiore del pivot x;
-scambia A[i] e A[j]
-ripeti fino che i<j
-alla fine scambia A[i] con il pivot x;
-ritorna q=i;

void QuickSort(Item *A,int N){


int l=0,r=N-1;
QuickSortR(A,l,r);
}

void quicksortR(Item *A,int l,int r){

int q;
if(r<=l)
return;
q=partition(A,l,r);
quicksortR(A,l,q);
quicksortR(A,q+1,r);
return;
}
void Swap(Item *v,int n1,int n2){
Item temp;
temp=v[n1];
v[n1]=v[n2];
v[n2]=temp;
return;
}
void partition(Item *A,int l,int r){

int i=l-1,j=r;
Item x=A[r];
for( ; ; ){
while(less(A[++i],x));//incrementa i finchè non trova un elemento maggiore del pivot
while(greater(A[j--],x));//decrementa j finchè non trova un elemento minore del pivot
if(j==l)
break;
if(i>=j)
break;
Swap(A,i,j);//scambia A[i] e A[j]
}
Swap(A,i,r); //scambia A[i]con il pivot x
return i;
}

____IN LOCO NON STABILE; efficenza legata alle partizioni: se il pivot è già il max o min: n^2. Caso
migliore: nlogn; Caso medio=caso migliore;
_________________________________________________________________________________________________________________
________________________________________________

---->CAPITOLO 7: PROBLEMI DI RICERCA E OTTIMIZZAZIONE:

1)PRINCIPIO DI MOLTIPLICAZIONE

typedef struct{ int *scelte; int num_scelte;}Livello;


val=malloc(n*sizeof(Livello));

for(i=0;i<n;i++)
val[i].scelte=malloc(val[i].num_scelte*sizeof(int));
sol=malloc(n*sizeof(int));

...

int princ_molt(int pos, Livello *val, int *sol,int n, int count){

int i;
if(pos>=n){
for(i=0;i<n;i++)
printf("%d",sol[i]);
printf("\n");
return count +1;
}//terminazione

for(i=0;i<val[pos].num_scelte;i++){
sol[pos]=val[pos].scelte[i];
count=princ_molt(pos+1,val,sol,n,count);
}
return count;
}

--------------------------------------------------------------------------------------------------------

2)DISPOSIZIONI SEMPLICI:

val=malloc(n*sizeof(int));
sol=malloc(k*sizeof(int));
mark=malloc(n*sizeof(int));

int disp(int pos,int *val,int *sol,int *mark,int n,int k,int count){

int i;
if(pos>=k){
for(i=0;i<k;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=0;i<n;i++){
if(mark[i]==0){
mark[i]=1;
sol[pos]=val[i];
count=disp(pos+1,val,sol,mark,n,k,count);
mark[i]=0;//backtracking
}
}
return count;
}
--------------------------------------------------------------------------------------------------------

3)DISPOSIZIONI RIPETUTE:
val=malloc(n*sizeof(int));
sol=malloc(k*sizeof(int));

int disp_rip(int pos,int *val,int *sol,int *mark,int n,int k,int count){

int i;
if(pos>=k){
for(i=0;i<k;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=0;i<n;i++){

sol[pos]=val[i];
count=disp_rip(pos+1,val,sol,mark,n,k,count);

}
return count;
}
-------------------------------------------------------------------------------------------------------

4)PERMUTAZIONI SEMPLICI:

val=malloc(n*sizeof(int));
sol=malloc(n*sizeof(int));
mark=malloc(n*sizeof(int));

int perm(int pos,int *val,int *sol,int *mark,int n,int count){

int i;
if(pos>=n){
for(i=0;i<n;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=0;i<n;i++){
if(mark[i]==0){
mark[i]=1;
sol[pos]=val[i];
count=perm(pos+1,val,sol,mark,n,count);
mark[i]=0;//backtracking
}
}
return count;
}
-----------------------------------------------------------------------------------------------------

5)PERMUTAZIONI CON RIPETIZIONE:

val=malloc(n*sizeof(int));
dist_val=malloc(n*sizeof(int));//contiene gli elementi distindi del multiset (sono di numero
n_dist)
sol=malloc(k*sizeof(int));
mark=malloc(n*sizeof(int));//in parallelo a dist_val, memorizza il numero di occorrenze di ogni
elemento di dist_val

int perm_r(int pos,int *dist_val, int *sol, int *mark, int n, int n_dist, int count){

int i;
if(pos>=n){
for(i=0;i<n;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=0;i<n_dist;i++){
if(mark[i]>0){
mark[i]--;
sol[pos]=dist_val[i];
count=perm_r(pos+1,dist_val,sol,mark,n,n_dist,count);
mark[i]++;//backtrack
}
}
return count;
}
---------------------------------------------------------------------------------------------------------

6)COMBINAZIONI SEMPLICI:

val=malloc(n*sizeof(int));
sol=malloc(k*sizeof(int));
//start determina a partire da quale valore di val si inizia a riempire sol

int comb(int pos,int *val, int *sol, int n,int k,int start,int count){

int i,j;
if(pos>=k){
for(i=0;i<k;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=start;i<n;i++){
sol[pos]=val[i];
count=comb(pos+1,val,sol,n,k,i+1,count);
}
return count;
}
--------------------------------------------------------------------------------------------------------

7)COMBINAZIONI RIPETUTE:

val=malloc(n*sizeof(int));
sol=malloc(k*sizeof(int));
//start determina a partire da quale valore di val si inizia a riempire sol

int comb(int pos,int *val, int *sol, int n,int k,int start,int count){

int i,j;
if(pos>=k){
for(i=0;i<k;i++) printf("%d",sol[i]);
printf("\n");
return count+1;
}
for(i=start;i<n;i++){
sol[pos]=val[i];
count=comb(pos+1,val,sol,n,k,start,count);
start++;
}
return count;
}
--------------------------------------------------------------------------------------------------------

8)INSIEME DELLE PARTI:

a)Ricorsivo:

int powerset(int pos, int *val, int *sol, int k, int start, int count){

int i;
if(start>=k){

for(i=0;i<pos;i++)
printf(“%d”,sol[i]);
printf(“\n”);
return count+1;
}
for(i=start;i<k;i++){
sol[pos]=val[i];
count=powerset(pos+1,val,sol,k,i+1,count);
}
count=powerset(pos,val,sol,k,k,count);
return count;
}

b)Con disposizioni ripetute:

int powerset(int pos,int *val,int *sol,int k,int count){


int j;
if(pos>=k){
printf(“{ \t”);
for(j=0;j<k;j++)
if(sol[j]!=0)
printf(“%d \t”,val[j]);
printf(“} \n”);
return count+1;
}
sol[pos]=0; //non prendere l’elemento pos
count=powerset(pos+1,val,sol,k,count);//ricorri su pos+1
sol[pos]=1; //backtrack: prendi l’elemento pos
count=powerset(pos+1,val,sol,k,count);
return count;
}

c)Con combinazioni semplici:

int powerset_simp_comb(int* val, int k, int* sol){


int count = 0, n;
printf("{ }\n");
count++;
for(n = 1; n <= k; n++){
count += powerset_r(val, k, sol, n, 0, 0);
}
return count;
}

int powerset_r(int* val, int k, int* sol, int n, int pos, int start){
int count = 0, i;
if (pos == n){
printf("{ ");
for (i = 0; i < n; i++)
printf("%d ", sol[i]);
printf("}\n");
return 1;
}
for (i = start; i < k; i++){
sol[pos] = val[i];
count += powerset_r(val, k, sol, n, pos+1, i+1);
}
return count;
}
--------------------------------------------------------------------------------------------------------

9)INSIEME DELLE PARTI:

a)Con disposizioni ripetute:

void disp_ripet(int pos, int *val, int *sol, int n, int k) {


int i, j, t, ok=1, *occ;
occ = calloc(n, sizeof(int));

if (pos >= n) {
for (j=0; j<n; j++)
occ[sol[j]]++;
i=0;
while ((i < k) && ok) {
if (occ[i]==0)
ok = 0;
i++;
}
free(occ);
if (ok == 0)
return;
else {
printf("partizione: ");
for (i=0; i<k; i++) {
printf("{ ");
for (j=0; j<n; j++) {
if (sol[j]==i)
printf("%d ", val[j]);
}
printf("} ");
}
printf("\n");
return;
}
}
for (i = 0; i < k; i++) {
sol[pos] = i;
disp_ripet(pos+1, val, sol, n, k);
}
}

b)ALGORITMO DI ER

//PER TUTTE LE PARTIZIONI:


void SP_rec(int n,int m,int pos,int *sol,int *val) {
int i, j;
if (pos >= n) {
printf("partizione in %d blocchi: ", m);
for (i=0; i<m; i++) {
printf("{ ");
for (j=0; j<n; j++)
if (sol[j]==i)
printf("%d ", val[j]);
printf("} ");
}
printf("\n");
return;
}
for (i=0; i<m; i++) {
sol[pos] = i;
SP_rec(n, m, pos+1, sol, val);
}
sol[pos] = m;
SP_rec(n, m+1, pos+1, sol, val);
}

// PARTIZIONI IN K BLOCCHI.
void SP_rec(int n, int k, int m, int pos, int *sol, int *val) {
int i, j;
if (pos >= n) {
if (m == k) {
for (i=0; i<m; i++) {
printf("{ ");
for (j=0; j<n; j++) {
if (sol[j]==i)
printf("%d ", val[j]);
}
printf("} ");
}
printf("\n");
}
return;
}

for (i=0; i<m; i++) {


sol[pos] = i;
SP_rec(n, k, m, pos+1, sol, val);
}
sol[pos] = m;
SP_rec(n, k, m+1, pos+1, sol, val);
}