0) b1[--n] = b[i]; // az utolsót már így is lehet! else Console.WriteLine("a tömb üres!"); for(i=0; i < b.Length; i++) Console.Write(b1[i]+" "); AAO"> 0) b1[--n] = b[i]; // az utolsót már így is lehet! else Console.WriteLine("a tömb üres!"); for(i=0; i < b.Length; i++) Console.Write(b1[i]+" "); AAO">
Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
1
AAO Csink László 2008. november
2
Egy n elemű sorozat csupa 0-ból és 1-ből áll
Egy n elemű sorozat csupa 0-ból és 1-ből áll. Rendezzük n-1 összehasonlítással! int i; int[] b = { 0,0,1,0,1,1,0,0,1,0,1,0,0,1,1,0 }; for (i = 0; i < b.Length; i++) Console.Write(b[i] + " "); Console.WriteLine(); int n = b.Length; int[] b1 = new int[n]; // b1 segédtömb for (i = 0; i < n - 1; i++) // b1 végére rakjuk az 1-ket if (b[i] ==1) b1[--n] =b[i]; // fontos, hogy --n és nem n-- if (b.Length > 0) b1[--n] = b[i]; // az utolsót már így is lehet! else Console.WriteLine("a tömb üres!"); for(i=0; i < b.Length; i++) Console.Write(b1[i]+" "); AAO
3
Egy n elemű sorozat csupa 0-ból és 1-ből áll
Egy n elemű sorozat csupa 0-ból és 1-ből áll. Rendezzük összehasonlítás nélkül! int szum = 0, i = 0; int[] b = { 0,0,1,0,1,1,0,0,1,0,1,0,0,1,1,0 }; // megszámoljuk, hány 1-es van for (i = 0; i < b.Length; i++) szum += b[i]; // b „elejét” kellő számú nullával feltöltjük for (i = 0; i < b.Length - szum; i++) b[i]=0; // b „végét” feltöltjük annyi 1-essel, amennyivel kell for (int j= i; j < b.Length; j++) b[j] = 1; AAO
4
A két megoldás összehasonlítása
Az első változatban kellett egy n hosszú ciklus és n-1 összehasonlítás, valamint még egy tömb A második változatban nem kellett összehasonlítás és extra tömb, de több ciklusra volt szükség AAO
5
Geometriai feladat Számítsuk ki a sokszög kerületét és területét!
Legyen adott egy konvex sokszög a síkban, csúcsainak koordinátáival, melyek óramutató járása szerinti bejárási tömbben adottak egy tömbben: x0 y0 x1 y1 x2 y2 ….. Számítsuk ki a sokszög kerületét és területét! AAO
6
A kerületszámítás eleje
Az egyik pont (x,y), a másik (xx,yy) koordinátájú A távolságot számító függvény: public static double tav(double x, double y, double xx, double yy) { return Math.Sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy)); }; AAO
7
Közepe (a Main() belseje)
double[] tomb = new double[] { 1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, -3.0 }; double x, y, xx, yy, d = 0.0; int i, n=tomb.Length; for (i = 0; i+3 < n; i=i+2) { // végig a pontokon x = tomb[i]; y = tomb[i+1]; xx = tomb[i+2]; yy = tomb[i+3]; d += tav(x, y, xx, yy); } d += tav(tomb[0], tomb[1], tomb[n - 2], tomb[n - 1]); AAO
8
Háromszög területe Heron képlettel
A 3szög pontjai (x1,y1), (x2,y2), (x3,y3) public static double heron(double x1, double y1, double x2, double y2, double x3, double y3){ double s, d1, d2, d3 ; d1 = Math.Sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)); d2 = Math.Sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3)); d3 = Math.Sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3)); s = (d1 + d2 + d3) / 2.0; return Math.Sqrt(s * (s - d1) * (s - d2) * (s - d3)); } AAO
9
Konvex sokszög területszámítása
double[] tomb = new double[] { 1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, -3.0 }; double x, y, x1, y1, x2,y2, h = 0.0; int n = tomb.Length; x = tomb[0]; y = tomb[1]; for (int i = 2; i +3 < n; i = i+2) { x1 = tomb[i]; y1 = tomb[i+1]; x2 = tomb[i+2]; y2 = tomb[i+3]; h += heron(x, y, x1, y1, x2,y2); } Console.WriteLine("terulet: " + h); AAO
10
Miért kell a konvexitás?
Amit számítunk: T=(sárga+lila+kék)+(lila+kék) +(lila+barna) Helyesen: T=(sárga+lila+kék)-(lila+kék) +(lila+barna)=sárga+lila+barna A konvexitás biztosítja, hogy a területek összeadhatók! AAO
11
Legnagyobb közös osztó 1.
public static int euklidesz(int a, int b) { int t,a1,b1; a1 = Math.Max(a, b); b1 = Math.Min(a, b); while (a1 != b1) if (a1 > b1) a1 = a1 - b1; else { t = a1; a1 = b1; b1 = t; } } return a1; AAO
12
Legnagyobb közös osztó 2.
public static int gcd(int a, int b) { int t; while (b != 0) t = b; b = a % b; a = t; } return a; Hívás gcd(6,10) t b a 10 6 4 2 AAO
13
Legnagyobb közös osztó 3.
function gcd(a, b) if b = 0 return a else return gcd(b, a mod b) Pszeudokódban public static int gcd(int a, int b) { return ( b == 0 ? a : gcd(b, a % b) ); } Rekurzív C# algoritmus AAO
14
Példa egy harmadfokú polinomra:
Horner séma egy polinom adott x helyen vett értékének gyors kiszámítására Példa egy harmadfokú polinomra: P(x)=7x3 – 2x2 + 5 x = (7x2 – 2x + 5) x - 8= ((7x-2) x +5) x - 8 Az együtthatókat jelöljük: a[3] = 7 a[2]= - 2 a[1]= 5 a[0]= - 5 N=3; POL= a[N]; for(i=n-1; i>=0; i--) POL = POL*x + a[i]; AAO
15
A Fibonacci sorozat A Fibonacci számsorozatban minden szám az első kettő után - az azt megelőző kettő összege. Így tehát a számsorozat: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 stb. Minél későbbi tagjait vesszük a sorozatnak, két egymást követő szám aránya annál inkább az aranymetszéshez fog közelíteni (ami megközelítőleg 1:1,618 vagy 0,618:1) AAO
16
Kiszámítás rekurzívan
public static int fibo(int i){ if (i == 0) return 0; else if (i == 1) return 1; else return fibo(--i) + fibo(--i); } Beugrató kérdés: Ez ugyanaz-e, mint return 2*fibo(--i) ? return fibo(i-1) + fibo(i-2); A Fibonacci számok gyorsan nőnek, a long indokolt lehet AAO
17
Fibonacci tömbbel int i, n; Console.Write("n= ");
n = int.Parse(Console.ReadLine()); long[] f = new long[n]; // Fibonacci számok gyorsan nőnek f[0]=0; f[1]=1; for( i=2;i<n; i++) f[i]= f[i-1]+f[i-2]; AAO
18
Fibonacci ArrayList-tel
int i=0, value=0; Console.Write(„Keressük az első Fibonacci számot, amely nagyobb mint: "); int n = int.Parse(Console.ReadLine()); ArrayList fiblist = new ArrayList(); fiblist.Add(0); fiblist.Add(1); for (i = 2; value <= n; i++) { int[] tomb = new int[fiblist.Count]; fiblist.CopyTo(tomb); value = tomb[i - 1] + tomb[i - 2]; fiblist.Add(value); } Console.WriteLine(n+" . fibo= " + fiblist[--i]); AAO
19
Volt-e szükség menetközben mindegyik Fibonacci számra?
Ha a feladat úgy szól, hogy olvassunk be egy n számot, és ha az első n-nél nagyobb Fibonacci szám 5-tel osztható, akkor írjuk ki az eddigi Fibonacci számok számtani közepét, egyéb esetben pedig a mértani közepét, akkor szükség van az összes korábbi Fibonacci számra (avagy mégsem??) De ha csak az aktuális Fibonacci szám kell, akkor van a tömbhasználatnál egyszerűbb megoldás. A rekurzió, vagy… AAO
20
Fibonacci segédváltozókkal
int i = 0, seged0 = 0, seged1 = 1, f=0; Console.Write("Keressük az n-dikFibonacci számot, ahol n= "); int n = int.Parse(Console.ReadLine()); if (n == 0) Console.WriteLine("A válasz 0"); else if (n==1) Console.WriteLine("A válasz 1"); else{ for (i = 2; i <= n; i++) { f =seged0 + seged1; seged0 = seged1; seged1 = f; } Console.WriteLine("f= "+f); Gyors és memóriatakarékos! Csak a legutolsó Fibonacci számot adja meg. AAO
21
Fibonacci zárt alakban – a képlet
Ekkor c0=0, c1=1, és n >=1 esetén (teljes indukcióval belátható) AAO
22
Fibonacci zárt alakban – a program
int fib; Console.Write("Hanyadik Fibonacci számot számítsuk: "); double n = double.Parse(Console.ReadLine()); double gyot =Math.Sqrt(5.0); fib = (int) Math.Truncate( (1.0/gyot)*( Math.Pow(((1.0+gyot)/2.0),n) - Math.Pow(((1.0-gyot)/2.0),n) ) ); Console.WriteLine("Az eredmény:"+fib); AAO
23
Rendezések A rendezési algoritmus olyan algoritmus, amely egy lista vagy egy tömb elemeit egy meghatározott (növekvő vagy csökkenő) sorrendbe helyezi el. A rendezés lehet numerikus és lehet lexikografikus. A rendezés legtöbbször azért szükséges, hogy utána könnyebben lehessen keresni. Ezentúl, szűkebb értelemben vett rendezés alatt egy olyan algoritmust fogunk érteni, melynek inputja egy egészeket tartalmazó számsorozat, outputja a számsorozat növekvő sorrendben. Az output mindig egy permutációja az inputnak. AAO
24
A rendezési algoritmusok osztályozása
Egy n elemű tömb esetében a szükséges összehasonlítások száma szerint Általános esetben (mi is az általános eset ?!) O(n*log n) összehasonlításnál kevesebb nem elég Számos ismert esetben (példák jönni fognak) O(n*n) összehasonlítás szükséges Néhány esetben (legutóbb tárgyalt eset, ahol csak 0 és 1 szerepelt) O(n) is elég Az O (ordó) jelölés magyarázatát ld. az Analízis tárgyban, vagy itt: AAO
25
További szempontok Szokás vizsgálni a cserék (swap) számát is.
Legyen a és b egészek. Cseréljük ki az értéküket! { int kesztyu = a; a = b; b = kesztyu; } Vizsgálható a memória takarékosság, vannak „helyben” rendező algoritmusok, és vannak olyanok, amelyek segéd tárterületeket igényelnek. Vannak rekurzív és nem rekurzív rendezések. AAO
26
Stabilitás Stabil rendezésnél az azonos kulcsú rekordok relatív sorrendje megmarad, nem stabil rendezésnél változhat. Tekintsünk egész koordinátájú pontokat a síkban, és bocsássunk merőlegeseket az x-tengelyre. Legyen az a feladat, hogy az így keletkezett szakaszokat rendezni kell az x-tengelyen vett korrdinátájuk szerint. Nevezzük az x-koordinátákat kulcsnak. Eszerint történnek az összehasonlítások, de csere esetén a teljes szakaszt (azaz pontpárt) kell cserélni. Legyen a pontsorozat (4, 2) (3, 7) (3, 1) (5, 6) Két sorrend is létrejöhet, ha vannak azonos x-koordinátájú (x=3) pontok: (3, 7) (3, 1) (4, 2) (5, 6) (eredeti sorrend marad, ez a stabil) (3, 1) (3, 7) (4, 2) (5, 6) (eredeti sorrend változik) AAO
27
Buborékrendezés A buborék rendezés a legrosszabb esetben (amikor az elemek csökkenő sorrendben vannak) valamint az átlagos esetben (amikor az elemek véletlenszerűen helyezkednek el) is O(n*n) komplexitású. Mivel sok O(n*log n) komplexitású rendezés van, nagy n esetén a buborék nem előnyös, kivéve, ha az elemek nagyjából eleve növekvően rendezettek. AAO
28
Buborék 1. (csere figyelésével)
public static void bubbleSort(int[] A) { bool csereltunk; int i, kesztyu; do { csereltunk = false; for (i = 0; i < A.Length - 1; i++) { if (A[i] > A[i + 1]) { kesztyu = A[i]; A[i] = A[i + 1]; A[i + 1] = kesztyu; csereltunk = true; } } while (csereltunk); } // nem kezeltük, ha a tömb 0 vagy 1 hosszú AAO
29
Buborék 1. főprogram static void Main() {
int[] A = new int[10]; int i; Random RandomClass = new Random(); for (i = 0; i < A.Length; i++) { A[i] = RandomClass.Next(10, 30); Console.Write(A[i] + " "); } Console.WriteLine(); bubbleSort( A ); for (i = 0; i < A.Length; i++) Console.Write(A[i] + " "); Console.ReadLine(); AAO
30
Buborék 2. public static void bubbleSort(int[] A) {
if (A.Length == 0) Console.WriteLine("A tömb üres!"); else if (A.Length == 1) Console.WriteLine("A tömb 1 elemű!"); else { int i, j, kesztyu; for (i = 0; i < A.Length - 1; i++) for (j = A.Length - 1; j > i; j--) if (A[ j – 1 ] > A[ j ]) { kesztyu = A[j]; A[j] = A[j - 1]; A[j - 1] = kesztyu; } } AAO
31
Kétirányú buborék – cocktail sort (C#)
bottom = 0; top = n-1; bool csere_volt = true; while (csere_volt == true){ csere_volt = false; for (i = bottom; i < top; i++) if (a[i] > a[i + 1]) { csere_volt= true; cs = a[i]; a[i]=a[i+1]; a[i+1]=cs; } top = top - 1; for (i = top; i > bottom; i--) if (a[i] < a[i - 1]) { csere_volt = true; cs = a[i]; a[i] = a[i-1]; a[i-1] = cs; } bottom = bottom + 1; } AAO
32
if (a[i - 1] <= a[i]) i++; // ha jó a sorrend, előre! else {
Kerti törpe rendezés (C#) Wikipedia: The name comes from the supposed behavior of the Dutch garden gnome in sorting a line of flowerpots. It is conceptually simple, requiring no nested loops. i = 1; while (i < n) { if (a[i - 1] <= a[i]) i++; // ha jó a sorrend, előre! else { int cs = a[i - 1]; a[i - 1] = a[i]; a[i] = cs; i--; if (i == 0) i = 1; } // else vége } // while vége AAO
33
Hogyan működik? Az algoritmus megkeresi az első olyan helyet, ahol két egymást követő elem rossz sorrendben van, és megcseréli őket. Ha egy ilyen csere után rossz sorrend keletkezik, az csak közvetlenül a legutolsó csere előtt lehet, így ezt is ellenőrizzük. Talán ez az elképzelhető legegyszerűbb rendezés. AAO
34
A buborék lényeges javítása: fésűs rendezés
A fésűs rendezést (comb sort) eredetileg 1980-ban tervezték, majd újra felfedezték és 1991-ben publikálták a Byte magazinban. A buborék rendezés módosítása, sebességében közelít a híres quicksorthoz. Az alapötlet az, hogy a sorozat végén levő kicsi értékekre találjunk rá minél hamarabb, mert ezek lassítják jelentősen a buborékot. (A sorozat elején levő nagy értékek nem annyira lassítóak, mert ezekre hamar rátalálunk). AAO
35
A fésű kódja public static void combSort(int[] A) { int i; if (A.Length == 0) Console.WriteLine("A tömb üres!"); else if (A.Length == 1) Console.WriteLine("A tömb egyelemű!"); else { int gap = A.Length, cserevolt = 0, kesztyu; while ((gap >1) || (cserevolt !=0)) { if (gap > 1) // gap /1.3 lefelé kerekítve gap = (int)Math.Truncate((double)gap / 1.3); if ((gap == 10) || (gap == 11)) gap = 9; i = 0; cserevolt = 0; while (i + gap < A.Length) { if (A[i] > A[i+gap]){ kesztyu = A[i]; A[i]=A[i+1]; A[i+1] = kesztyu; cserevolt = 1; } i++; AAO
36
Megjegyzések 10 ezer elemű tömbön végzett kísérletek szerint a fésűs rendezés alig rosszabb a quicksortnál (10 %-kal); a változtatás a buborékhoz képest nem nagy. Ugyanakkor nem kell gondoskodni az eleve rendezett esetről, ami a quicksortot nagyon lelassítja (látni fogjuk). A gap beállításával először a távollevő elemeket rendezzük. Ezután a gap csökken, míg végül egy lesz. Ez esetben azonos a program a buborékkal; következésképpen korrekt. Lacey és Richard Box megmutatták, hogy a gap minden lépésben 1.3-mal osztandó. Továbbá felfedezték, hogy 9 és 10 nem alkalmas gap-nek, és 11-gyel helyettesítendő. AAO
37
Combsort versus quicksort
sec Combsort sec Bubblesort 1.36 sec 10 ezer egész szám rendezési kísérletének időeredményei Forrás: [2008. nov. 16.] AAO
38
Quicksort -rekurzívan
static void csere( ref int x, ref int y) { int t= x; x = y; y = t; } static int partition (int[] a, int first, int last) { int pivot = a[first], lastS1 = first, firstUnknown = first + 1; while (firstUnknown <= last) { if (a[firstUnknown] < pivot) { lastS1++; csere( ref a[firstUnknown], ref a[lastS1]); } firstUnknown++; } csere( ref a[first], ref a[lastS1]); return lastS1; static void quicksort (int[] a) { quicksort (a, 0, a.Length - 1); } static void quicksort (int[] a, int first, int last) { if (first < last) { int pivotIndex = partition (a, first, last); quicksort (a, first, pivotIndex - 1); quicksort (a, pivotIndex + 1, last); AAO
39
Minimum kiválasztásos rendezés
static void csere (ref int x, ref int y) { int cs =x; x=y; y=cs; } static void Main() { int i,min, n = 10; int[] a = new int[n]; Random RandomClass = new Random(); for (i = 0; i < n; i++) a[i] = RandomClass.Next(10, 26); for (i = 0; i < n; i++) { min = i; for (int j = i + 1; j < n; j++) if (a[j] < a[min]) min = j; csere(ref a[i], ref a[min]); } AAO
40
Beszúrásos rendezés static void csere (ref int x, ref int y) { int cs =x; x=y; y=cs; } static void Main() { int i,min, n = 10; int[] a = new int[n]; Random RandomClass = new Random(); for (i = 0; i < n; i++) a[i] = RandomClass.Next(10, 26); for (i = 1; i < n; i++) { j = i - 1; while ((j> -1) && (a[j] > a[j+1])) { csere(ref a[j], ref a[j+1]); j--; } AAO
41
Sorting demo AAO
42
Halmazműveletek: metszet
A feladat most két tömb a[0..n-1] és b [0..m-1] azonos elemeinek kiválogatása c tömbbe. A feladat csak úgy értelmezhető pontosan, ha az egyes tömbökben egy elem nem szerepel kétszer. (Mivel most a matematikai halmazokat tömbként ábrázoljuk.) Az algoritmus lényege: menjünk végig az a tömb elemein, és válogassuk ki azokat (kiválogatás), melyek szerepelnek b-ben (eldöntés). Így a feladat a korábbi tételekre visszavezethetõ. c maximális elemszáma n és m közül a kisebbik. Feltételeztük, hogy egyik halmaz sem üres. AAO
43
Deklarációk a metszethez C#
int n = 10, m=6, db =Math.Min(n,m); // tömbméretek int i,j,k; // ciklusváltozók int[] a = new int [n]; // a halmaz elemei 0..n-1 int[] b = new int [m]; // b halmaz elemei 0..m-1 int[] c = new int [db]; // a metszet elemei // db csak a maximális lehetséges tömbméret. Ha a metszet // üres, akkor nyilván nincs elem a metszetben. AAO
44
Metszet C# kód k = 0; for (i=0; i<n;i++) {
Az if NINCS a ciklusban, mert a for törzse üres! k = 0; for (i=0; i<n;i++) { for(j=0; (j<m) && (b[j] != a[i]); j++); // amíg j<m és b[j]<>a[i] if (j<m) c[k++]=a[i]; // ha j=m, akkor a[i] nem szerepelt b-ben // ha j<m, akkor a[i] előfordult b-ben } for (i = 0; i < k; i++) Console.WriteLine(c[i]); // kiíratás AAO
45
Halmazműveletek: unió
A feladat most két tömb a[0..n-1] és b [0..m-1] elemeinek egyesítése c tömbbe. Az egyes tömbökben egy elem nem szerepel kétszer. (mint az előbb) A legkézenfekvőbb megoldás: tegyük be c-be a összes elemét, majd b-ből azokat, melyek nem szerepelnek a-ban. c elemszáma legfeljebb n+m. Feltételeztük, hogy egyik halmaz sem üres. AAO
46
Unió C# kód for (i = 0; i < n; i++) c[i] = a[i]; //a-t áttöltjük c-be k = n; for (j = 0; j < m; j++){ // keressük azt a b-belit, ami nincs a-ban for (i = 0; (i< n) && (b[j] != a[i]); i++) ; if (i >= n) c[k++] = b[j]; // ha volt ilyen, c-be teszzük } for (i = 0; i < k; i++) Console.WriteLine(c[i]); // Futásidő n*m nagyságrendű! AAO
47
Unió speciális esetben (C#): az a és b (halmazokat reprezentáló) tömbök rendezettek (összefuttatás)
Csak az egyik fut! i = 0; j = 0; k = 0; while(( i < n) && ( j < m)) if (a[i]<b[j]) c[k++] = a[i++]; else if (a[i]==b[j]) {c[k++]= a[i++]; j++;} else c[k++] = b[j++]; for (x=i; x<n; x++) c[k++] =a[x]; for (x=j; x<m; x++) c[k++] =b[x]; for (i = 0; i < k; i++) Console.WriteLine(c[i]); // Futásidő n+m nagyságrendű, n*m helyett (előző)! AAO
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.