Potíže s cykly v programu do školy – Delphi – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Potíže s cykly v programu do školy – Delphi – Fórum – Programujte.comPotíže s cykly v programu do školy – Delphi – Fórum – Programujte.com

 

Jan
~ Anonymní uživatel
187 příspěvků
8. 6. 2014   #1
-
0
-

Dobrý den,

dělám doma semestrálku v Delphi a trošku si nevím rady, jakou část mám upravit. Má to být program, který vygeneruje do pole n souřadnic bodů v rovině (x,y), a potom má porovnat jejich vzdálenosti a najít tu nejmenší ze všech. Něco jsem už udělal, ale pořád mi to dělá pouze kombinaci posledního bodu s ostatníma - což je mi trochu divný. Jak je vidět v tom zdrojáku snažil jsem se tam nějak zavést dva cykly a myslel jsem že budou pracovat oba současně, ale pak se ukázalo, že to udělá jen inkrementaci pro i, jenže to j se pak načte asi jen jako největší i...promiňte, moc tomu ještě nerozumím, takže nevím, jestli je to možné. Došel jsem k tomu, když jsem si nechal vypisovat indexy, pro které to danou vzdálenost vypočítá, a ono to napíše vždy poslední, respektive ještě větší o jedničku, ale to tam mám chybu...poprosil bych o radu, třeba jen info jak udělat dva cykly kde jeden běží od začátku v tom prvním...(pozn. prvně jsem měl místo cyklu while prostě jen for i:=1 to n-1)

procedure NahodneGeneruj (var Pole:Tpole; sgpole : TStringGrid; n : integer);
var

Minimum, maximum : integer;
i,j : integer;
MinVzdalenost : real;
Vzdalenost : real;
PrvniIndex, DruhyIndex : integer;
a : integer;

begin

  Randomize;

  n:= StrToInt (frmHlavni.edtPocet.text);
  Minimum := StrToInt (frmHlavni.edtMIN.text);
  Maximum := StrToInt (frmHlavni.edtMAX.text);

  sgPole.ColCount := 2;
  sgPole.RowCount := n;

    for i := 1 to 2 do
       for j := 1 to n do

  Pole [i,j] := RoundTo (Minimum + Random* (Maximum-Minimum),-2);


    for i := 0 to n do
       for j := 0 to 2 do

               begin
                    sgPole.Cells[j,i] := FloatToStr(Pole[j+1,i+1]);
                    end;

begin

minVzdalenost := MaxInt;

i:=1;

while i<=(n-1) do

begin

    for j:= i+1 to n do

        vzdalenost := sqrt(sqr(Pole[1,i]-Pole[1,j])+sqr(Pole[2,i]-Pole[2,j]));

    if vzdalenost < minVzdalenost then


minVzdalenost := vzdalenost;

if vzdalenost = minVzdalenost then

PrvniIndex := i;
DruhyIndex := j;

i:=i+1 ;

end;

Nahlásit jako SPAM
IP: 178.255.168.–
p3can
~ Anonymní uživatel
312 příspěvků
8. 6. 2014   #2
-
0
-

ach ... to je zase kod xD

zaprve ty procedury maji byt jako samostatne funkcni celky kodu, coz znamena ze to co pouzivas v tele by si mel deklarovat v parametrech te procedury. taky by ta procedura mela delat to "jak je pojmenovana". kdyz mas pojmenovanou proceduru nahodnegeneruj tak proc to krome generovani i pocita nejake vzdalenosti ? a kde to ma nejaky vystup ?

proc je jednu  i,j a podruhe j,i v tech cyklech ?

proc toto?
if vzdalenost < minVzdalenost then

      minVzdalenost := vzdalenost;

if vzdalenost = minVzdalenost then

predpokladam ze chyba je tu  

misto

if vzdalenost = minVzdalenost then

PrvniIndex := i;
DruhyIndex := j;

toto

if vzdalenost = minVzdalenost then
begin
PrvniIndex := i;
DruhyIndex := j;
end;
Nahlásit jako SPAM
IP: 77.92.213.–
Sniper
~ Anonymní uživatel
215 příspěvků
8. 6. 2014   #3
-
0
-

Tohle je semestrálka?! Trochu jsem se nudil, tak jsem to zkusil napatlat. Takhle bych to viděl já po max. půlhodince "práce":

uses
  Math;

type
  TPoints = Array of TPoint;

procedure GenerateArray(var Points: TPoints; Count: Integer; Min, Max: Integer);
var
  i:  Integer;
begin
SetLength(Points,Count);
Randomize;
For i := Low(Points) to High(Points) do
  begin
    Points[i].X := RandomRange(Min,Succ(Max));
    Points[i].Y := RandomRange(Min,Succ(Max));
  end;
end;

Function ShortestDistance(Points: TPoints; out Pt1Idx,Pt2Idx: Integer): Double;
var
  i,j:      Integer;
  Distance: Double;
begin
Pt1Idx := -1;
Pt2Idx := -1;
Result := 0;
For i := Low(Points) to Pred(High(Points)) do
  For j := Succ(i) to High(Points) do
    begin
      Distance := Sqrt(Sqr(Points[i].X - Points[j].X) + Sqr(Points[i].Y - Points[j].Y));
      If Distance > Result then
        begin
          Result := Distance;
          Pt1Idx := i;
          Pt2Idx := j;
        end;
    end;
end;

procedure TfrmMainForm.btnGenerateClick(Sender: TObject);
var
  Points:     TPoints;
  Idx1,Idx2:  Integer;
  Distance:   Double;
  i:          Integer;
begin
GenerateArray(Points,StrToIntDef(lePointsCount.Text,0),
              StrToIntDef(leCoordMin.Text,0), StrToIntDef(leCoordMax.Text,100));
sgPoints.RowCount := Length(Points);
For i := Low(Points) to High(Points) do
  begin
    sgPoints.Cells[0,i] := IntToStr(Points[i].X);
    sgPoints.Cells[1,i] := IntToStr(Points[i].Y);
  end;
Distance := ShortestDistance(Points,Idx1,Idx2);
If (Idx1 >= 0) and (Idx2 >= 0) then
  ShowMessage('Shortest distance: ' + FloatToStr(RoundTo(Distance,-3)) + sLineBreak +
              'Point 1: #' + IntToStr(Idx1) + ' [' + IntToStr(Points[Idx1].X) + ', ' + IntToStr(Points[Idx1].Y) + ']' + sLineBreak +
              'Point 2: #' + IntToStr(Idx2) + ' [' + IntToStr(Points[Idx2].X) + ', ' + IntToStr(Points[Idx2].Y) + ']')
else
  ShowMessage('Calculation failed.');
end;
Nahlásit jako SPAM
IP: 90.179.201.–
Jan
~ Anonymní uživatel
187 příspěvků
8. 6. 2014   #4
-
0
-

#2 p3can
Díky, že ses na to podíval...já vím že to mám směšně udělaný :D asi bych to uměl pak překopat na podprocedury - jenže tohle je něco jako pracovní verze, já si na tom testuju, jestli by ten algoritms vůbec šlapal.

Takže to beru na vědomí, že to nazívám generátorem čísel, ale vlastně dělá to všechno možný...předělám.

No potom volám tu proceduru po zmáčknutí tlačítka generuj, takže vlastně program vyplní tu mřížku hodnotami z pole a pak bych chtěl aby hned našel největší a teď jen pracovně mi tu vzdálenost vyhodil ve zprávě. Tu taky volám po zmáčknutí tlačítka...

Jenže jde o to, že mi to nedělá kombinaci všech bodů...aby pro první bod vyzkoušel všechny kombinace až do posledního, pak přeskočil na druhý a zase udělal kombinace se všemy zbývajícími, takhle až do konce...a ja dělám chybu v tom jak mam nadeklarovat to, aby vždy poskočil na další bod, tam chvilku setrval a projel zbytek...ten skok mi prostě nevychází...protože mi to vždy udělá jen všechny kombinace s tím úplně posledním (a já to vůbec nechápu jak)...

zjistil jsem to kontrolu počítal jsem si to znova v excelu :) takže ten program počítá správně, jenže pouze vzhledem k poslednímu bodu

určitě to musí být strašný na tohle koukat, ale já se tím živit nebudu, a není to pro mě zas úplně jednoduchý ;)    

Nahlásit jako SPAM
IP: 178.255.168.–
Kit+15
Guru
8. 6. 2014   #5
-
0
-

#3 Sniper
Nenech se mýlit. Semestrálka - to je půl stránky kódu a k tomu 10 stránek keců kolem toho :)

Doporučil bych při hledání minimální vzdálenosti nepoužívat funkci sqrt().

Nahlásit jako SPAM
IP: 46.174.34.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Jan
~ Anonymní uživatel
187 příspěvků
8. 6. 2014   #6
-
0
-

Díky za ten program,

je to super takhle vidět celý, jenže to asi nemůžu použít.

Ale zkusím se podle toho trochu řídit.

Nahlásit jako SPAM
IP: 178.255.168.–
Sniper
~ Anonymní uživatel
215 příspěvků
8. 6. 2014   #7
-
0
-

#5 Kit
Pravda s tou semestrálkou. Ale jak bys tedy počítal druhou odmocninu? Jediné, co mě napadá je Math.Power(N,0.5). Případně, pokud by šlo jenom o porovnání a vlastní vzdálenost by mě nezajímala, tak by se odmocnění mohlo vypustit úplně.

Nahlásit jako SPAM
IP: 90.179.201.–
Sniper
~ Anonymní uživatel
215 příspěvků
8. 6. 2014   #8
-
0
-

Mimochodem koukám že jsem sem dal blbej kus kódu, tohle vyhodí největší vzdálenost, funkce ShortestDistance má vypadat takhle: 

Function ShortestDistance(Points: TPoints; out Pt1Idx,Pt2Idx: Integer): Double;
var
  i,j:      Integer;
  Distance: Double;
begin
Pt1Idx := -1;
Pt2Idx := -1;
Result := MAXDOUBLE;
For i := Low(Points) to Pred(High(Points)) do
  For j := Succ(i) to High(Points) do
    begin
      Distance := Sqrt(Sqr(Points[i].X - Points[j].X) + Sqr(Points[i].Y - Points[j].Y));
      If Distance < Result then
        begin
          Result := Distance;
          Pt1Idx := i;
          Pt2Idx := j;
        end;
    end;
end;
Nahlásit jako SPAM
IP: 90.179.201.–
Jan
~ Anonymní uživatel
187 příspěvků
8. 6. 2014   #9
-
0
-

#8 Sniper
A tobě to takhle fungovalo? Já jsem to udělal skoro stejně a vyskakuje mi vždy jen to, jak jsou od sebe daleko první dva. :-/

Nahlásit jako SPAM
IP: 178.255.168.–
Sniper
~ Anonymní uživatel
215 příspěvků
8. 6. 2014   #10
-
0
-

Teda neověřoval jsem to matematicky, ale zdá se mi, že to funguje. Je otázka co jsi tam změnil. Taky se nenech zmást "Point 1" & "Point 2", jejich indexy jsou až za křížkem.

Nahlásit jako SPAM
IP: 90.179.201.–
Jan
~ Anonymní uživatel
187 příspěvků
8. 6. 2014   #11
-
0
-

Já myslím, že je to vzásadě to samé, nebo ne?

Zase tam nemám ještě všechno a ty hodnoty si nechám jen tak ledabyle ukázat ve zprávě - no jestli jsem to špatně pochytil z toho tvého kódu a něco důležitého chybí, že se to kvůli tomu nerozchodí, tak jsem si toho zatím nevšim.

Tady je tedy celý můj...akorát že vůbec neporovnává všechny kombinace

unit dva_body_nearest;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, Math;

const

Max_pocet = 100;
Pocet_souradnic = 2;

type
  Tpole = array [1..Pocet_souradnic,1..Max_Pocet] of real;
  TfrmHlavni = class(TForm)
    btnGeneruj: TButton;
    edtPocet: TEdit;
    edtMIN: TEdit;
    edtMAX: TEdit;
    sgPole: TStringGrid;
    Memo1: TMemo;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure btnGenerujClick (Sender : TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmHlavni     : TfrmHlavni;
  Pole          : Tpole;
  n,i,j         : integer;
  PrvniIndex    : integer;
  DruhyIndex    : integer;
  MinVzdalenost : double;
implementation

{$R *.dfm}

procedure NahodneGeneruj (var Pole:Tpole; sgpole : TStringGrid; n : integer);
var
Minimum, maximum : integer;
i,j : integer;
begin
  Randomize;
    n:= StrToInt (frmHlavni.edtPocet.text);
    Minimum := StrToInt (frmHlavni.edtMIN.text);
    Maximum := StrToInt (frmHlavni.edtMAX.text);

    sgPole.ColCount := 2;
    sgPole.RowCount := n;

      for i := 1 to 2 do
        for j := 1 to n do

          Pole [i,j] := RoundTo (Minimum + Random* (Maximum-Minimum),-2);


      for i := 0 to n do
        for j := 0 to 2 do

          begin
            sgPole.Cells[j,i] := FloatToStr(Pole[j+1,i+1]);
          end;

end;

Function NejblizsiVzdalenost (Pole : Tpole; out PrvniIndex, DruhyIndex : integer):double;
var
i,j           : integer;
Vzdalenost    : double;
begin
PrvniIndex := -1;
DruhyIndex := -1;
Result     := MaxDouble;
  for i := Low(Pole) to Pred(High(Pole)) do
    for j:= Succ(i) to High(Pole) do
      begin
        vzdalenost := sqrt(sqr(Pole[1,i]-Pole[1,j])+sqr(Pole[2,i]-Pole[2,j]));
        if vzdalenost < Result then
          begin
            Result := vzdalenost;
            PrvniIndex := i;
            DruhyIndex := j;

          end;
      end;
end;

procedure TfrmHlavni.btnGenerujClick(Sender: TObject);
begin
NahodneGeneruj (pole,sgpole,n);
Showmessage (FloatToStr(NejblizsiVzdalenost(Pole,PrvniIndex,DruhyIndex)));
Showmessage (FloatToStr (PrvniIndex)+' , '+FloatToStr(DruhyIndex))
end;

end.
Nahlásit jako SPAM
IP: 178.255.168.–
Kit+15
Guru
8. 6. 2014   #12
-
0
-

#7 Sniper
Přesně. Jde-li pouze o porovnání, odmocnina se dá úplně vypustit. Případně se dá odmocnit až samotný výsledek. Je to jedna z mála optimalizací, které mají skutečný smysl. Našel jsem pro to i speciální metodu v C# přímo v manuálu od Microsoftu i s doporučením.

Nahlásit jako SPAM
IP: 46.174.34.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Sniper
~ Anonymní uživatel
215 příspěvků
8. 6. 2014   #13
-
+1
-
Zajímavé
Kit +

Hooo, to je ale divočina. Tak popořádku...

  • nepoužívej typ real (beztak se to castne na double)
  • proč nepoužíváš dynamický array?
  • TPole máš daný nebo je to tvoje práce? Nějak jsem nepochopil proč to vypadá jak to vypadá (dvourozměrné pole 2x100).
  • nepřistupuj v běžných procedurách k vnějším instancím objektů; potřebuješ-li je, předej je parametrem
  • není-li to nezbytně nutné, nepoužívej nikdy globální proměnné
  • pokud převádíš textový vstup od uživatele, nikdy nepoužívej StrToXXX, ale TryStrToXXX nebo StrToXXXDef

Hlavní problém je, jak máš nadefinovaný to pole - pleteš si pak indexy a proto ti to vyhazuje hovadiny. Pokud chceš mít souřadnice jako float, ne jako integer co mám já, tak ho nadeklaruj třeba takhle: 

type
  TFloatPoint = record
    X: Single;
    Y: Single;
  end;

  TPoints = Array of TFloatPoint;


A nebo, pokud mermomocí potřebuješ proměnlivý počet složek souřadnice, to můžeš nadeklarovat třeba: 

type
  TFloatPoint = Array[0..ElementsCount - 1] of Single;

  TPoints = Array of TFloatPoint;

Každopádně si změň to pole, uvidíš že se v tom pak sám líp vyznáš.

Nahlásit jako SPAM
IP: 90.179.201.–
Jan
~ Anonymní uživatel
187 příspěvků
9. 6. 2014   #14
-
0
-

Jo, měl jsem to hodně zmotaný...právě v tom poli a jeho indexech. já to změnil ještě, než jsem si to přečetl od tebe

Mě napadlo, že sice používám ty šikovné operátory pro inkrementaci podle tebe, ale že nejspíš nejdou použít pro dvojrozměrné pole, když nebude vědět jakou hodnotu z těch dvou indexu po něm žádám. Tak jsem to upravil a hlavně jsem si všiml, že v té funkci pro hledání vzdáleností nemám pro n přiřazenou žádnou hodnotu...a já to celou dobu přes něj zkoušel (achjo) ...i to jsem tam dodal, a teď to běží...   samozřejmě je to pořád asi dost zbastlený, ale já mám hlavně radost, že to sype výsledky :))

Takže už mi to jde i s tím mým konstantním polem (vlastně jsem nikdy nepochopil, proč je zadaný konstantama, ale můžu do něj ukládat víc hodnot, než je právě velikost toho pole...jen si musím dávat pozor, že když jich zadám méně, tak se ve zbytku objevují nuly...nj vlastně je to dost nešikovný, ale já nevím, jestli se tím mám ještě zabývat, moc času mi nezbývá)...popravdě jiný, než s tou konstantou, neumím :) dynamický jsem se neučil

Takže díky za všechny ty tipy, vezmu si to k srdci a zkusim to podle toho trochu vyladit. Pomohl jsi mi!

P.S.: nevim, jestli je to možny, ale zatim jsem to vyřešil takhle intuitivně (funguje to):

Function NejblizsiVzdalenost (Pole : Tpole; out PrvniIndex, DruhyIndex : integer):double;
var
  j,k        : integer;
  Vzdalenost : double;
begin
n          := StrToInt (frmHlavni.edtPocet.text);
PrvniIndex := -1;
DruhyIndex := -1;
Result     := MaxInt;
for j := Low(Pole[j]) to Pred(n) do
  for k := Succ(j) to High(Pole[j]) do
    begin
      vzdalenost := sqrt(sqr(Pole[1,j]-Pole[1,k])+sqr(Pole[2,j]-Pole[2,k]));
      if vzdalenost < Result then
        begin
          Result     := vzdalenost;
          PrvniIndex := j;
          DruhyIndex := k;
        end;
    end;
end;
Nahlásit jako SPAM
IP: 178.255.168.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 5 hostů

Podobná vlákna

Zamotane cykly — založil blibli

C Cykly, 5 operací — založil Lukáš

Tkinter a cykly — založil Spectator

Problém - cykly — založil crAzY^

Cykly s promennymi — založil Petrr

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý