luni, 1 octombrie 2012

Elementul Median Divide et Impera

Problema Elementului Median se reduce defapt la calcularea celui mai mare/mai mic k element dintr-o secventa(de exemplu, in sirul [1 8 4 2 5] al treilea cel mai mic element este 4) problema ce se poate rezolva folosind Divide et Impera.


Ideea:selectia unui element dintr-un sir se poate reduce la sortarea sirului, ca mai apoi sa se extraga elementul dorit.
♣ Aceasta metoda este eficienta cand mai multe selectii trebuiesc facute intr-o lista, pentru ca exista doar O sortare initiala SCUMPA, urmata de operatii IEFTINE de extractie.

Algoritmul ineficient pentru extragerea celui mai mic/mai mare k element are complexitate temporala O(kn), si presupune alegerea celei mai "extreme" valori (cea mai mare/mica) si mutarea acesteia spre "inceputul" vectorului, pana ajungem la elementul dorit.

function select(list[1..n], k)
     for i from 1 to k
         minIndex = i
         minValue = list[i]
         for j from i+1 to n
             if list[j] < minValue
                 minIndex = j
                 minValue = list[j]
         swap list[i] and list[minIndex]
     return list[k]

Sursa cod:Wikipedia

ALGORITMUL DE SELECTIE GENERAL BAZAT PE PARTITIONARE

Algoritm creat de Hoare, inventatorul quicksort. Se mai numeste si quickselect.
Asemenea lui quicksort, acest algoritm foloseste o functie de paritionare care poate, in timp liniar (luand indecsii elementelor din vector de la stanga la dreapta), sa grupeze vectorul in doua parti:
  • elementele mai mici decat un anumit element ales, numit PIVOT si
  • elementele mai mari sau egale cu pivotul.

Adica o secventa [4 7 3 8 2 5 0], dupa calcularea pivotului, ar arata asa: [0 3 2 4 7 5 8], unde 4 este pivotul.

Iata codul in C++ (varianta mea)

//ELEMENT MEDIAN by Iulix

#include<iostream>
#include<stdint.h>
#include<math.h>
#include<vector>


using namespace std;

void interschimbare(int &a, int &b){
int aux;
aux = a;
a = b;
b = aux;
}

int partition_secv(vector<int> &secv, int left, int right, int indexPivot){
//patitionare quicksort
	int pivotValue, storeIndex;
	int i;
	pivotValue = secv[indexPivot];
	interschimbare(secv[indexPivot], secv[right]); //duc pivotul la sfarsitul vectorului
	storeIndex = left;
	
	for(i=left; i <=right-1; i++)
		if(secv[i]<pivotValue){
								interschimbare(secv[i], secv[storeIndex]);
								storeIndex++;
								}
	interschimbare(secv[right], secv[storeIndex]);

return storeIndex;
} 

int select_secv(vector<int> &secv, int left, int right, int k){
//algoritmul quickselect al lui Hoare	
	int newIndexPivot, indexPivot, pivotDistance=0;	
		
	if(left==right)
		return secv[left];
	indexPivot = secv[left]; //aleg pivotul initial ca fiind cel mai din stanga element
	newIndexPivot = partition_secv(secv, left, right, indexPivot); //noul pivot
	/*calculam pivotDistance, ceea ce inseamna distanta pivotului "maxim sortat" fata de cel mai din stanga 
	element al vectorului - in acest moment, deoarece a fost executata functia partition_secv, 
	vectorul va fi de forma (elemente mai mici decat pivot sortate)(pivot)(elemente mai mari decat pivot sortate)
	*/
	pivotDistance = newIndexPivot - left;
	//apoi comparam cu indexul cautat, k, ca sa vedem unde ne situam (in stanga pivotului sau in dreapta lui?)
	if(pivotDistance==k) return secv[newIndexPivot];
		else if(k > pivotDistance) //trebuie sa ma duc in dreapta
				return select_secv(secv, newIndexPivot+1, right, k - pivotDistance + 1);
			else //trebuie sa ma duc in stanga
				return select_secv(secv, left, newIndexPivot-1, k);
}

int main(){

vector<int> secventa;
int myint;
int k;
cout<<"Introduceti numerele din secventa:\nTastati 0 la sfarsitul secventei\n";

do{
	cin>>myint;
	secventa.push_back(myint);
}while(myint);

cout<<"Secventa pe care ati introdus-o: ";
int i;
for(i=0; i<secventa.size(); i++)
	cout<<secventa[i]<<" ";
cout<<"\n";

cout<<"introduceti k:\n"; cin>>k;

cout<<"Al "<<k<<"-lea cel mai mic element este "<<select_secv(secventa, 0, secventa.size()-1, k)<<"\n";


return 0;
}


Complexitatea temporala este in cel mai bun caz O(n), iar in cel mai rau caz, O(n^2).
Complexitatea acestui algoritm depinde in mare masura de alegerea pivotilor - de aceea s-a implementat un algoritm asemanator, BFPRT, in care vectorul este impartit in bucati de cate cinci elemente, carora apoi li se calculeaza elementul "median" (adica pivotul).

Resurse:
Wikipedia

Syntax Highlighters

Syntax Highlighters


Vrei sa transformi un cod ce arata asa:

#include<stdio.h>
#include<stdlib.h>

int main(){
 printf("Hello World");
 return 0;
}


...intr-un cod care arata asa:

#include<stdio.h>
#include<stdlib.h>

int main(){
 printf("Hello World");
 return 0;
}


Nimic mai simplu! Pentru HTML, poti folosi hilite.me , un site unde introduci codul tau (nu neaparat ceva in C, exista o gramada de optiuni) si care ti-l transforma in cod html.

Pentru mai multe Syntax Highlighters poti incerca acest site.

Have fun!

Merge Sort Divide et Impera

Divide et Impera - Merge Sort


Algoritmii Divide et Impera:
  • impart problema in subprobleme asemanatoare cu cea initiala, mai mici ca dimensiune pe care apoi le rezolva recusiv si apoi combina solutiile pentru a crea o solutie pentru problema originala;
  • 3 pasi:
    • Divide: problema data este divizata intr-un set de subprobleme;
    • Impera: subproblemele sunt rezolvate recursiv (daca sunt suficient de mici, sunt rezolvate direct);
    • Combina: solutiile problemelor sunt combinate pentru a obtine solutia problemei initiale;
  • Avantaje: algoritmi eficienti; faciliteaza paralelizarea algoritmului;
  • Dezavantaje: overheaddatorat recusivitatii.


Merge Sort

1.Divide: divide cele n elemente ce trebuie sortate in n/2, pana se ajunge la submultimi de UN element -care sunt deja sortate.
2.Impera: sorteaza recursiv secventele folosind Merge Sort.
3.Combina: se asambleaza solutiile initiale.

Lucrurile vor evolua cam asa:


Sursa Imaginii: Wikipedia


Si acum, codul meu...



Codul (in C):
// Mergesort in C
  #include<stdio.h>
  #include<stdlib.h>

#define INF 3200

int p=1; int r=7;
int A[100];


int initialize_vector(int A[]){
A[1]=10 ;A[2]=1 ;A[3]=17 ;A[4]=0 ;A[5]=2 ;A[6]=1 ;A[7]=0 ;
}

int MERGE_eu(int A[],int p, int q, int r){
 int n1, n2; //n1 = nr elem din stanga, n2 = nr elem din dreapta
 n1 = q-p+1;
 n2 = r-q;
//S[] = vector elem stanga, D[] = vector elem dreapta - alocare dinamica
 int *S, *D;
 S = (int *)calloc(n1+1, sizeof(int));
 D = (int *)calloc(n2+1, sizeof(int));
//acum initializam vectorii, S preia valorile din A-ul stang, D din A-ul drept
 int i, j;
 for(i=1; i<=n1; i++)
  S[i]=A[p+i-1];
 for(j=1; j<=n2; j++)
  D[j]=A[q+j];
 
 S[n1+1]=INF; D[n2+1]=INF;
 i=1; j=1;
 
 int k;
 for(k=p; k<=r; k++)
  if(S[i]<=D[j]){
   A[k]=S[i]; i=i+1;}
  
  else {
   A[k]=D[j]; j=j+1; } 
}

int MERGE_SORT_eu(int A[], int p, int r){
     if(p<r){ //daca p>=r, inseamna ca vectorul are maxim 1 element -e sortat deja
 int q = (p+r)/2; //mijlocul vectorului
 MERGE_SORT_eu(A, p, q); //stanga
 MERGE_SORT_eu(A, q+1, r); //dreapta
 MERGE_eu(A, p, q, r); //combinarea subsecventelor
 }

}

int main(){
 printf("test\n");
 initialize_vector(A);
 MERGE_SORT_eu(A,p,r);
int i;
for(i=p; i<=r; i++)
 printf("%d ", A[i]);
printf("\n");

return 0;
}



Surse:

miercuri, 25 ianuarie 2012

Intro

Si uite-asa m-am hotarat sa va scriu un blog despre informatica...
... deoarece am observat ca exista destul de putine tutoriale in limba romana care sa ofere explicatii complete asupra anumitor probleme si tehnici de programare.

Mai degraba, va ofer viziunea mea asupra unor probleme.

Sper sa gasiti acest blog util si distractiv ;)