Üdv!
Előkerült egy probléma, aminek nem tudom, van-e megoldása.
type csalad=record
nev:string;
gyerek:byte;
end;
var cs:array[1..100] of csalad;
Most szeretnék írni ehez egy rendezést, aminek paraméterként adom át, hogy mi szerint rendezze. Pl. rendez(nev). Az egyetlen működő megoldás az, hogy a rendezésnél egy feltétell megvizsgálom, mit adtam meg (case) és a szerint adom meg utána a rendezésben szükséges feltételt. Kb így:
case mit of
'nev': if cs[i].nev>cs[j].nev then
begin
[...]
end;
'gyerek': if cs[i].gyerek>cs[j].gyerek then
begin
[...]
end;
end;
Ez a megoldás szerintem nagyon gány, nincs erre a problémára elegáns megoldás?
- 6832 megtekintés
Hozzászólások
Ha általánosan akarod:
type relacio=function(cs1,cs2:csalad):boolean;
procedure rendez(mit:relacio);
begin
[...]
if mit(cs[i].nev,cs[j].nev) then
begin
[...]
end;
[...]
end;
A gyerekek rendezéséhez ezt kell átadni:
function gyereknagyobb(cs1,cs2:csalad):boolean;
begin
result:=cs1.gyerek>cs2.gyerek;
end;
Nem ellenőritem, lehet benne bug.
Amúgy a nevek összehasonlításához inkább a sysutils függvényeit kéne használni, amik figyelnek a kódolásra, tehát az ékezeteseket is jól rendezik.
- A hozzászóláshoz be kell jelentkezni
Ha jól értem, a mit az = relacio, ami pedig visszatér true-val, ha cs[i].nev>cs[j].nev. És ez adódik vissza if-nek. Szóval ha visszafejtjük, ezt kapjuk az if-be: cs[i].nev.gyerek>cs[j].nev.gyerek. Vagy rosszul értelmezem?
Megpróbálom leírni a "feladatot" kicsit máshogy, hátha csak félreértés van. :)
Szóval van a fent leírt cs tömb. Ez feltöltve pl. így néz ki:
cs[1].nev='Szabó';
cs[1].gyerek=2;
cs[2].nev='Kovács';
cs[2].gyerek=1;
cs[3].nev='Nagy';
cs[3].gyerek=3;
És a feladat az, hogy ha nekem úgy tetszik, akkor név szerint rendezem, ha meg úgy, akkor gyerek szerint.
Tehát ezeket kaphatjuk:
1. Kovács 2
2. Nagy 3
3. Szabó 1
Vagy
1. Szabó 1
2. Kovács 2
3. Nagy 3
Namost. Ez ugye egyszerűen megoldható, ha 2 eljárásunk van, amelyikek közül az egyik rendezi név szerint, a másik meg gyerek szerint. Viszont ez nem elég rugalmas, mert mi van akkor, ha hirtelen be kell hoznom egy 3. paramétert, pl. jövedelem. Ezért arra gondoltam, fogok egy rendezést, aminek átadom paraméterben, hogy mi alapján rendez. Ha a pascal nagyon rugalmas lenne, ez akár így is kinézhetne:
procedure rendez(mit:string);
begin
[...]
if cs[i].mit>cs[j].mit then
[...]
end;
begin
[...]
rendez('nev');
[...]
rendez('gyerek');
[...]
end.
De mivel a nyelv nem scriptnyelv, ezért ez a megoldás járhatatlan.
- A hozzászóláshoz be kell jelentkezni
Eljárás típust használtam. Valóban nem túl rugalmas. Esetleg használhatsz variant tömböt, de ez növeli a memóriahasználatot és valószínűleg csökkenti a sebességet. Vagy mutatótömböt, ekkor csak a típust kell valahogy átadni, vagy egy típus-pointer recordban tárolni, de figyelni kell a mutatók kezelésére. Továbbá lehet valamilyen lista objektumokat[/url] használni, valamilyen absztrakt osztályból származó objektumokat tárolni, amiket egy absztrakt metódus implementációja hasonlít össze másik azonos típusú objektummal, vagy Free Pascal esetén operátor felüldefiniálást használni.
Szóval mindegyik megoldás bonyolult, akkor értemes használni, ha tényleg szükség van az általánosságra.
- A hozzászóláshoz be kell jelentkezni
Hello!
Egy eleg hulye megoldas jutott eszembe. Ha a ket adatot egy stringben helyezned el akkor a relacio mindig annak megfeleloen rendezne oket, hogy mi van a string elejen. Kerdes az, hogy megengedhetsz ilyen feltoltest vagy csak tovabb ganyolja az egeszet.
Ami biztos, hogy semmikeppen sem kene minden iteracioban lefuttatni egy if-et arra, hogy mi alapjan rendezel, akkor inkabb csinalj ket ciklust kulon.
- A hozzászóláshoz be kell jelentkezni
pascalban eljárás is lehet változó. a rendező eljárásnak egyszerűen átadod az összehasonlító eljárást, és aszerint lesznek rendezve a recordjaid.
- A hozzászóláshoz be kell jelentkezni
"pascalban eljárás is lehet változó"
Ez eddig világos. Nade hogy adom át és hogy használom? Kaphatnék egy példát?
Pl. egyszerűség kedvéért most csak kiíratni akarom a tömböt egy ciklussal.
Szóval ezt kellene átírni úgy, hogy a nev ne konstans legyen, szóval ha én a gyereket akarom kiírni, az úgy adódjon át. Akkor talán meg is értem. :)
procedure kiir;
begin
for i:=1 to n do
begin
writeln(cs[i].nev); {Ezen kellene módosítani}
end;
end;
Ezt ugye így hívom meg: kiir; Kb egy hasonló, egysoros megoldást szeretnék kapni, amiben én adom meg, melyiket (nev vagy gyerek) írja ki.
- A hozzászóláshoz be kell jelentkezni
...
type
TCompareFunc = function(A, B: record):integer;
function Compare(A, B: record): integer;
begin
// Itt megírod az összehasonlításhoz a kódot, és pl ha A>B akkor result := -1, ha egyenlő akkor 0, ha kisebb 1
end;
procedure Rendez(T: array, CF: TCompareFunc)
begin
//Itt meg tudod hívni a CF fgv-t, ettől függően rendezed a tömbödet
KissebbVagyNagyobb := CF(X,Y);
end;
var
func: TCompareFunc;
Lista: array;
begin
func := @Compare;
Rendez(Lista, func);
end.
Csak nagy vonalakban.
- A hozzászóláshoz be kell jelentkezni
Ok, én még mindig nem értem. :)
Azt értem, hogy van a Compare fv, ami elvégzi az összehasonlítást. De amikor meghívom a CF fv-t, akkor nekem már tudnom kell, hogy a nev vagy gyerek alapján rendezek. Legalábbis így látom. Viszont ahhoz a Rendez-nek kellene átadni, hogy én nev vagy gyerek alapján rendezek. Jó lenne, ha látnék egy konkrét példát a fenti feladat esetében, hogy hogy kellene meghívni a dolgokat ahhoz, hogy jól működjenek...
Érdekes, hogy ez scriptnyelvekben milyen egyszerűen megoldható. Bash-ban pl. ennyi: ${cs[i]}.($mit) Mármint így nézne ki, ha lennének recordok bashban. :) Js-ben meg pl. ennyi: eval('cs[1].'+mit); Persze js-ben sem tudok recordokról...
- A hozzászóláshoz be kell jelentkezni
A pascal típusos nyelv, azt nem várhatod el tőle, hogy kitalálja mit, hogyan akarsz rendezni.
Esetleg adhatsz át pointereket, meg változó hosszakat, de így csak bináris rendezést tudsz csinálni.
Talán variant típussal is megoldható, de annak használatába még nem kellett belemerülnöm. :)
- A hozzászóláshoz be kell jelentkezni
Bocsi, lehet én vok nehéz felfogású, de újból végigolvasva, nekem úgy tünik, azt várod el, hogy a rendező algoritmusod kitalálja mi szerint akarsz rendezni.
Ez szerintem egy nyelvben sem mükszik.
- A hozzászóláshoz be kell jelentkezni
Huhh, essünk neki mégegyszer. :)
van egy tömb, aminek minden eleme 1 1 record. Pl.
cs[1].nev='Szabó';
cs[1].gyerek=1;
cs[2].nev='Kovács';
cs[2].gyerek=2;
cs[3].nev='Nagy';
cs[3].gyerek=3;
Most nekem van egy menüm, amiben kiválasztom, hogy ezeket az értékeket név szerint, vagy gyerekek száma szerint rendezem. Tehát ha a név szerinti rendezést választom, ezt akarom kapni:
Név Gyerek
-------------
Kovács 2
Nagy 3
Szabó 1
De ha én gyerekek száma szerint akarok rendezni, ezt szeretném kapni:
Név Gyerek
-------------
Szabó 1
Kovács 2
Nagy 3
Namost. Választhatom azt a megoldást, hogy csinálok 2 eljárást, az egyik rendez név szerint, a másik gyerek szerint. De ez így elég gazdaságtalan, mert a 2 rendezés gyakorlatilag ugyan az a kód, csak az egyikben a nev szerepel cs[számlálóváltozó] után, a másikban a gyerek.
Más nyelvekben, ahol nincsenek recordok, ott mátrixszal oldom meg a problémát. Pl.
/*Igen, volna 0. elem is, ha C-ről beszélünk. :)*/
cs[1][1]='Szabó';
cs[1][2]=2;
cs[2][1]='Kovács';
cs[2][2]=1;
cs[3][1]='Nagy';
cs[3][2]=3;
Amit ezután kb így rendezhetek:
void rendez(int mit)
{
[Rendezés eleje, feltétel:]
if(cs[i][mit]>cs[j][mit])
[Rendezés vége]
}
És így hívom meg, ha név szerint akarok rendezni:
rendez(0);
, és így, ha gyerek szerint:
rendez(1);
.
Ez a megoldás pascalban is működne, de mivel egyrészt szebb, ha használok recordokat, másrészt éppen a recordokat tanuljuk, nekem úgy kellene megírni a programot. Szóval erre keresek megoldást.
- A hozzászóláshoz be kell jelentkezni
Pascalban nem tudsz váltózóra ilyen módon hivatkozni, másrészt NEM UGYANAZ a két rendezés, mivel eltérő típusú változókat kell sorbarendezned.
- A hozzászóláshoz be kell jelentkezni
Nem ugyanaz, ez tény. Viszont elég jó eredményt ad vissza ahhoz, hogy példaprogramként megoldjuk órán. És én ezt gondoltam volna tovább. Kár, hogy nem megoldható.
Illetve órán még eszembejutott egy olyan megoldás, hogy egy vektorba kiszórom a record azon elemeit, amiket rendezni szeretnék. Ezután a vektoron megyek végig, és amikor a vektorhoz nyúlok, akkor a cs tömböt is módosítom. Persze itt meg az a probléma, hogy a record többféle változót tartalmazhat. Ha tudnám, hogy hogy lehet változót dobni, majd futás közben újra létrehozni, megoldható lenne a probléma. (Ez utóbbi egymásba ágyazott eljárásokkal megoldható.)
- A hozzászóláshoz be kell jelentkezni
Akkor pointerek, meg a változó mérete, és mint egy-egy byte tömböt hasonlítasz össze 2 változót.
- A hozzászóláshoz be kell jelentkezni
A
Rendez(Lista, func);
hívásnál a második paraméter tartalmazza a rendező függvényt. A
func := @Compare;
értékadás után ugyanis a func változó a Compare függvény memóriacímét tartalmazza. Ez a változó a Rendez függvényben CF néven jelenik meg, így az ottani
CF(X,Y)
függvényhívás a Compare függvényt hívja meg, ami itt az egyik rendező függvény. Másik rendező függvény használatához a Rendez második paraméterében a másik függvény címét add át. Amúgy azt hiszem, mem kell a függvény címét változóba írni, közvetlenül
Rendez(Lista, @Compare);
is jó.
Amúgy ha nem kell valami speciális gyors rendezési algoritmus (azaz O(length(Lista)^2) is elég), legegyszerűbb mindehol kiírni a rendezési algoritmust (kb. egy sor). Ha O(length(Lista)*log(length(lista))) idejű kell, akkor jobb, ha osztályokkal dolgozol.
- A hozzászóláshoz be kell jelentkezni