Triedenie poľa komplexných čísel (riešené príklady)

Z Kiwiki
Verzia z 16:17, 8. marec 2010, ktorú vytvoril Juraj (diskusia | príspevky)
Skočit na navigaci Skočit na vyhledávání

Algoritmy a programovanie - zbierka úloh


Štruktúry

Rekurzia

Dynamická alokácia pamäti

Vyhľadávanie

Triedenie

>Triedenie poľa komplexných čísel
>Triedenie poľa smerníkov na CPLX
>Triedenie poľa štruktúr
>Triedenie poľa smerníkov

Lineárny zoznam

Binárny strom

Numerické algoritmy

Majme známu štruktúru komplexné číslo - CPLX. Ako iste viete, komplexné číslo obsahuje 2 časti:reálnu časť (re) a imaginárnu časť (im). Ľubovoľné komplexné číslo C=a+i*b dokážeme zobraziť v komplexnej rovine ako vektor so začiatkom v bode [0,0] a koncom v bode C=[a,b].

Veľkosť komplexného čísla |C| je vlastne vzdialenosť od počiatku súradnicovej sústavy. Vypočítame ho pomocou pytagorovej vety ako: |C|=(a*a+b*b)^1/2

Majme pole komplexných čísel, ktoré chceme zotriediť podľa ich veľkosti. V hlavnom programe main načítam číslo n a následne n komplexných čísel. Tieto komplexné čísla načítajte do jednorozmerného poľa komplexných čísel, ktoré má presne veľkosť n (použite dynamickú alokáciu).

Ako triediaci algoritmus použijeme quicksort, pretože je značne efektívny. Metóda triedenia quicksort bola vysvetlená na prednáške. Len v krátkosti: quicksort je rekurzívny algoritmus, ktorý si rozdelí usporiadavané pole na 2 časti: prvky v prvej časti sú menšie ako stredný prvok (pivot) a prvky v druhej časti sú väčšie ako stredný prvok. Potom sa rekurzívne aplikuje algoritmus quickosrt na prvú aj druhú časť triedeného poľa, pokiaľ je počet prvkov v danej časti poľa väčší ako 1.

V tomto príklade usporiadavame pole celých čísel. Našou úlohou je ale usporiadať pole komplexných čísel. Vo funkcii QuickSort sa zmení prvý parameter na pole komplexných čísel: CPLX data[]. Ďalej je treba zmeniť tú časť kódu, kde sa navzájom porovnávajú prvky triedeného poľa (podčiarknuté časti kódu). V tomto prípade sú to dva cykly while, kde sa určujú indexy i a j, ktoré slúžia pri usporiadavaní poľa na časť väčšiu a menšiu ako je pivot. Tieto časti kódu nahradíme porovnávacou funkciou, ktorá bude porovnávať dve komplexné čísla x a y. Ak platí že x>y, tak funkcia vráti 1, inak vráti 0. Týmto zručíme rovnakú funkcionalitu ako relačný operátor ‘>’. Funkcia bude mať 2 parametre typu CPLX a návratová hodnota bude int.

1 int porovnaj(CPLX a, CPLX b)
2 {
3   if(abs(a)>abs(b))
4      return 1;
5   else
6      return 0;
7 }

Na skontrolovanie správnosti usporiadania poľa komplecných čísel môžeme použiť jednoduchú funkciu, ktorá overí či prvok s indexom i+1 je väčší ako prvok s indexom i. Pri prvej nezhode funkcia vráti hodnotu 0. Ak sa pre všetky prvky platí predpoklad prvok[i+1]>prvok[i] , tak vráti funkcia hodnotu 1.

1 int skontroluj(CPLX data[ ],int n)
2 { 
3   for(int i=1;i
4   {
5     if(porovnaj(data[i-1],data[i])>1)
6         return 0;
7   }
8   return 1;
9 }

Ak máme pripravenú porovnávaciu funkciu, tak aplikovanie iného algoritmu triedenia je veľmi jednoduché. Stačí v danom kóde zameniť časť kódu, kde sa robí porovnávanie prvkov. Jazyk C obsahuje vstavanú funkciu qsort, ktorá usporiadava pole prvkov pomocou algoritmu quicksort. Hlavička funkcie vyzerá nasledovne:

void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));

Opis funkcie qsort je na stránke qsort

Použitie funkcie qsort pre náš príklad:

 qsort((void *)ccisla2,n,sizeof(ccisla2[0]),porovnajQ);
1 int porovnajQ(const void *a, const void *b)
2 {   if(abs((*(CPLX *)a))>abs((*(CPLX *)b)))
3         return 1;
4     if(abs((*(CPLX *)a))<abs((*(CPLX *)b)))
5         return -1;   
6     return 0;
7 }

Podľa definície funkcie qsort musí mať porovnávacia funkcia 2 argumenty typu ukazateľ na void. Teda parametre a a b sú typu ukazateľ na void. My však potrebujeme porovnať 2 komplexné čísla (bez ukazovateľov). Ako prvé musíme a a b pretypovať z ukazateľa na void na ukazateľ na CPLX. Toto urobíme následovne: (CPLX *)a.Teraz je a ukazateľ na CPLX. Ale ako už bolo povedané, my máme k dispozícii len komplexné čísla (CPLX), nie ukazatele. Z teórie ukazateľov vieme vzťah medzi ukazateľom a poľom – že ak je x ukazovateľ na nejaký dátový typ, tak *x je obsah prvého (s indexom 0) prvku. Teda, ak je (CPLX *)a ukazovateľ na CPLX, tak(*(CPLX *)a)je obsah tohto ukazateľa – čiže komplexné číslo a.

Na záver porovnajte, či oba algoritmy dosahujú zhodné výsledky – stačí porovnať polia usporiadané funkciou QuickSort a funkciou qsort.

1 int skontroluj(CPLX data1[ ],CPLX data2[ ],int n)
2 {   for(int i=0;i<n;i++)
3         if(porovnaj(data1[i],data2[i])!=0)
4             return 0;
5     return 1;
6 }

Možné riešenie:

  1 #include <iostream>
  2 #include <math.h>
  3 using namespace std;
  4 
  5 struct CPLX{double re,im;};
  6 
  7 void nacitajCPLX(CPLX &c)
  8 {     cin>>c.re>>c.im;  }
  9 
 10 double abs(CPLX x)
 11 {  return sqrt( (x.re*x.re)+ (x.im*x.im) ); }
 12 
 13 int porovnaj(CPLX a, CPLX b)
 14 {   if(abs(a)>abs(b))
 15         return 1;
 16     else     
 17         return 0;
 18 }
 19 
 20 void zamen (CPLX &a, CPLX &b)
 21 {
 22     CPLX tmp=a;
 23     a=b;
 24     b=tmp;
 25 }
 26 
 27 void QuickSort(CPLX data[ ],int lavy, int pravy)
 28 {      if(lavy<pravy)
 29       {  int i = lavy, j = pravy;
 30           CPLX p = data[ (lavy + pravy) / 2 ];
 31           do {
 32                 while ( porovnaj(p,data[ i ])>0 ) i++;
 33                 while ( porovnaj(data[ j ],p)>0 ) j--;
 34                 if (i <= j)
 35                       {    zamen(data[ i ], data[ j ]);
 36                          i++; j--;
 37                     }
 38                } while (i <= j);
 39                 QuickSort(data, lavy, j);
 40                 QuickSort(data, i, pravy);
 41         }
 42 }
 43 
 44 int skontroluj(CPLX data[ ],int n)
 45 {   for(int i=1;i<n;i++)
 46         if(porovnaj(data[i-1],data[i])>0)
 47             return 0;
 48     return 1;
 49 }
 50 
 51 int skontroluj(CPLX data1[ ],CPLX data2[ ],int n)
 52 {    for(int i=0;i<n;i++)
 53         if(porovnaj(data1[i],data2[i])!=0)
 54             return 0;
 55     return 1;
 56 }
 57  
 58 void vypis(CPLX data[ ],int n)
 59 {  for(int i=0;i<n;i++)
 60     {   cout<<data[i].re;
 61         if(data[i].im>0)
 62             cout<<"+i"<<data[i].im;
 63         else
 64             cout<<"-i"<<-data[i].im;
 65         cout<<" ("<<abs(data[i])<<")";
 66         cout<<endl;
 67    }
 68 }
 69  
 70 int porovnajQ(const void *a, const void *b)
 71 {   if(abs((*(CPLX *)a))>abs((*(CPLX *)b)))
 72         return 1;
 73     if(abs((*(CPLX *)a))<abs((*(CPLX *)b)))
 74       return -1; 
 75      return 0;
 76 }
 77 
 78 int main()
 79 {   int n;     
 80     cin>>n;
 81     CPLX *ccisla1=new CPLX[n];
 82     CPLX *ccisla2=new CPLX[n];
 83 
 84     for(int i=0;i<n;i++)
 85     {  nacitajCPLX(ccisla1[i]);
 86         ccisla2[i]=ccisla1[i];
 87     }
 88 
 89     int k;
 90     QuickSort(ccisla1,0,n-1);
 91     k=skontroluj(ccisla1,n);
 92     cout<<"kontola QuickSort:"<<k<<endl;
 93 
 94     qsort((void *)ccisla2,n,sizeof(ccisla2[0]),porovnajQ);
 95     k=skontroluj(ccisla2,n);
 96     cout<<"kontola qsort:"<<k<<endl;
 97     k=skontroluj(ccisla1,ccisla2,n);
 98     cout<<"Kontrola zhodnosti: "<<k;
 99     return 0;
100 }