30 aprilie 2010

Heapsort

O structură de date Heap este un arbore binar complet, cu proprietatea că o cheie-părinte este mai mică (in cazul min Heap)/mai mare (în cazul max Heap) decât toți fiii săi. În realitate, arborele se reprezintă ca un vector în care „nodul” aflat pe poziția i are ca părinte un nod de pe poziție (i-1)/2 , iar fiii săi se află pe pozițiile 2*i+1 respectiv 2*i+2 din vector.

În următorul program din C, se creează un Heap dintr-un vector, inițial cu elemente în ordinea vectorului (nerespectând proprietatea); după care se mută elementele in așa fel încât să se respecte proprietatea de Heap.
Dintr-un Heap se pot extrage cu ușurință elementele minime pentru ca reprezintă poziția 0 din vector (sau rădăcina din arborele imaginat), și astfel tot extrăgând minimul se obține o listă sortată cu o complexitate N*log N.
După ce se extrage un element din Heap, se alege ultimul element din vectorul de Heap (a cărei poziție este sigur ocupată) și se mută de la rădăcină, în căutarea unui loc potrivit in Heap unde să fie respectată proprietatea. Astfel, Heap-ul este refăcut.
Când se adaugă un element, se adaugă inițial la sfârșit după care se urcă în căutarea unui loc potrivit, cum am spus și mai sus.
#include "stdio.h"
#include"stdlib.h"
typedef struct heap_vector_struct
{
// Vectorul de elemente
int *values;
// Dimensiunea heap-ului
int dimVect;
// Capacitatea (dimensiunea maxima)
int capVect;
} HeapVector;


HeapVector* CreeazaVector(int *value, int dimV, int capV) {
HeapVector * HV;
HV=(HeapVector*)malloc(sizeof(HeapVector));
HV->dimVect=dimV;
HV->capVect=capV;
HV->values=(int*)malloc(capV*sizeof(int));
int i;
printf("vectorul meu:\n");
for (i=0;i<=dimV-1; i++){
HV->values[i]=value[i];
printf("%d ",value[i]);}
printf("\n");
return HV;
}
void ElibereazaVector(HeapVector *h) {
free(h->values);
free(h);
}
// returneaza pozitia parintelui
int Parinte(HeapVector *h, int poz) {
if (h->values[(poz-1)/2])
return (poz-1)/2;
return -1;
}
int DescS(HeapVector *h, int poz) { //pozitie fiu stanga
if (h->values[2*poz+1])
return 2*poz+1;
return -1;
}

int DescD(HeapVector *h, int poz) { //pozitie fiu dreapta, daca exista
if (h->values[2*poz+2])
return 2*poz+2;
return -1;
}

int min(int a , int b, int c) {
int y=a;
if (y > b)
y=b;
if (y > c)
y=c;
return y;
}

void InterschimbaValori(HeapVector *h, int a , int b) {
int c=h->values[a];
h->values[a]=h->values[b];
h->values[b]=c;
}

void CoboaraValoare(HeapVector *h, int poz) {
int pozDesc=0;
while(1) {
if (DescD(h,poz) && DescS(h,poz)) {
int valMin = min(h->values[poz], h->values[DescS(h,poz)],h->values [DescD(h,poz)]);
if (valMin == h->values[poz])
return; // nimic de facut
if (valMin == h->values[DescS(h,poz)])
pozDesc =DescS(h,poz);
else
pozDesc = DescD(h,poz);
InterschimbaValori(h,poz, pozDesc);
poz = pozDesc;
}
else return;
}
}
void CoboaraValoaresort(HeapVector *h, int poz) {
int pozDesc=0;
while (1) {
if (DescD(h,poz)&&DescS(h,poz)) {
int valMin = min(h->values[poz], h->values[DescS(h,poz)],h->values [DescD(h,poz)]);
if (valMin == h->values[poz])
return; // nimic de facut
if (valMin == h->values[DescS(h,poz)])
pozDesc =DescS(h,poz);
else
pozDesc = DescD(h,poz);
InterschimbaValori(h,poz, pozDesc);
poz = pozDesc;
}
}
}
void UrcaValoare(HeapVector *h, int poz) {
while (poz > 0 && h->values[poz] > h->values[Parinte(h,poz)]) {
// ... interschimbam nodul curent cu parintele
InterschimbaValori(h,poz, Parinte(h,poz));
// Urcam pozitia curenta mai sus cu un nivel si reluam
poz = Parinte(h,poz);
}
}
int Minim(HeapVector *h) {
return h->values[0];
}


int ExtrageMinim(HeapVector *h) { // ia minimul si il sterge
int min=h->values[0];
int g=h->dimVect-1;
InterschimbaValori(h,0,g);
h->dimVect--;
CoboaraValoare(h,0);
return min;
}
void ConstruiesteHeap(HeapVector *h) {
int i;
for (i=h->dimVect/2; i>= 0; i--)
CoboaraValoare(h,i);
}

void AdaugaValoare(HeapVector *h, int val) {
h->dimVect++;
if (h->capVectdimVect) {
h->capVect++;
h->values=(int*)realloc(h,h->capVect*sizeof(int));
}
h->values[h->dimVect-1]=val;
UrcaValoare(h,h->dimVect-1);
}

void HeapSort1(HeapVector *h) {
int *minim;
minim=(int*)malloc(h->dimVect*sizeof(int));

int i;
for(i=0;idimVect; i++){
minim[i]=ExtrageMinim(h);
printf("%d ", minim[i]); }
}

int main () {
int i,p, *s;
s=(int*)malloc(30*sizeof(int));
for(i=0;i<=13 ;i++)
scanf("%d",&s[i];

HeapVector *H;
H=CreeazaVector(s,14,30);
ConstruiesteHeap(H);
printf("asta e heapul:");
for (i=0; i<=13;i++)
printf("%d ",H->values[i]);

printf("\nvectorul sortat :");
HeapSort1(H);
printf("\nvectorul sortat");
for (i=0;i<=9;i++)
printf("%d ",H->values[i]);
ElibereazaVector(H);
return 0;
}

28 aprilie 2010

Fapte si reguli in Clips

; inlocuirea tuturor aparitiilor unui nr cu altul
(deffacts facts (list 1 2 3 2 5) (before 2) (after 10))

(defrule inloc
(before ?x)
(after ?y)
?p<-(list $?a ?b $?c)
(test (eq ?x ?b))
=> (retract ?p)
(assert (list $?a ?y $?c)))

; reuniunea oricator multimi
(deffacts sets (set 1 2 3 4) (set 3 4 5) (set 7 8) (union ))

(defrule reunion
?p<-(set $?a ?b $?c)
?q<-(union $?u)
(test (not (member ?b $?u)))
=> (retract ?q)
(assert (union $?u ?b)))

; intersectia oricator multimi
(deffacts sets (set 1 2 3 4) (set 3 4 5) (set 7 8 3 4))

(defrule init
(not (inter $?x))
?z<-(set $?l)
=> (assert (inter $?l )))

(defrule intersect
?q<-(inter $?a ?b $?c)
?p<-(set $?ll)
(test (not (member ?b $?ll)))
=> (retract ?q)
(assert (inter $?a $?c)))

; toate permutarile unei multimi
(deffacts facts (set 1 2 3))

(defrule perm
?p<-(set $?a ?b ?c $?d)
=> (assert (set $?a ?c ?b $?d)))

; sortarea unei liste folosind bubble sort
(deffacts facts (set 4 7 9 1 2 3))

(defrule sort
?p<-(set $?a ?b $?e ?c $?d)
(test ( > ?b ?c))
=> (retract ?p)
(assert (set $?a ?c $?e ?b $?d)))

; daca un nod este accesibil din alt nod
(deftemplate edge (slot node) (multislot succs))
(deftemplate cale (slot start) (slot stop))

(deffacts varfuri
(edge (node 1) (succs 2 3 4))
(edge (node 2) (succs 1 3))
(edge (node 3) (succs 1 4))
(edge (node 4) (succs )))

(deffacts GAP
(cale (start 2) (stop 4)))
(defrule accesibilitate-directa
(edge (node ?u) (succs $? ?v $?))
=> (assert (accesibil ?u ?v)))

(defrule accesibilitate-indirecta
(accesibil ?u ?z)
(accesibil ?z ?v)
=> (assert (accesibil ?u ?v)))

(defrule solutie
(cale (start ?u) (stop ?v))
(accesibil ?u ?v)
=> (printout t "Da, " ?v " este accesibil din " ?u crlf)
(halt))

;max a doua numere
(deffacts n (numbers 5 17))

(defrule select_max1
(numbers ?x ?y )
(test (> ?x ?y))
=> (assert (maxim ?x)))

(defrule select_max2
(numbers ?x ?y )
(test (<= ?x ?y))
=> (assert (maxim ?y)))
(defrule printmax
(maxim ?n)
=>
(printout t ?n crlf))

;max intre oricate nr
(deffacts numbers
(number 6)
(number -1)
(number 2))

(defrule initmax
(not (maxim ?))
(number ?x)
=> (assert (maxim ?x)))

(defrule comp
(number ?n)
?p <- (maxim ?m)
(test ( < ?m ?n))
=> (retract ?p)
(assert (maxim ?n)))

(defrule printmax
(maxim ?n)
=>
(printout t ?n crlf))

; distanta minima intre 2 noduri, intr-un graf orientat, cu costuri
; aflare dacă un graf e conex
(deftemplate muchie (slot from) (slot to) (slot cost))
(deftemplate cale (slot start) (slot stop))

(deffacts nodes (noduri 1 2 3 4 5 6) (cost_infinit 1000) (ok 0))

(deffacts varfuri
(muchie (from 1) (to 2) (cost 5))
(muchie (from 1) (to 3) (cost 3))
(muchie (from 1) (to 4) (cost 8))
(muchie (from 3) (to 4) (cost 2))
(muchie (from 3) (to 5) (cost 2))
(muchie (from 4) (to 1) (cost 8))
(muchie (from 4) (to 6) (cost 1))
(muchie (from 5) (to 4) (cost 4))
(muchie (from 6) (to 2) (cost 3))
)

(deffacts turneu
(cale (start 1) (stop 6)))

(defrule init
(noduri $? ?x $?)
(noduri $? ?y $?)
(test (not (eq ?x ?y)))
(cost_infinit ?c )
=> (assert (drum ?x ?y ?c))
(assert (drum ?y ?x ?c))
)
(defrule init_arce_directe
(muchie (from ?x) (to ?y) (cost ?c))
?p<-(drum ?x ?y ?cost)
(test (not (eq ?x ?y)))
(cost_infinit ?inf)
(test (eq ?inf ?cost))
=> (retract ?p)
(assert (drum ?x ?y ?c))
)
(defrule drum-min
(drum ?u ?v ?c1)
(drum ?v ?w ?c2)
?p<-(drum ?u ?w ?cost)
(test (> ?cost (+ ?c1 ?c2)))
=> (retract ?p)
(assert (drum ?u ?w (+ ?c1 ?c2))))

(defrule solutie
(cale (start ?u) (stop ?v))
(drum ?u ?v ?cost)
=> (printout t "Costul minim este " ?cost crlf)
(halt))
(defrule conex
(drum ?u ?v ?cost)
(cost_infinit ?inf)
(test (eq ?cost ?inf))
=> (assert (ok ?inf)))

(defrule netareconex
(cost_infinit ?inf)
(ok ?val)
(test (eq ?val ?inf))
=> (assert (ok2 ?inf ))
(printout t "GRAFUL NU este tare conex!!!" crlf) )

(defrule tareconex
(ok ?val)
(test ( < ?val 1))
=> (printout t "cred ca e tare conex" crlf) )

Socketi "raw"

Socketii "raw", din familia de protocoale PF_PACKET sunt folositi pentru a receptiona sau trimite pachete "raw" direct la nivelul dispozitivului fizic (nivelul OSI 2). Sunt folositi pentru a implementa protocoale direct in user-space fie pentru a le testa fie pentru ca protocolul nu are rost sa fie implementat in kernel. Aceasta familie de protocoale pune la dispozitie doua tipuri de socketi:

  • SOCK_RAW - pachetele sunt prezentate utilizatorului asa cum sunt primite de la device driver (i.e. cu tot cu headerul de nivel 2); de asemenea la trimiterea unui pachet printr-un socket de acest tip pachetele sunt trimise nemodificate astfel incat trebuie sa contina si headerul
  • SOCK_DGRAM - pachetele sunt prezentate utilizatorului fara headerul de nivel 2; pachetelor trimise pritr-un socket de acest tip li se va adauga headerul de nivel 2; practic utilizatorul vede doar continul pachetului

Socketii "raw" sunt creati la fel ca si socketii normali cu apelul de sistem socket:

packet_socket = socket(PF_PACKET, int socket_type, int protocol);
unde socket_type poate fi SOCK_RAW sau SOCK_DGRAM iar protocol una din constantele definite in linux/if_ether.

Aplicatia de mai jos "asculta" toate pachetele care ajung in calculator si printeaza continutul lor, fie ca ii sunt adresate calculatorului sau nu.


#include "netinet/in.h"
#include "stdio.h"
#include "unistd.h"
#include "netpacket/packet.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "net/if.h"
#include "stdlib.h"
#include "sys/ioctl.h"
#include "string.h"
#include "net/if_arp.h"
#include "linux/if_ether.h"

int start(int proto) //eth_p_ip
{
int fd = socket(PF_PACKET, SOCK_DGRAM, htons(proto));

if (fd < 0)
{
perror("can't create protocol socket:");
return -1;
}
return fd;
}

int bind_socket(int fd, int interface, int protocol)
{
struct sockaddr_ll sock_info;

memset(&sock_info, 0, sizeof(sock_info));

sock_info.sll_family = AF_PACKET;
sock_info.sll_protocol = htons(protocol);
sock_info.sll_ifindex = interface;

if (bind(fd, (struct sockaddr *)&sock_info, sizeof(sock_info)))
{
perror("can't bind socket to i/f %m\n");
return -1;
}
return 0;
}

int find_interface(char *name)
{
struct ifreq ifr;
int iindex = 1;
int sock = socket(PF_PACKET, SOCK_RAW, 0);

ifr.ifr_ifindex = iindex;

while (ioctl(sock, SIOCGIFNAME, &ifr) == 0)
{
if (strcmp(ifr.ifr_name, name) == 0)
{
close(sock);
return iindex;
}
ifr.ifr_ifindex = ++iindex;
}
close(sock);
return -1;
}

int set_promisc(int fd, int ifn)
{
struct packet_mreq pack_info;

pack_info.mr_type = PACKET_MR_PROMISC;
pack_info.mr_alen = 0;

pack_info.mr_ifindex = ifn;

if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &pack_info, sizeof(pack_info)))
{
printf("can't set promiscous mode\n");
return -1;
}

return 0;
}

int recv_packet(int sockfd, int *ifn, unsigned char macaddr[], unsigned char *data, int maxlen)
{
struct msghdr msg;
struct iovec iov;
struct sockaddr_ll sock_info;

int len;

memset(&msg, 0, sizeof(msg));
msg.msg_name = &sock_info;
msg.msg_namelen = sizeof(sock_info);
msg.msg_iovlen = 1;
msg.msg_iov = &iov;

iov.iov_len = maxlen;

iov.iov_base = data;

len = recvmsg(sockfd, &msg, 0);

*ifn = sock_info.sll_ifindex;
memcpy(macaddr, sock_info.sll_addr, 6);

return len;
}


int main()
{
int sockfd = start(ETH_P_IP);
int interface = find_interface("eth0");
int b = bind_socket(sockfd, interface, ETH_P_IP);
unsigned char *macaddr=(unsigned char *)malloc(256*sizeof(unsigned char)), *data= (unsigned char *)malloc(256*sizeof(unsigned char));
while (1) {
int promise = set_promisc(sockfd, interface);
int recv = recv_packet(sockfd, &interface, macaddr, data, 256), i;
for(i=0; i < 256;i++)
printf("%c",data[i]);
printf("\n");
}
return 0;

}

Nota
Fisierul va fi executat din pozitie de admin (in Linux: sudo su)

16 aprilie 2010

Hash tables

Urmatorul program creeaza o structura de date Hash - o structura care asociaza unei anumite chei (indicele vectorului Hash[]) o lista de vectori de elemente (ale unei multimi), avand cardinalul card. Lista este simplu-inlantuita.
Se mai verifica si daca o anumita multime A poate fi acoperita de multimi de un anumit cardinal din Hash table.

#include "stdio.h"
#include "stdlib.h"

typedef struct lista {
int * elem;
int card;
struct lista *leg;
} * Hash;

void insert (int * multime,int card, Hash * L) {
Hash ins = (Hash)malloc(sizeof(struct lista));
ins->elem = multime;
ins->leg = NULL;
ins->card = card;
if (*L == NULL) {
*L = ins; return ; }
else {
Hash aux = *L;
while (aux->leg !=NULL)
aux= aux->leg;

aux->leg = ins; }
}

void printvect (int * v,int n) {

int i;
for(i=0;i < n;i++)
printf( "%d ", v[i]);
printf("\n");
}


void afisare (Hash h, int i) {

Hash aux;
if (h != NULL) {
aux = h;
printf("h[%d] = \n",i);
while (aux != NULL)
{
printvect(aux->elem,aux->card);
aux = aux->leg;
}
}
}

int exista (Hash h, int elem) {

if(h==NULL)
return 0;
Hash aux = h;
int ok =0;
while (aux) {
int c = aux->card, i;
for(i=0; i < c ; i++)
if (aux->elem[i]==elem) ok = 1;
if(ok ==1)
return 1;
aux = aux->leg;
}
return 0;

}

int main() {

Hash *h;
FILE * f = fopen("in", "r");
int n,i;
fscanf(f, "%d", &n);
h = (Hash *)malloc (n*sizeof(struct lista));
for(i=0; i < n ; i++)
h[i]= NULL;
while(!feof(f)) {
int m;
fscanf(f, "%d", &m);
int * v = (int *)malloc(m*sizeof(int));
for(i=0; i < m ;i++)
fscanf(f,"%d", &v[i]);
insert (v,m, &h[m]);
}
for(i=0; i < n ; i++)
afisare(h[i],i);

// multimea A de cardinal k poate fi acoperita de multimi de card. p din Hash table?
printf("\n\n");

FILE * ff = fopen ("in2", "r");
int *A, k,p;
fscanf(ff,"%d", &k);
A = (int *)malloc(k*sizeof(int));
for(i=0; i < k ;i++)
fscanf(ff,"%d", &A[i]);
fscanf(ff,"%d", &p);
int ok = 1;
for(i=0; i < k && ok; i++)
if(!exista(h[p], A[i]))
ok = 0;
if (ok==1) {
printf("da\n");
afisare(h[p],p);
}
else printf("nu\n");

return 0;
}

Functii in Haskell

allEqual a b c =
if a == b && a == c && b == c then True
else False

allDifferent a b c =
if a /= b && a /= c && b /= c then True
else False

howManyEqual a b c
| allEqual a b c = 3
| allDifferent a b c = 0
| otherwise = 2

-- calculeaza sirul fibonacci
fibonacci n
| n == 0 = 1
| n == 1 = 1
| otherwise = fibonacci(n -1) + fibonacci(n - 2)

-- creeaza o pereche ordonata
orderTuple a b
| a > b =(b, a)
| otherwise = (a, b)

-- daca un element apartine listei
member x [] = False
member x (h:t) =
if (h == x) then True
else member x t

-- produs cartezian a doua liste
cartProd a b = [(x,y) | x<-a, y<-b]

-- applies f to every element of list l and returns the new list
functie x = x+2
mapp f [a] = [f a]
mapp f (a:l) =
(f a):(mapp f l)

-- returns a list containing only the elements from list l, satisfying the predicate p
predicat x = x > 2
filterr p (a:l) =
if (p a) then a:(filter p l)
else filter p l

{- reduces a list to a value, going from left to right: applies f to the seed and the first list element,
then applies f to the result and the second element etc -}
f x y= x+y
foldleft f seed [] = seed
foldleft f seed l =
seed + foldleft f (head l) (tail l)

{- computes the sum of list elements, using foldleft -}
sumList l = foldleft f 0 l

{- reduces a list to a value, going from right to left: first computation is (f last_element seed) -}
foldright f elem [] = elem
foldright f seed l =
foldright f (head l) (tail l) + seed

{- returns the number of occurences of val in a, b, c -}
valOccurs val a b c
| a==val = 1+(valOccurs val (1-a) b c)
| b==val = 1+(valOccurs val a (1-b) c)
| c==val = 1+(valOccurs val a b (1-c))
| otherwise = 0

{- returns an ordered triple based on a, b, c -}
orderTriple a b c =
if (a<=b && b<=c) then (a,b,c)
else if (b<=a && a<=c) then (b,a,c)
else if (a<=c && c<=b) then (a,c,b)
else if(b<=c && c<=a) then (b,c,a)
else if (c<=a && a<=b) then (c,a,b)
else (c,b,a)

{- returns the minimum in a list -}
minim a b =
if (a < b) then a
else b
minVal (a:[]) = a
minVal (a:l) =
minim a (minVal l)

{- returns True if all list elements are equal -}
allEq [a] = True
allEq (a:l) =
if (a/= (head l)) then False
else allEq l

{- returns True if list is sorted ascending -}
ascOrd [a] = True
ascOrd (a:l) =
if (a > (head l)) then False
else ascOrd l

{- returns True if list p is a prefix of list l -}
startsWith [] lista = True
startsWith lista [] = False
startsWith p l =
if ((head p) /= (head l)) then False
else startsWith (tail p) (tail l)

{- removes the prefix p from list l -}
del p l =
if (p==[] && l /= []) then l
else del (tail p) (tail l)

{- substitutes all occurences of element old with element new in the list l -}
subst old new [] = []
subst old new (a:l) =
if (a == old) then new:(subst old new l)
else a:(subst old new l)

14 aprilie 2010

Tipuri de date in Haskell

-- tipul nr naturale

data Natural =
Zero |
Succ Natural
deriving Show

--fct pt predecesor
prede (Succ n) = n

-- egalitate
equal Zero Zero = True
equal (Succ n) Zero = False
equal Zero (Succ n) = False
equal m n =
if equal (prede m) (prede n)== True then True
else False

-- aduna 2 nr naturale
add n Zero = n
add m n =
Succ (add m (prede n))

-- diferenta a doua nr
subs n Zero = n
subs m n =
if (equal m n) then Zero
else prede (subs m ( prede n))

-- a mai mare ca b
gt (Succ n) Zero = True
gt Zero (Succ n) = False
gt m n =
if equal m n then False
else gt m n

-- a mai mic ca b
lt (Succ n) Zero = False
lt Zero (Succ n) = True
lt m n =
if equal m n then False
else lt m n

-- inmultire
mult n Zero = Zero
mult Zero n = Zero
mult (Succ n) (Succ Zero) = (Succ n)
mult (Succ Zero) (Succ n) = (Succ n)
mult m n =
add (mult (prede m) n) n


-- tipul List

data List a =
Empty |
Cons a (List a)
deriving Show

-- lungimea unei liste
lung Empty = 0
lung (Cons x lista) = 1 + lung lista

-- concatenare
conc Empty l = l
conc (Cons x lista) l =
Cons x (conc lista l)


-- tipul Tree, arbore binar de cautare

data Tree a =
Null |
Frunza a |
Nod (Tree a) a (Tree a)
deriving Show

-- inserare intr-un arbore binar
insert t Null = Frunza t
insert t (Frunza a) =
if (t < a) then Nod (Frunza t) a Null
else Nod Null a (Frunza t)
insert x (Nod left t right) =
if (x < t) then Nod (insert x left) t right
else Nod left t (insert x right)

-- construieste un arbore binar de cautare pornind de la o lista
constr Empty = Null
constr (Cons a lista) =
insert a (constr lista)

-- numara elem din arbore
numar Null = 0
numar (Frunza a) = 1
numar (Nod left x right) = 1 + numar left + numar right

-- adancimea arborelui
maxim a b =
if (a < b) then b
else a

adan Null = 0
adan (Frunza x) = 1
adan (Nod left x right) = 1 + maxim (adan left) (adan right)

-- o lista cu elem din arborele parcurs inordine - SRD (lista sortata)
srd (Frunza a) = Cons a Empty
srd Null = Empty
srd (Nod left a right) =
conc (srd left) (Cons a (srd right))

DFS si sortare topologica

Parcurgerea in adancime (Depth-First Search - DFS) porneste de la un nod dat (nod de start), care este marcat ca fiind in curs de procesare. Se alege primul vecin nevizitat al acestui nod, se marcheaza si acesta ca fiind in curs de procesare, apoi si pentru acest vecin se cauta primul vecin nevizitat, si asa mai departe. In momentul in care nodul curent nu mai are vecini nevizitati, se marcheaza ca fiind deja procesat si se revine la nodul anterior. Pentru acest nod se cauta primul vecin nevizitat. Algoritmul se repeta pana cand toate nodurile grafului au fost procesate. In urma aplicarii algoritmului DFS asupra fiecarei componente conexe a grafului, se obtine pentru fiecare dintre acestea cate un arbore de acoperire (prin eliminarea muchiilor pe care nu le folosim la parcurgere). Pentru a putea reconstitui acest arbore, pastram pentru fiecare nod dat identitatea parintelui sau.
Pentru fiecare nod se vor retine: timpul descoperirii, timpul finalizarii, parintele si culoarea.
Algoritmul de explorare DFS nu este nici complet (cautare pe un subarbore infinit) nici optimal (nu gaseste nodul cu adancimea minima).

Dandu-se un graf orientat aciclic, sortarea topologica realizeaza o aranjare liniara nodurilor in functie de muchiile dintre ele. Orientarea muchiilor corespunde unei relatii de ordine de la nodul sursa catre cel destinatie. Astfel, daca (u,v) este una dintre muchiile grafului, u trebuie sa apara inaintea lui v in insiruire. Daca graful ar fi ciclic, nu ar putea exista o astfel de insiruire (nu se poate stabili o ordine intre nodurile care alcatuiesc un ciclu).
Sunt doi algoritmi cunoscuti pentru sortarea topologica: algoritmul bazat pe DFS (parcurgere DFS pentru determinarea timpilor si sortare descrescatoare in functie de timpul de finalizare) un alt algoritm este cel descris de Kahn.

Programul de mai jos realizeaza o parcurgere DFS si o sortare topologica bazata pe aceasta a unui graf citit dintr-un fisier (dat ca liste de adiacenta).


#include "stdio.h"
#include "stdlib.h"
#include "assert.h"

struct Nod
{
int val;
int nrVecini;
int * vecini;
int culoare;
int parinte;
int tDescoperire;
int tFinal;
};

int n;
struct Nod * graf;

/* citeste lista de adiacenta din fisier */
void readData()
{
FILE * f;
int i, j;

f = fopen( "in2.txt","r" );
assert( f );

fscanf( f, "%d", &n );
graf = ( struct Nod * ) malloc ( n * sizeof( struct Nod ) );

for ( i = 0; i < n; ++i ) {
graf[i].val = i;
fscanf( f, "%d", &graf[i].nrVecini );
graf[i].vecini = ( int * ) malloc ( graf[i].nrVecini * sizeof ( int ) );
for ( j = 0; j < graf[i].nrVecini; ++j )
fscanf( f, "%d", &graf[i].vecini[j] );
graf[i].parinte = -1;
graf[i].culoare = 0;
graf[i].tDescoperire = -1;
graf[i].tFinal = -1;
}
fclose( f );
}

/* afisarea timpilor din alg DFS*/
void printTimpi()
{
int i;
printf( "\n" );
for ( i = 0; i < n; ++i )
printf ( "Nod %d: descoperit la t=%d, explorat la t=%d \n", i, graf[i].tDescoperire, graf[i].tFinal );
printf( "\n" );
}

int timp = 0;

/* parcurgere DFS a grafului */
void explorare(int u) {

graf[u].tDescoperire = timp++;
graf[u].culoare = 1;
int j;
for(j = 0 ; j < graf[u].nrVecini ; j++) {
int x = graf[u].vecini[j];
if(graf[x].culoare ==0) {
graf[x].parinte = u;
explorare(x);
}
}
graf[u].culoare = 2;
graf[u].tFinal = timp++;

}

void DFS ()
{
int i;
for (i=0; i < n ; i++)
if(graf[i].culoare == 0)
explorare(i);
}



/* sortare topologica */
void topSort()
{
int ok = 0,i,j;
struct Nod aux;
while (ok == 0) {
ok = 1;
for(i=0; i < n-1;i++)
if(graf[i].tFinal < graf[i+1].tFinal) {
ok = 0; aux = graf[i]; graf[i]=graf[i+1]; graf[i+1]=aux; }
}
}

int main(void){
int i;

//incarca graful din fisier
readData();

//parcurgere BFS
DFS();

//afisarea timpilor
printTimpi();

//sortare topologica
topSort();
printf( "Sortare topologoca: " );
for ( i = 0; i < n; ++i )
printf ( "%d ", graf[i].val );
printf("\n");

for( i = 0; i < graf[i].nrVecini; ++i )
free(graf[i].vecini);
free(graf);
return 0;
}

BFS intr-un graf

Parcurgerea in latime (Breadth-first Search - BFS) este un algoritm de cautare in graf, in care, atunci cand se ajunge intr-un nod oarecare, v, nevizitat, se viziteaza toate nodurile nevizitate adiacente lui v, apoi toate varfurile nevizitate adiacente varfurilor adiacente lui v, etc.
BFS depinde de nodul de start. Plecand dintr-un nod se va parcurge doar componenta conexa din care acesta face parte. Pentru grafuri cu mai multe componente conexe se vor obtine mai multi arbori de acoperire.
In urma aplicarii algoritmului BFS asupra fiecarei componente conexe a grafului, se obtine un arbore de acoperire (prin eliminarea muchiilor pe care nu le folosim la parcurgere). Pentru a putea reconstitui acest arbore, se pastreaza pentru fiecare nod dat identitatea parintelui sau. In cazul in care nu exista o functie de cost asociata muchiilor, BFS va determina si drumurile minime de la radacina la oricare
nod.
Pentru implementarea BFS se foloseste o coada. In momentul adaugarii in coada, un nod trebuie colorat gri (a fost descoperit si urmeaza sa fie prelucrat).
Algoritmul de explorare BFS este complet si optimal.

#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "queue.h"

#define START 0
#define FINISH 2
#define INF 10000

struct Nod
{
int nrVecini;
int * vecini;
int culoare;
int parinte;
};

int n;
struct Nod * graf;

/* citeste lista de adiacenta din fisier */
void readData()
{
FILE * f;
int i, j;

f = fopen( "in1.txt","r" );
assert( f );

fscanf( f, "%d", &n );
graf = ( struct Nod * ) malloc ( n * sizeof( struct Nod ) );

for ( i = 0; i < n; ++i ) {
fscanf( f, "%d", &graf[i].nrVecini );
graf[i].vecini = ( int * ) malloc ( graf[i].nrVecini * sizeof ( int ) );
for ( j = 0; j < graf[i].nrVecini; ++j )
fscanf( f, "%d", &graf[i].vecini[j] );
graf[i].parinte = -1;
graf[i].culoare = 0;
}
fclose( f );
}

void printRoad()
{
int aux = FINISH;
printf( "Drumul de la finish la start: " );
while ( aux != START ) {
printf ( "%d ", aux );
if ( graf[aux].parinte>=0 ) {
aux = graf[aux].parinte;
} else {
printf("\nEroare. nu se cunoaste parintele nodului %d\n", aux );
return;
}
}
printf ( "%d\n", aux );
}

/* parcurgere BFS a grafului, plecand din nodul start */
void BFS ( int start )
{
int *dist =(int *)malloc(n*sizeof(int));
int i;
for (i=0; i < n; i++)
dist[i] = INF;
dist[start] = 0;
graf[start].culoare = 1;// gri
Queue Q = NULL;
int j;
enqueue (&Q, &start);
while (size(Q) > 0) {
i = *(int *)Front(Q);
for(j=0; j < graf[i].nrVecini; j++) {
int *x = (int *)malloc(sizeof(int));
*x = graf[i].vecini[j];
if(graf[*x].culoare == 0) { //alb
dist[*x]=dist[i]+1;
graf[*x].parinte = i;
graf[*x].culoare = 1; // gri
enqueue(&Q, x);
free (x);
}
}
graf[i].culoare = 2; //negru
dequeue (&Q);

}
printf("start %d finish %d \n", START, FINISH);
printf("distanta este %d\n", dist[FINISH]);
}

int main(void){
int i;

//incarca graful din fisier
readData();

//parcurgere BFS
BFS( START );

//afisarea nodurilor dintre finish si start
printRoad();

for( i = 0; i < graf[i].nrVecini; ++i )
free(graf[i].vecini);
free(graf);
return 0;
}

Algoritmi de dirijare

Problema dirijarii apare la nivelul retea, si consta in a determina calea pe care o vor parcurge pachetele de la calculatorul sursa la calculatorul destinatie. Software-ul nivelului retea trebuie sa asigure desfasurarea a doua procese distincte:

  • retransmitere (forwarding): ceea ce se intampla cand un pachet ajunge la ruter, si acesta trebuie sa stabileasca, prin consultarea unei tabele de rutare, linia de iesire pe care va transmite pachetul mai departe
  • dirijare (routing): este procesul de construire si actualizare a tabelei de rutare - adica de stabilire a cailor pe care vor fi transmise pachetele

Referitor la algoritmii ce tin de procesul de dirijare, putem distinge doua categorii de algoritmi: algoritmi neadaptivi (ce realizeaza o dirijare statica - toate rutele sunt determinate initial si nu se tine cont de modificarile ulterioare de trafic si topologie ce apar in retea) si algorimi adaptivi (rutele sunt modificate ca urmare a schimbarilor de topologie si de trafic din retea).

Dintre algoritmii neadaptivi fac parte:

  • dirijarea pe calea cea mai scurta (shortest path routing): subreteaua este reprezentata ca un graf, in care ruterele sunt noduri, si se aplica un algoritm (de exemplu Dijkstra) pentru a determina caile cele mai scurte dintre noduri; se pot folosi diverse metrici, cum ar fi numarul de rute intermediare, distanta geografica, intarzierile medii de transmisie
  • inundarea (flooding): ruterul trimite fiecare pachet receptionat pe toate liniile de iesire, in afara de cea pe care a venit pachetul; varianta: inundarea selectiva (selective flooding)

Algoritmii adaptivi cel mai des utilizati sunt:

  • dirijarea cu vectori distanta (distance vector routing): fiecare ruter mentine o tabela cu calea cea mai buna pentru fiecare destinatie si linia de iesire corespunzatoare acestei cai; tabelele sunt actualizate pe baza informatiilor primite de la celelalte rutere
  • dirijarea folosind starea legaturilor (link state routing): fiecare router determina costurile asociate cailor catre vecini, apoi trimite aceste informatii in toata subreteaua; dupa schimburile de informatii, fiecare ruter are informatii complete despre graf si poate determina caile minime

Exemple de protocoale de dirijare:

  • RIP (Routing Internet Protocol) - utilizeaza algoritmul distance vector
  • OSPF (Open Shortest Path First Protocol) - utilizeaza algoritmul link state
  • BGP (Border Gateway Protocol)

Programul de mai jos citeste dintr-un fisier un numar n reprezentand dimensiunea unei matrici de adiacenta a unui graf cu nodurile retelei, precum si aceasta matrice. Initial creeaza o tabela de rutare pentru fiecare nod, care contine informatii despre toate nodurile retelei, sub forma : Destinatar , Cost (=valoarea asociata muchiei dintre acel nod si destinatar), Next_Hop (=nodul urmator de urmat pentru a ajunge la destinatar). Apoi, pentru fiecare nod se vor actualiza informatiile despre celelalte noduri combinand informatiile gasite in fiecare tabela de rutare cercetata.


#include "stdio.h"
#include "stdlib.h"
#define INF 1000

int **a, n;

typedef struct tabela {

int *dest;
int *cost;
int *next_hop;

} Tabela;

void printTabela(Tabela t) {

int i;
for(i=0; i < n; i++)
printf("%d\t%d\t%d \n", t.dest[i], t.cost[i], t.next_hop[i] );
}

int find_dest(Tabela t, int poz) { // prima dest incepand cu poz

int i=poz;
while(t.cost[i] == INF && i<=n-1)
i++;
if (i<=n-1)
return t.dest[i];
return -1; // nu a gasit
}

int main () {

FILE * f = fopen ("in", "r");
fscanf(f, "%d",&n);
int i,j,k;
a = (int **)malloc(n*sizeof(int));

for(i=0; i < n ; i++)
a[i] = (int *)malloc(n*sizeof(int));
for(i=0; i < n ; i++)
for(j=0; j < n ; j++)
fscanf(f, "%d", &a[i][j]);

Tabela * tab = (struct tabela *)malloc(sizeof(struct tabela)*n);
for(i=0; i < n ; i++) {
tab[i].dest = (int *)malloc(n*sizeof(int));
tab[i].cost = (int *)malloc(n*sizeof(int));
tab[i].next_hop = (int *)malloc(n*sizeof(int));
}

// constructia tabelei in forma initiala
for (i=0; i < n ; i++) { // pt fiecare tabela
for(j=0; j < n ; j++)
if (a[i][j]) {
tab[i].dest[j] = j;
if(i!=j)
tab[i].cost[j] = 1;
else
tab[i].cost[j] = 0;
tab[i].next_hop[j] = j;
}
else {
tab[i].dest[j] = j;
tab[i].cost[j] = INF;
tab[i].next_hop[j] = -1;
}
}

printf("Tabela 5 inainte de aplicarea algoritmului:\n");
printTabela(tab[5]); // printam un anumit nod


for(i=0; i < n ; i++) // pt fiecare tabela

for(j=0; j < n ; j++) { // pt fiecare destinatie din tabela
k = find_dest(tab[j],0);
while(k!=-1) {
if (tab[i].cost[k] > tab[j].cost[k] + tab[i].cost[j]) {
tab[i].cost[k] = tab[j].cost[k] + tab[i].cost[j];
tab[i].next_hop[k] = tab[j].dest[j];
}
k = find_dest(tab[j],k+1);
}
}

printf("Tabela finala 5 cu drumuri optime:\n");
printTabela(tab[5]);

return 0;

}

08 aprilie 2010

Purificarea retelelor Petri

In procesul de modelare a protocoalelor folosind RP, pot aparea retele impure. De exemplu, o tranzitie impura t are un loc de intrare l, care este simultan nod de iesire. Pentru o RP pura niciun loc nu este intrare si iesire a aceleiasi tranzitii. Se demonstreaza ca orice RP impura poate fi transformata intr-o RP pura prin reducere. Reducerea ei se face astfel:

- se suprima arcele (l, t) si (t, l)

- se suprima t daca ea devine izolata

Urmatorul program indeplineste urmatoarele functii:

  • isi creeaza un exemplu de retea Petri folosind locuri si tranzitii
  • verifica daca reteaua contine impuritati;
  • aplica reducerea specificata asupra fiecarei tranzitii impure;
  • in final printeaza reteaua purificata

#################################

#include"stdio.h"

typedef struct {
int pre[100];
int post[100];
int Npre,Npost;
} tran;

int main() {
tran t[6];

t[1].Npre=2;
t[1].Npost=2;
t[1].post[0]=1;
t[1].post[1]=2;
t[1].pre[0]=1;
t[1].pre[1]=2;

t[2].Npre=3;
t[2].Npost=1;
t[2].post[0]=3;
t[2].pre[2]=3;
t[2].pre[0]=1;
t[2].pre[1]=2;


t[3].Npre=1;
t[3].Npost=1;
t[3].post[0]=1;
t[3].pre[0]=3;

t[4].Npre=1;
t[4].Npost=1;
t[4].post[0]=2;
t[4].pre[0]=3;

t[5].Npre=1;
t[5].Npost=1;
t[5].post[0]=3;
t[5].pre[0]=3;

int n=5,ok=1,i,k,l;

do {
ok=1;
for(i=1;i<=n;i++)
for(k=0;k<=t[i].Npre-1 ; k++)
for(l=0; l<=t[i].Npost-1; l++)
if((t[i].pre[k]==t[i].post[l]) && (t[i].pre[k]!=0)) // daca a gasit tranzitie impura
{
ok=0;
t[i].pre[k]=t[i].post[l]=0; // purifica
break;
}
} while(ok==0);

for(i=1;i<=n;i++) {
printf("\nT%d:\nPre:",i);
for(k=0;k<=t[i].Npre-1;k++)
printf("%d ",t[i].pre[k]);
printf("\nPost:");
for(k=0; k<=t[i].Npost-1 ; k++)
printf("%d ",t[i].post[k]);
}

return 0;
}

03 aprilie 2010

Calcul de polinoame folosind cozi

#include "stdio.h"
#include "queue.h"
#include "stdlib.h"

typedef struct nod_pol{
double coef;
int exp;
} p_nod;

int main(){

Queue Q = NULL, P = NULL;
p_nod p[] = { {2,3},{23,2},{2,0},{34,3},{5,1},{3,2},{8,0}};
enqueue(&Q, &p[0]);
enqueue(&Q, &p[1]);
enqueue(&Q, &p[2]);
enqueue(&P, &p[3]);
enqueue(&P, &p[5]);
enqueue(&P, &p[4]);
enqueue(&P, &p[6]);
int i,j,k,m;

Queue aux1=Q , aux2 = P , suma = NULL, produs = NULL;
k = size(Q);
m = size(P);
int exp;

// adunarea a doua polinoame
p_nod y = *(p_nod*)dequeue(&aux1);
p_nod z = *(p_nod*)dequeue(&aux2);
if (y.exp>z.exp) exp = y.exp;
else exp = z.exp;
int exp2 = y.exp + z.exp;
for (j=exp;j>=0;j--){
aux1 = Q; aux2 = P;
p_nod *t = (p_nod*)malloc(sizeof(p_nod));
t->exp = j;
t->coef = 0;
for (i=0;i<=k-1;i++){
p_nod y = *(p_nod*)dequeue(&aux1);
if (y.exp==j) t->coef+=y.coef;
}
for (i=0;i<=m-1;i++){
p_nod z = *(p_nod*)dequeue(&aux2);
if (z.exp==j) t->coef+=z.coef;
}
enqueue(&suma,t);
}
k = size(suma);
for (i=0;i<=k-1;i++){
z = *(p_nod*)dequeue(&suma);
printf("%.2lf %d\n",z.coef,z.exp);
}
printf("\n");

// inmultirea a doua polinoame
for (j=exp2; j>=0; j--){
p_nod *t = (p_nod*)malloc(sizeof(p_nod));
t->exp = j;
t->coef = 0;
aux1 = Q;
while (aux1!=NULL){
aux2 = P;
p_nod y = *(p_nod*)dequeue(&aux1);
while (aux2!=NULL){
p_nod z = *(p_nod*)dequeue(&aux2);
if (y.exp + z.exp == j)
t->coef+=y.coef*z.coef;
}
}
enqueue(&produs,t);
}
k = size(produs);
for (i=0;i<=k-1;i++){
z = *(p_nod*)dequeue(&produs);
printf("%.2lf %d\n",z.coef,z.exp);
}
return 0;
}

Sortare radix folosind cozi

Se foloseste urmatoarea interfata pentru tipul de date Coada:

queue.h

#ifndef _QUEUE_H
#define _QUEUE_H

typedef struct nod{
void* data;
struct nod* next;
}q_nod;
typedef q_nod* Queue;
/* adaugare in coada */
int enqueue(Queue*, void*);
/* extragere din coada */
void* dequeue(Queue*);
/* inspectarea primului element */
void* Front(Queue);
/* test coada vida */
int isEmpty(Queue);
/* dimensiunea cozii */
int size(Queue);
#endif


queue.c

#include "stdlib.h"
#include "queue.h"

int enqueue (Queue *Q,void *x){

Queue aux,pus;
aux = *Q;
if (aux!=NULL){
while (aux->next!=NULL)
aux = aux->next;
pus = (Queue)malloc(sizeof(q_nod));
pus->data = x;
aux->next = pus;
pus->next = NULL;
return 0; }
else {
aux = (Queue)malloc(sizeof(q_nod));
aux->data = x;
aux->next = NULL;
*Q = aux;
return 0;
}
}

void* dequeue (Queue *Q){
Queue aux;
aux = *Q;
if(*Q==NULL) return NULL;
void* x = (*Q)->data;
*Q = (*Q)->next;
free(aux);
return x;
}

void* Front (Queue Q){
if (Q==NULL)
return NULL;
else
return Q->data;
}

int isEmpty (Queue Q){
return Q==NULL;
}

int size (Queue Q){
int k = 0;
Queue aux = (Queue)malloc(sizeof(q_nod));
aux = Q;
while (aux!=NULL){
k++;
aux = aux->next;
}
return k;
}
Sortarea este urmatoarea:

#include "queue.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"

int rangmax (int n, int *X){

int xm = X[0];
int k, r;
for (k=0; k
if(X[k] > xm)
xm = X[k];
r = 0;
while (xm > 0){
r++;
xm/=10;
}
return r;
}

void Distribuie (int n, int* X, Queue* QC, int r){

int nc=0, ind, i, j, *pi;
for(i=0 ; i<=n-1 ; i++){
int t=X[i];
for(j=0; j <=r-1; j++)
t /= 10;
ind = t % 10;
if(isEmpty(QC[ind]))
nc++;
pi = (int*)malloc(sizeof(int));
*pi = X[i];
enqueue(&QC[ind], pi);
}
}


void Colecteaza (Queue* QC, int* X){

int j, i=0, *pi;
for (j=0; j<=9; j++)
while(!isEmpty(QC[j])){
pi = dequeue(&QC[j]);
X[i] = *pi;
i++;
free(pi);
}
}


void RadixSort (int n, int* X){

int rmx, i, r;
Queue QC[10];
for(i=0; i<=9 ; i++)
QC[i]= NULL;
rmx = rangmax(n, X);
for (r=0; r<=rmx; r++){
Distribuie(n, X, QC, r);
Colecteaza(QC, X);
}
}

int main(){

int n, i;
int *x;
scanf("%d", &n);
x = (int*)malloc(n*sizeof(int));
for(i=0; i<=n-1; i++)
scanf("%d", &x[i]);
RadixSort(n, x);
for(i=0; i<=n-1 ; i++)
printf("%5d ", x[i]);
printf("\n");
free(x);
return 0;
}