25 martie 2010

Probleme in Scheme

; verificare daca o lista e palindroma

(define (palindrome? lista)
(let secv ((l1 lista) (l2 (reverse lista)))
(cond
((null? l1)
#t) ; s-a ajuns la sfarsitul listelor fara probleme => palindrom
((= (car l1) (car l2)) ; daca sunt egale se apeleaza secventa pt restul listelor
(secv (cdr l1) (cdr l2)))
(#t ; nu s-a apelat secventa din nou => inegalitate si lista nu e palindroma
#f)))
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; toate elementele dintr-o lista de liste etc, adunate intr-o sg lista

(define flatten
(lambda (lista)
(cond ((null? lista) '())
((pair? (car lista)) ; daca car este o lista
(append (flatten (car lista)) ; apeleaza fct flatten pt car si pt cdr , si apoi le impreuneaza
(flatten (cdr lista))))
(else ; daca car este un sg element
(cons (car lista) ; il insereaza
(flatten (cdr lista))))))) ; la lista rezultata in urma aplicarii flatten asupra restului de lista curenta

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; multimea tuturor submultimilor ale unei multimi

(define (power-set lista)
(if (null? lista) '(())
(let ((rest (power-set (cdr lista)))) ; salveaza fct aplicata pe restul de lista
(append rest ; pe care il adauga
(map (lambda (sublista) ; la ceea ce rezulta prin aplicarea cons inceputului de lista dintr-o sublista si acelui rest
(cons (car lista) sublista))
rest))
)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; produsul cartezian a 2 liste

(define make ; produs cartezian de un singur element cu o lista
(lambda(x lista)
(if (null? lista) '()
(cons (append (list x) (list(car lista))) (make x (cdr lista)) )
)))

(define cart-2
(lambda(list1 list2)
(if (or (null? list2)(null? list1)) '()
(append (make(car list1) list2) ; aplica fct make pentru fiecare prim elem din prima lista, cu lista a doua
(cart-2 (cdr list1) list2)) ; se aplica acelasi procedeu pt ceea ce ramane din prima lista cu lista a doua
)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; produsul cartezian a n liste

(define (cart-22 l1 l2) ; var mai buna de a calcula cart-2
(foldl
(lambda (x res)
(append
(foldl
(lambda (y acc) (cons (cons x y) acc))
'() l2) res))
'() l1))

(define (cp lofl) ; cart-n insa cu puncte
( if(null? lofl) '()
( foldl cart-22 (first lofl) (rest lofl))))

(define conv-dot ; converteste o lista cu puncte intr-una fara
(lambda (lista)
( if (null? lista) '()
( if (pair? lista)
(append (list(car lista)) (conv-dot (cdr lista) ) ) (cons lista '())
))))

(define cart-n
(lambda (lista)
(map conv-dot (cp lista))) ; aplica fct de conversie pt toate listele rezultate cu pct
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; calcularea nr e

(define inv_fact ; calculeaza 1/nr!
(lambda (nr)
(let loop ((n nr) (index 1))
(if (= n 1)
(if (= index 1)
index
(- index 1))
(loop (/ n index) (+ index 1))))))

(define succ ; succesorul lui n
(lambda (n)
(* n (/ 1 (+ (inv_fact (/ 1 n)) 1)))))

(define make_prog
(lambda (k)
(cons k (lambda ()
(make_prog (succ k))))))

(define prog_stream
(make_prog 1)) ; 1/1! + ....

(define take
(lambda (nr stream)
(let loop((n nr) (st stream) (aux 1))
(if (= n 0)
aux
(loop (- n 1) ((cdr st)) (+ aux (car st)))))))

; verificare:
;(log (take 30 prog_stream))

Problema reginelor

Pe o tablă NxN trebuie așezate N regine astfel încât să nu existe conflicte între oricare 2 piese (o regină poate elimina altă regină dacă segmentul determinat de cele două piese este paralel cu oricare din axele sau diagonalele tablei de joc).

In program, *s este vectorul care retine pe ce linie se afla fiecare regina pusa pe o singura coloana. Ex. s[1]=3 inseamna `regina de pe coloana 1 se afla pe linia 3`.

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

int n , *s;
int vf;

void avans () {

vf++;
s[vf]=-1;

}

int succesor () {

s[vf]++;
return s[vf] < n;

}

int valid () {

int ok = 1;
int i;
for (i=0; i < vf; i++)
if(s[i]==s[vf] || abs(s[vf]-s[i])==vf-i)
ok=0;
return ok;
}

int sol () {

return vf==n-1;
}

void tipar () {

int i,j;
printf("solutie\n");
for(i=0; i < n; i++) {
for(j=0; j < n; j++) {
if(s[i]==j) printf("Q");
else printf("#"); }
printf("\n"); }
printf("\n");
}

void back() {

vf = -1;
avans ();
while(vf > -1) {
if(succesor()) {
if(valid()) { if(sol()) tipar();
else avans(); }
else ; }
else vf--; }
}

int main() {

printf("\n");
printf("n= ");
scanf("%d", &n);
s = (int *) malloc (n*sizeof(int));
back();
return 0;

}

23 martie 2010

Functii cu continuari in Scheme


Diverse feluri de a calcula suma elementelor unei liste

; in mod normal

(define sum_list
(lambda (l)
(letrec ((sum (lambda (l s)
(if (null? l) s
(sum (cdr l) (+ s (car l)))))))
(sum l 0))))

; cu afisare pe parcurs- propagare de la un apel la altul

(define sum_list
(lambda (l)
(letrec ((sum (lambda (l s)
(if (null? l) s
(let ((result (sum (cdr l) (+ s (car l)))))
(display result)
result))))) ; ultima expresie din secventa dicteaza valoarea la care se evalueaza let, respectiv ramura else
(sum l 0))))
(sum_list '(0 3 6))

; propagare direct catre primul apel

(define sum_list
(lambda (l)
(call/cc ; call continuation
(lambda (cont)
(letrec ((sum (lambda (l s)
(if (null? l) (cont s) ; se abandoneaza , se intoarce in call/cc si il pune pe s
; reia procesul de evaluare a apelului initial, furnizandu-i valoarea corespunzatoare
(let ((result (sum (cdr l) (+ s (car l)))))
(display result)
result)))))
(sum l 0))))))
; (sum_list '(1 2 3)) ; 6

; cu verificare ca ceea ce se aduna e numar

(define sum_list
(lambda (l)
(call/cc
(lambda (cont)
(letrec ((sum (lambda (l s)
(cond
((null? l) (cont s))
((number? (car l)) (sum (cdr l) (+ s (car l))))
(else (cont 0)))))) ; valoarea speciala 0, in caz de eroare - "aruncare de exceptii"
(sum l 0))))))
(sum_list '(1 2 3)) ; 6
(sum_list '(1 2 scheme rulz)) ; 0

; adunarea unor nr cu succ, pred, zero??
; fctii add , sub , mult , div (2 numere) folosind fct si continuari

(define succ
(lambda (x)
(+ x 1)))

(define pred
(lambda (x)
(- x 1)))

(define zero??
(lambda (x)
(if (= 0 x) #t #f)))

(define unu??
(lambda (x)
(if (= 1 x) #t #f)))

; adunare normala

(define add
(lambda (a b)
(cond
((zero?? b) a)
(else (add (succ a) (pred b))))))

; adunare cu continuari

(define add2
(lambda (a b)
(call/cc
(lambda (cont)
(letrec ((adds (lambda (a b)
(if (zero?? b) (cont a)
(let ((result (adds (succ a) (pred b) )))
(display result)
result)))))
(adds a b))))) )

; scadere normala

(define sub
(lambda(a b)
(cond
((zero?? b) a)
(else (sub (pred a) (pred b)))
)))

; scadere cu continuari

(define sub2
(lambda (a b)
(call/cc
(lambda (cont)
(letrec ((subs (lambda (a b)
(if (zero?? b) (cont a)
(let ((result (subs (pred a) (pred b))))
(display result)
result)))))
(subs a b))))))

; inmultire nr naturale

(define mult ; c contor =de la 1 ..... b se aduna a, acum = acumulator
(lambda (a b c acum)
(call/cc
(lambda (cont)
(letrec ((mul (lambda (a b c acum)
(if (= c b) (cont acum)
(let ((acum (add2 acum a)) (c (succ c)))
(mul a b c acum))))))
(mul a b c acum)
)))))

;(mult 3 8 0 0)

; impartire exacta pt nr naturale

(define div
(lambda (a b c) ; c = contor
(call/cc
(lambda (cont)
(letrec ((di (lambda (a b c)
(if (zero?? a) (cont c)
( let ((result (sub2 a b)))
(di result b (succ c)))))))
(di a b 0)
)))))

;(div 21 3 0)

22 martie 2010

Protocoale cu fereastra glisanta pentru legatura de date

In cazul acestor protocoale, la orice moment de timp, emitatorul mentine o multime de numere de secventa care corespund cadrelor pe care are permisiunea sa le trimita. Aceste cadre apartin unei ferestre de transmisie. Receptorul va mentine o fereastra de receptie (avand de asemenea o multime de numere de secventa) corespunzatoare cadrelor ce pot fi acceptate. Cele doua ferestre (ale emitatorului si receptorului) nu trebuie sa aiba aceeasi dimensiune.

Protocolul cu fereastra glisanta de un bit
utilizeaza metoda stop-and-wait, deoarece emitatorul transmite un cadru si asteapta confirmarea sa inaintea transmiterii urmatorului cadru.

Urmatoarea aplicatie emitator / receptor functioneaza conform cu descrierea protocolului cu fereastra glisanta de un bit. Cele doua aplicatii transmit date intre ele prin intermediul unor pipe-uri, contorizand numarul pachetului trimis/receptionat.
Emitatorul trimite cadre dintr-un pachet pe care le contorizeaza, trimite si contorul acestora. Receptorul stie la ce contor sa se astepte, si daca primeste un cadru nedorit, trimite la randul sau propriul contor neupdatat, astfel emitatorul mai trimite o data cadrul respectiv.
In plus, s-a folosit codificarea si decodificarea crc pentru a verifica si mai bine datele. Emitatorul calculeaza propriul tabel crc si, pentru fiecare cadru trimis, calculeaza acumulatorul, pe care il transmite. Receptorul la randul lui si-a creat tabelul crc, primeste acumulatorul dar si calculeaza un nou acumulator pe baza cadrului primit. In plus fata de conditia de concordanta a numarului cadrelor, diferenta intre acumulatoare trebuie sa fie 0.

sender.c

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "crc.h"

char *text = "smoke this in your pipe and stuff it please";


int main () {


int fd1, fd2;
fd1 = open ("pipe1", O_RDONLY );
fd2 = open ("pipe2", O_WRONLY );
int inc = 0, i=0, primit=0, j, acum=0;
word *tabel;
tabel = tabelcrc(CRCCCITT);
int ok=1;

do {
if(ok)
crctabel(text[i], &acum, tabel);
ok = 0;
write (fd2, &text[i], 1);
write (fd2, &inc, 4);
write(fd2, &acum, 2);
printf("%d\n",acum);
read (fd1, &primit, 4);
if(primit==inc)
{ inc++;
i++;
ok = 1;
}
} while(i < strlen(text)+1);

close (fd1);
close(fd2);
return 0;

}



receiver.c

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "crc.h"


int main () {

int fd1, fd2;
char buf;
int contor=-1;
int cadru;
fd1 = open ("pipe1", O_WRONLY );
fd2 = open ("pipe2", O_RDONLY );
word acum, acum_nou=0;
word * tabel = tabelcrc(CRCCCITT);
word ac;


while(1) {
read ( fd2, &buf, 1);
read ( fd2, &cadru,4);
read(fd2, &acum, 2);

crctabel(buf, &acum_nou, tabel);
ac = acum_nou;
crctabel(ac>>8, &acum, tabel);
crctabel(ac& 0x00FF, &acum, tabel);
// printf("%d\n", acum);
printf ( "%c\n", buf );
if(cadru == contor+1 && acum==0) {
contor++;
write(fd1, &contor, 4);
}
else
write (fd1, &contor, 4);
}

close (fd1);
close (fd2);
return 0;

}


La compilare se va folosi si fisierul crc.c definit aici.

15 martie 2010

Comanda semaforului de trafic

// Model numeric pentru un controlul unui semafor de trafic.
// By Dan Hyde,
module traffic;
parameter on = 1, off = 0, red_tics = 35, amber_tics = 3, green_tics = 20;
reg clock, red, amber, green;
// va opri simularea dupa 1000 unitati de timp
initial begin: stop_at
#1000; $stop;
end
// initializeaza luminile si seteaza monitorizarea registrelor.
initial begin: Init
red = off; amber = off; green = off;
$display(" Timpul green amber red");
$monitor("%3d %b %b %b", $time, green, amber, red);
$vw_dumpvars();
$vw_group("all", $time, green, amber, red);
end
// task de asteptare pentru aparitiile fronturilor pozitive ale ceasului
// inainte de a stinge (off) luminile
task light;
output color;
input [31:0] tics;
begin
repeat(tics) // asteapta detectarea fronturilor pozitive ale ceasului
@(posedge clock);
color = off;
end
endtask
// forma de unda pentru o un ceas cu o perioada de doua unitati de timp
always begin: clock_wave
#1 clock = 0;
#1 clock = 1;
end
always begin: main_process
red = on;
light(red, red_tics); // cheama task-ul de asteptare
green = on;
light(green, green_tics);
amber = on;
light(amber, amber_tics);
end
endmodule


Iesirea este urmatoare

(Time green amber red)
0 0 0 1
70 1 0 0
110 0 1 0
116 0 0 1
186 1 0 0
226 0 1 0
232 0 0 1
302 1 0 0
342 0 1 0
348 0 0 1
418 1 0 0
458 0 1 0
464 0 0 1
534 1 0 0
574 0 1 0
580 0 0 1
650 1 0 0
690 0 1 0
696 0 0 1
766 1 0 0
806 0 1 0
812 0 0 1
882 1 0 0
922 0 1 0
928 0 0 1
998 1 0 0

Detectarea si corectarea erorilor in legatura de date

Informatiile schimbate intre diferite sisteme sunt codificate, pentru a realiza adaptarea statistica a sursei la canalul de comunicatie. Canalul de comunicatie poate fi afectat sau nu de perturbatii.Un canal neperturbat ar corespunde unei criptari sau compresii a informatiei, pe cind un canal perturbat transmisiei acesteia.
Sistemele actuale care inglobeaza calculatoare si echipamente automate necesita o transmisie cit mai corecta a informatiei; pentru aceasta semnalul trimis este prelucrat inainte de a fi emis. Prelucrarea semnalului se realizeaza foarte usor in cazul transmisiei de semnale discrete, prin codificare. Receptorul va decodifica semnalul primit si va incerca sa estimeze daca au aparut erori. Pentru tratarea codificarii/decodificarii s-a dezvoltat un amplu aparat matematic, bazat pe calculul vectorial si polinomial. Astfel, in cazul codurilor bloc, folosind alfabetul binar {0,1}, se pot realiza 2^n combinatii (cuvinte de cod de aceeasi lungime n) folosind n biti.
Aceste cuvinte de cod pot fi asimilate cu vectori sau cu polinoame. Daca toate cele 2^n combinatii reprezinta cuvinte utile (cu sens), atunci aparitia unei erori transforma un cuvint de cod in altul, fara a se putea realiza detectia sau corectia erorilor. De aceea, informatia utila va fi codificata pe k
Un program de calcul al codului de control ciclic CRC-CCITT este urmatorul:


crc.h

#define CRCCCITT 0x1021 // polinomul generator

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

typedef unsigned short int word;
typedef unsigned char byte;

word calculcrc (word, word, word);
word* tabelcrc (word);


crc.c

#include "crc.h"
#include "stdio.h"
#include "string.h"
//
// calculeaza noul rest partial pe baza vechiului rest
// (acum), a unui octet de date (data) si a polinomului
// generator (genpoli)
//

word calculcrc (word data, word genpoli, word acum)
{
int i;
data <<= 8;
for (i=8; i > 0; i--)
{
if ((data^acum) & 0x8000)
acum = (acum << 1) ^ genpoli;
else
acum <<= 1;
data <<= 1;
}
return acum;
}

/*
Functia "calculcrc" determina efectul aplicarii procedeului clasic de calcul CRC asupra unui octet de date. Generatorul polinomial (genpoly) si continutul initial al acumulatorului
(accum) sint date ca argumente.

Calculul prin program al secventei de control sugereaza posibilitatea de a trata problema nu la nivelul fiecarui bit al unui mesaj, ci la nivelul octetilor. Ideea este de a gasi o modalitate mai simpla prin care, dat fiind un octet de date si continutul vechi al acumulatorului (registrul de deplasare) sa se calculeze noua valoare a acumulatorului. Facind o simulare a operatiilor, se poate constata ca octetul de date se combina doar cu bitii mai semnificativi ai acumulatorului, noua valoare a acumulatorului fiind suma (modulo 2 a) secventei de control corespunzatoare acestei valori combinate si a octetului mai putin semnificativ al acumulatorului. Deoarece valoarea combinata ocupa 8 biti, ea poate avea 256 de valori diferite, secventele de control pentru toate aceste valori putind fi calculate si pastrate intr-un tablou. In acest mod calculul noului acumulator se poate face foarte simplu, prin insumarea modulo 2 a octetului inferior al acumulatorului cu o valoare precalculata, din cea totala.

Functia tabelcrc construieste acest tablou; ea are ca parametri:
generatorul polinomial si un pointer la o functie CRC (de ex. calculcrc) si intoarce (unsigned short * ) un pointer in tabela.
*/

//
// calculeaza tabelul codurilor CRC
// alcatuieste tabelul codurilor CRC pentru un anumit
// polinom generator (poli); apeleaza "calculcrc" pentru
// toate cele 256 combinatii posibile ale octetului de date
// intoarce un pointer la tabelul de coduri, alocat dinamic
//

word* tabelcrc (word poli )
{
word* ptabelcrc;
int i;
if ((ptabelcrc = (word*) malloc (256 * sizeof (word))) == NULL)
return NULL;
for (i=0; i < 256; i++)
ptabelcrc [i] = calculcrc (i, poli, 0);
return ptabelcrc;
}

// calculeaza CRC partial (acum) corespunzator unui octet
// (data) prin utilizarea tabelului codurilor CRC (tabelcrc)

void crctabel (word data, word* acum, word* tabelcrc)
{
word valcomb;
valcomb = ((*acum >> 8) ^ data) & 0x00FF;
*acum = ((*acum & 0x00FF) << 8) ^ tabelcrc [valcomb];
}

//
// calculeaza CRC pentru un fisier al carui nume este dat de utilizator; pentru verificare, dupa calculul CRC corespunzator fisierului, se continua calculul considerind si valoarea CRC gasita;
// rezultatul (acumulator) dupa adaugarea CRC este nul

int main ()
{
char s [] = "stuff this in your pipe";
word acum = 0, *tabel = tabelcrc(CRCCCITT); // CRCCCITT este generatorul de polinoame
int i;
for(i=0; i < strlen(s); i++)
crctabel(s[i], &acum, tabel); // pt toate car din string
printf("%d\n",acum);

word ac = acum;
crctabel(ac>>8, &acum, tabel);
crctabel(ac& 0x00FF, &acum, tabel);

printf("%d\n",acum);
return 0;

}

Probleme cu programare dinamica

1.
//fie un tablou de dimensiune n x m , alcatuit doar din 1 sau 0 .
// de afisat cel mai mare patrat care poate fi asezat doar pe pozitiile de 1 din matrice
//se afiseaza coltul din dreapta jos si dimensiunea patratului
// complexitatea sa fie O(n*m)

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

int **a, **c, n , m;

int minim(int i, int j) {

int min1=c[i][j-1], min2=0;
if(c[i-1][j] > c[i-1][j-1])
min2 = c[i-1][j-1];
else min2 = c[i-1][j];
return min1>min2? min2:min1;
}

int main() {

FILE *f = fopen("in","r");
int i,j;
fscanf(f,"%d %d",&n,&m);
a = (int **)malloc(n*sizeof(int));
c = (int **)malloc(n*sizeof(int));
for( i=0; i < n; i++) {
a[i]=(int *) malloc(m*sizeof(int));
c[i]=(int *) malloc(m*sizeof(int));
}

for(i=0; i < n ; i++ )
for(j=0; j < m ; j++ )
{fscanf(f,"%d", &a[i][j]);
if(i == 0 || j ==0)
c[i][j] = a[i][j];
}

for(i=1; i < n ; i++)
for(j=1 ; j < m ; j++)
if(a[i][j]) c[i][j] = 1 + minim(i,j);
else c[i][j]=0;

int max =0, ii=0, jj=0;
for(i=0; i < n ; i++)
for(j=0; j < m ; j++)
if(c[i][j]>max) { max = c[i][j]; ii=i; jj=j; }

printf("colt dreapta jos %d %d\nDimensiune %d\n",ii,jj,max);

return 0;
}

2.
// avem N dreptunghiuri de dimensiune variabile,date prin lungime si latime
// de aflat cel mai mare nr de dreptunghiuri incluse unul in altul
//analiza intr-o anumita ordine


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

typedef struct dr { int x; int y;} drept;

int n;
drept * d;
int *best ;

int maxim (int i) {

int j, max = 0;
for(j=0; j < i ; j++)
if( best[j] > max && d[j].y > d[i].y )
max=best[j];
return max;

}

int main() {

FILE *f = fopen("intr","r");
fscanf(f,"%d",&n);
d = (struct dr*)malloc(n*sizeof(struct dr));
int i,j,k;
for(i=0; i < n ; i++ ) {
fscanf(f,"%d %d", &j, &k);
d[i].x = j; d[i].y=k; }
best = (int *)malloc(n*sizeof(int));

// sortare descrescatoare dupa x
int ok;
drept aux;
do {
ok=0;
for(i = 0; i < n-1; i++)
if( d[i].x < d[i+1].x ) {
ok=1; aux = d[i]; d[i]=d[i+1]; d[i+1]=aux; }
} while(ok);

for(i=0; i < n ; i++ )
best[i]=1;

for(i=1; i < n ; i++ )
best[i] = 1 + maxim(i);

int max=0;
for(i=0; i < n ; i++ )
if(max < best[i]) max = best[i];
printf("Nr max este %d\n", max);
return 0;
}

11 martie 2010

Protocolul SLIP

Protocolul SLIP (Serial Line Internet Protocol) actioneaza la nivelul legaturii de date, realizand incapsularea pachetelor IP pentru transmisia acestora pe linii seriale si pe conexiuni modem. SLIP a fost primul protocol de acest gen, si datorita numarului mic de functionalitati pe care le ofera a fost inlocuit de-a lungul timpului cu alte protocoale, cel mai cunoscut fiind PPP (Point-to-Point Protocol).

Principalul obiectiv realizat de SLIP este de a delimita pachetele de date (pentru ca acestea sa fie percepute ca separate). In acest scop, la sfarsitul fiecarui pachet de date se adauga un caracter special numit, in cadrul acestui protocol, END; END este caracterul cu codul ASCII 192. Astfel apare problema ca, daca in interiorul pachetului de date se afla un caracter cu codul 192, acesta sa fie interpretat gresit de catre receiver ca fiind "sfarsit de pachet". Problema se rezolva prin inlocuirea caracterelor 192 din interiorul pachetelor, astfel:

Se defineste un caracter special numit ESC, cu codul ASCII 219 (nu trebuie confundat cu caracterul ESC din codul ASCII; in cazul de fata ESC e doar o denumire ce tine de protocolul SLIP). Daca in interiorul unui pachet de date apare un caracter END, acesta e inlocuit cu o secventa de 2 caractere: caracterul ESC urmat de caracterul cu codul 220. Si caracterele ESC trebuie modificate - ele se inlocuiesc cu secventa formata din caracterul ESC urmat de caracterul 221.

O varianta imbunatatita a protocolului consta din adaugarea de caractere END si la inceputul pachetelor, care il ajuta pe receiver sa poata ignora niste eventuali octeti ce apar "in plus" intre pachete din cauza zgomotului de pe linie.

RFC 1055 (specificatia protocolului SLIP): http://tools.ietf.org/html/rfc1055

sender.c

#include "stdio.h"
#include "string.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"

char send220 = 220;
char send221 = 221;
char END = '%';
char ESC = '#';

int fd1;

void send (char *phrase)
{
int len=strlen(phrase), i=0;

while (len--)
{
if(phrase[i] == END)
{
write (fd1, &ESC, 1 );
write (fd1, &send220, 1 );
}
else if(phrase[i]==ESC)
{
write (fd1, &ESC, 1 );
write (fd1, &send221, 1 );
}
else
write (fd1, &phrase[i], 1 );
i++;
}
}

int main ()
{
fd1 = open ( "mypipe", O_WRONLY );
char * phrase = "Stuff this#in your pipe% and smoke it\n";
char * phrase1 = "SMOKE%IT!!!\n";
send(phrase);
send(phrase1);

write (fd1, &END, 1 );
close (fd1);
return 0;
}

receiver.c

#include "stdio.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"

char END = '%';
char ESC = '#';

int main ()
{
int fd1;
char buf, b;

fd1 = open ( "mypipe", O_RDONLY );
do{
read ( fd1, &buf, 1 );
if(buf==ESC)
{
read ( fd1, &b, 1 );
if(b==220)
printf("%c",END);
else if(b==221)
printf("%c",ESC);
}
else if(buf !=END)
printf("%c",buf);

}while(buf!=END);

close (fd1);
return 0;
}

08 martie 2010

Cel mai lung subsir crescator dintr-un sir

O problema clasica de Programare Dinamica este determinarea celui mai lung subsir strict crescator dintr-un sir de numere. Un subsir al unui sir este format din caractere (nu neaparat consecutive) ale sirului respectiv, in ordinea in care acestea apar in sir.

Exemplu: pentru sirul 24 12 15 15 8 19 raspunsul este sirul 12 15 19.

Se observa ca daca incercam o abordare greedy nu putem stabili nici macar elementul de inceput intr-un mod corect.
Se poate rezolva si cu un algoritm care alege toate combinatiile de numere din sir, valideaza ca sirul obtinut este strict crescator si il retine pe cel de lungime maxima, dar aceasta abordare are complexitatea temporala O(2^N). Cu optimizari este posibil sa se ajunga la O(N!).

O metoda de rezolvare mai eficienta foloseste Programarea Dinamica. Incepem prin a stabili pentru fiecare element lungimea celui mai lung subsir strict crescator care incepe cu primul element si se termina in elementul respectiv. Numim aceasta valoare best(i) si aplicam formula recursiva best(i)= 1+ max(best(j)), cu j < elem(i).

Aplicand acest algoritm obtinem:
elem 24 12 15 15 8 19
best 1 1 2 2 1 3

Pentru 24 sau 12 nu exista nici un alt element in stanga lor strict mai mici decat ele, de aceea au best egal cu 1. Pentru elementele 15 se poate gasi in stanga lor 12 strict mai mic decat ele. Pentru 19 se gaseste elementul 15 strict mai mic decat el. Cum 15 deja este capat pentru un subsir-solutie de 2 elemente, putem spune ca 19 este capatul pentru un subsir-solutie de 3 elemente.
Cum pentru fiecare element din multime trebuie sa gasim un element mai mic decat el si cu best maxim, avem o complexitate O(N) pentru fiecare element. In total rezulta o complexitate O(N^2). Se pot obtine si rezolvari cu o complexitate mai mica folosind structuri de date avansate.

Pentru a gasi care sunt elementele ce alcatuiesc subsirul strict crescator putem sa retinem si o „cale de intoarcere”. Reconstructia astfel are complexitatea O(N). Exemplu: subproblema care se termina in elementul 19 are subsirul de lungime maxima 3 si a fost calculata folosind subproblema care se termina cu elementul 15 (oricare din ele). Subsirul de lungime maxima care se termina in 15 a fost calculat folosindu-ne de elementul 12. 12 fiind cel mai mic element din subsir marcheaza sfarsitul reconstructiei.

Programul in C este:

// sir de n numere se cere implementarea unui progr care det cel mai lung sir crescator O(n^2)

#include "stdio.h"

int main () {

int v [] = {24, 12, 15, 15, 8, 19}, n = 6;
int s[6], m =0, prec[6], l=0, best[6];
int i,j,k;
for(i=0; i < n;i++) {
best[i]=0;
prec[i]=-1;
}
best[0]=1;
for(i=1; i < n;i++) {
int max = 0;
for(j=0;j < i; j++) {
if(v[j] < v[i] && max < =v[j]) {
max = v[j];
best[i]=1+best[j];
prec[i]=j;
}
if(v[j]==v[i]) best[j]=best[i];
}
if(best[i]==0) best[i]=1;

}

int maxbest =0;
for(i=0; i < n; i++)
if(best[i] > maxbest)
maxbest = best[i];
j=0;
for(i=n-1; i > =0;i--)
if(best[i]==maxbest) {
s[j++]=v[i];
if(prec[i] > =0)
s[j++]=v[prec[i]];
i = prec [i];
maxbest=maxbest - 2;
}
for(i=j-1; i > =0; i--)
printf("%d ", s[i]);
printf("\n");
return 0;
}

03 martie 2010

Merge Sort in Scheme

(define (split ls) ; desparte o lista in doua
(letrec ([split-h (lambda (ls ls1 ls2)
(cond
[(or (null? ls) (null? (cdr ls))) ;daca are un element sau e vida
(cons (reverse ls2) ls1)]
[else (split-h (cddr ls) ; lista mai putin primele 2 elemente
(cdr ls1) (cons (car ls1) ls2))]))])
(split-h ls ls '())))

(define (merge pred ls1 ls2) ; combina elementele a doua liste -> o lista ordonata
(cond
[(null? ls1) ls2]
[(null? ls2) ls1]
[(pred (car ls1) (car ls2))
(cons (car ls1) (merge pred (cdr ls1) ls2))]
[else (cons (car ls2) (merge pred ls1 (cdr ls2)))]))

(define (merge-sort pred ls) ; corpul principal
(cond
[(null? ls) ls]
[(null? (cdr ls)) ls]
[else (let ([splits (split ls)])
(merge pred
(merge-sort pred (car splits))
(merge-sort pred (cdr splits))))]))

(merge-sort < '(5 2 4 0 1))

Sortare prin insertie in Scheme

In Scheme, o sortare se realizeaza in doua etape:
- se creeaza o functie simpla insert care adauga un element intr-o lista deja sortata. Merge pe principiul: ia o lista, verifica primul element, daca e mai mare decat elementul de inserat acesta se va insera chiar inaintea lui, altfel listei i se aplica `tail`, iar listei ce rezulta fara primul element i se aplica acelasi tratament pana cand elementul de inserat isi gaseste locul in lista (recursivitate).
- se creeaza o lista vida in care se vor insera pe rand fiecare element din lista noastra.


(define insert ; insereaza un element intr-o lista deja sortata
(lambda (element lista)
(cond ((null? lista) (list element)) ; daca e lista nula creeaza o noua lista din element
((<= element (car lista)) (cons element lista)) ; daca elementul<=primul element din lista, il pune primul
(else (cons (car lista) (insert element (cdr lista))))))) ; altfel lipeste primul element de restul listei unde element se presupune a fi inserat

(define ls '(20 51 19 13 10))
(define ls_empty '())

(define insertion-sort
(lambda (ls new)
(if (null? ls) new
(let ((new (insert (car ls) new))) (insertion-sort (cdr ls) new))
)
))

(insertion-sort ls ls_empty)

Forme curry si uncurry in Scheme

In Scheme, functiile au forma curry (isi asteapta parametrii pe rand) sau uncurry (primeste toti parametrii odata)

In urmatorul exemplu, se realizeaza concatenarea a doua liste folosind functii recursive in forma curry si uncurry:

appendcurry.ss


(define l1 '(1 2 3))
(define l2 '(5 6 7))

(define appendc
(lambda (l1)
(lambda (l2)
( if (null? l1) l2
(cons (car l1) ((appendc (cdr l1)) l2 ) ) ) )
))

(display ((appendc l1) l2))


appenduncurry.ss

(define l1 '(1 2 3))
(define l2 '(5 6 7))

(define appendu
(lambda (l1 l2)
( if (null? l1) l2
(cons (car l1) (appendu (cdr l1) l2 ) ) ) )
)

(display (appendu l1 l2))


Trecerea de la curry la uncurry sau invers a unei functii se face astfel:

(define f (lambda(x y) (+ x y)))

; curry -> uncurry

(define uc
(lambda (f)
( lambda(x)
(lambda(y)
(f x y)
))))

(((uc f ) 2 )3)

(define g (lambda (x)
(lambda (y)
(+ x y))))

; uncurry -> curry

( define cu
(lambda (f)
(lambda (x y)
((f x) y))))

((cu g) 2 3)

01 martie 2010

Protocolul ABP folosind comunicatia prin pipe-uri

Pipe-urile permit comunicatia intre doua procese pe sisteme Unix.
ABP (alternating bit protocol) este un transmitator de date simplu care transmite date corupte sau pierdute. Fiecare mesaj de la A la B contine doua parti: data (ce se transmite propriu-zis) si o secventa de 1 bit (0 sau 1) numita tag. In schimb, B transmite lui A un mesaj de confirmare (ACKnowledgement) ACK0 sau ACK1. Cand A trimite un mesaj, il trimite in mod continuu, pana cand primeste mesajul de confirmare de la B care contine acelasi lucru ca si tag. Cand acest lucru se intampla, A transmite urmatorului mesaj.
Cand B primeste un mesaj care nu este corupt si are ca si continut 0, incepe sa trimita ACK0, pana cand primeste un mesaj valid cu numarul 0. Apoi incepe sa trimita ACK1, etc.

Mai jos, sunt prezentate 2 programe in C care simuleaza transmiterea de date intre doua programe. In Linux se deschid 2 console, unde se creeaza 2 pipe-uri cu numele date in program:

mkfifo pipe1
mkfifo pipe2

Apoi se ruleaza programele in acelasi timp si se observa transmiterea de date.

receiver.c


#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "string.h"
#include "sys/stat.h"
#include "fcntl.h"

//receiver

int main ()

{
char tag;
int fd1, fd2;
fd1 = open ( "pipe1", O_RDONLY );
fd2 = open ("pipe2", O_WRONLY);

char buf [100];
int p;

while(1) {
read ( fd1, buf, 100 );
p=strlen (buf);
printf ( "%s \n", buf );
tag = buf [p-1];
write (fd2, &tag, 1);
}

close (fd1);
close (fd2);
return 0;
}


sender.c

#include "stdio.h"
# include "string.h"
#include "sys/types.h"
#include "unistd.h"
#include "sys/stat.h"
#include "fcntl.h"

// sender

char * phrase = "Stuff this in your pipe and smoke it";

int main ()

{ int fd1, fd2;
char tag;
fd1 = open ( "pipe1", O_WRONLY );
fd2 = open ("pipe2", O_RDONLY);
int i;
for(i=0 ; i < strlen (phrase); i+=3) {
write (fd1, phrase+i, 3);
read (fd2, &tag, 1);
}
close (fd1);
close(fd2);
return 0;
}

Merge Sort

Algoritmul merge sort execută următorii paşi
  1. Dacă lista este de lungime 0 sau 1, atunci este deja sortată. Altfel:
  2. Împarte lista nesortată în două subliste aproximativ egale.
  3. Sortează fiecare sublistă recursiv prin reaplicarea algoritmului merge sort.
  4. Se interclaseaza cele două liste şi se obţine lista iniţială sortată.


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

int *x;

void merge (int s,int d) {

int *y=(int *)malloc((d-s+1)*sizeof(int));
int i,j,k,m;
m=(s+d)/2;

for(i=s, j=m+1, k=0; i < =m && j < =d; k++)
if(x[i] < x[j])
   y[k]=x[i++];
else y[k]=x[j++];

for(; i < =m; k++)
   y[k]=x[i++];
for(; j < =d; k++)
   y[k]=x[j++];
for(k=0, i=s; k<d-s+1; k++)
   x[k+i]=y[k];
}


void ms (int i,int j) {

if(i < j) { ms(i,(i+j)/2);
  ms((i+j)/2+1,j);
  merge(i,j); }
}


int main()
{
int n, i;
scanf("%d",&n);
x=(int *)malloc(n*sizeof(int));

for(i=0; i < n; i++)
  scanf("%d",&x[i]);
printf("\n");

ms(0,n-1);
for(i=0; i < n ; i++)
   printf("%d ",x[i]);

return 0;

}

Sortare rapida (Quick sort)

Quicksort efectuează sortarea bazându-se pe o strategie divide et impera. Astfel, el împarte lista de sortat în două subliste mai uşor de sortat. Paşii algoritmului sunt:

  1. Se alege un element al listei, denumit pivot.
  2. Se reordonează lista astfel încât toate elementele mai mici decât pivotul să fie plasate înaintea pivotului şi toate elementele mai mari să fie după pivot. După această partiţionare, pivotul se află în poziţia sa finală.
  3. Se sortează recursiv sublista de elemente mai mici decât pivotul şi sublista de elemente mai mari decât pivotul.

O listă de dimensiune 0 sau 1 este considerată sortată.


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

int *x;

int poz (int s, int d) {

int i=s, j=d, di=0, dj=1, aux;
while(i < j)
{ if(x[i] > x[j])
{ aux=x[i];
x[i]=x[j];
x[j]=aux;
di=1-di;
dj=1-dj; }
i+=di;
j-=dj; }
return i;
}


void quick (int s, int d) {

if(s < d) { int k=poz(s,d);
quick(s,k-1);
quick(k+1,d); }
}

int main () {

srand(time(NULL));
int n;
scanf("%d",&n);
x=(int *)malloc(n*sizeof(int));

int i;
for(i=0; i < n ;i++)
x[i]=rand()%100;
for(i=0; i < n ;i++)
printf("%d ",x[i]);
quick(0,n-1);

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

return 0;
}