Entwickler-Ecke

Sonstiges (Delphi) - Sortieren eines Arrays auf Basis eines anderen Arrays


Xardas008 - Do 29.03.07 12:04
Titel: Sortieren eines Arrays auf Basis eines anderen Arrays
Hi ihr,

das Problem klingt komplizierter als es ist. Ich bin gerade einen Taschenrechner am programmieren, der auch Punkt vor Strichrechnung beherrscht.
Funktioniert soweit auch schon ganz gut.
Nur an einer Stelle hapert es, der Array, wo ich die eingegebenen Zahlen aus dem Editfeld drin speichere, müssen umsortiert werden, da ich intern Klammern in das Operatorenarray einfüge, wenn der Operator ein * oder ein / ist, damit der dies zuerst rechnet.

Das Problem durch die Klammern ist dann, dass die Reihenfolge der Zahlen nicht mehr stimmt, sie müssen neu sortiert werden.

Für die Rechnung 1 + 2x3 - 1/2 +6 muss der Taschenrechner intern folgendes machen, er rechnet erst 2x3, dazu addiert er die 1. Um jetzt 1/2 rechnen zu können, müssen beide Elemente im Array um 1 nach hinten geschoben werden (alle dahinter natürlich auch), um dann die +6 zu rechnen, muss die 6 ein weiteres mal nach hinten geschoben werden, usw.

Irgendwie bekomme ich die Prozedur dafür nicht so recht hin, wollte das ganze Rekursiv lösen, wobei beide Arrays dieser Prozedur übergeben werden müssen.

Hoffe dass ich mit Eurer Hilfe das hinbekomme, dann kann ich auch noch nachträglich Klammernsetzung einfügen (weil die sind nach mathematischen Gesetzen ja noch vor dem Punkt (* oder /) zu lösen.

Mit freundlichen Grüßen

Xardas008


Edit: Liefere euch hier mal eben die prozeduren GetNumber und SetOperator, wo die beiden Arrays gefüllt werden.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
function TFrm_Taschenrechner.GetNumbers(vNumber:STRING):Number;
var i, k:INTEGER;
    dummy:REAL;
    dummy3 :ARRAY[1..40of REAL;
    dummy2 :StringArray;
    dummy4 :char;
begin
   j := 0;
   for i := 1 to Length(vNumber) do
   begin

     if not(vNumber[i] = '|'then
     begin

         if vNumber[i] = '|' then
         begin
         inc(j);
         end
         else
         begin

           inc(j);
           Number2[j] := StrToFloat(vNumber[i]);
         end;
     end;
   end;
   result := Number2;
end;

function TFrm_Taschenrechner.SetOperator(Operator :STRING):StringArray;
var i:INTEGER;
begin
   k:= 0;
     for i := 1 to Length(Operator) do
   begin
     if not(Operator[i] = '|'then
     begin

         if Operator[i] = '|' then
         begin
         inc(k);
         end
         else
         begin
           inc(k);
           if (Operator[i]= '*'or (Operator[i] = '/'then
           begin
             vFeld[k] := '(';
             inc(k);
             vFeld[k] := Operator[i];
             inc(k);
             vFeld[k] := ')';
           end
           else
           begin
             vFeld[k] := Operator[i];
           end;
         end;
     end;
   end;
   result := vFeld;
end;


Xardas008 - Do 29.03.07 14:50

Habe folgende Schleife gebastelt, funktioniert fast, wenige Stellen erhalten einen falschen Wert. Hier die Schleife:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
for i:= 1 to Length(Operator) do
     begin
        if (Operator[i] = '('then
        begin
          for k := 1 to Length(Operator) do
          begin
          dummy3[k] := 0;
          end;
          for k:=i to Length(Operator) do
          begin
            dummy3[k] := vNumber[k+2];
          end;
          for k:=i to Length(Operator) do
          begin
            vNumber[k+3] := dummy3[k];
          end;

        end
        else
        begin
          if (Operator[i] = ')'then
          begin
            for k:= 1 to Length(Operator) do
            begin
              dummy3[k] := 0;
            end;
            for k:= i to Length(Operator) do
            begin
              dummy3[k] := vNumber[k];
            end;
            for k:=i to Length(Operator) do
            begin
              vNumber[k+1] := dummy3[k];
            end;

          end;
        end;


Bei der Beispielrechnung 1+ (2x3) - (1/2) + 6 muss die zweite 1 an Position 5 (von Pos. 4) und die 6 auf Pos. 9 von Pos. 6, an Pos. 5 landet die 1 auch, Pos. 9 erhält auch die 6, nur Position 6 erhält auch die 1, obwohl hier die 2 hingehört und pos. 7 hat dann die 2, die aber beim Rechnen nicht beachtet wird, da an der Stelle ein Operator steht der nicht abgefragt wird da es ne Klammer ist.

Am besten baue ich euch mal die Arrays hier auf.
Operator{'+','(','*',')','-','(','/',')','+',' ',...}
vNumber{1,2,3,4,5,6,0...}

Ist ziemlich kompliziert, gebe ich zu.

Wenn ihr noch Infos braucht, einfach sagen, ich bemüh mich dann diese zu liefern.


jaenicke - Do 29.03.07 16:00

Also ich werd mir das mal ansehen, aber was ich mich frage ist: Warum so kompliziert?
IMHO ist es deutlich einfacher eine Baumstruktur zu verwenden. So habe ich das auch gemacht, als ich symbolische Berechnungen durchführen wollte. Ganz nebenbei ist es so relativ einfach auch Ableiten und Integrieren einzubauen (naja Integrieren ist noch nicht fertig...).

Aber das wollte ich nur mal anmerken, deine Lösung werde ich mir mal ansehen, der Fehler muss ja zu finden sein.


Xardas008 - Do 29.03.07 17:15

Von Baumstruktur habe ich bisher noch nichts gehört, ka wie die gehen soll. Ich weiß ich programmiere irgendwie immer etwas zu kompliziert, sodass ich meistens später nicht mehr weiß was ich grade überhaupt gemacht habe lol^^


Xardas008 - Fr 30.03.07 08:48

Wo kann ich etwas über diese Baumstruktur nachlesen, vielleicht bekomme ich das Problem damit eher gelöst.


Narses - Fr 30.03.07 10:46

Moin!

Eine weitere, weit verbreitete Methode, die Operatorenrangfolge abzubilden, ist ein (Calculator-)Stack, also ein Kellerspeicher. Schau mal, ob du damit und geeigneten eigenen Klassen für Operatoren, die du dann mit den Argumenten in den Stack packst, weiter kommst. ;) Zumindest der Stack (= TStack) ist schon bei Delphi dabei. :idea:

cu
Narses


Xardas008 - Fr 30.03.07 15:07

So hab die letzten 15 Min nochmal rumexperimentiert, bis zu einer bestimmten Anzahl von Operatoren geht es gut, also oben genanntes Rechenbeispiel löst er nun richtig, aber kommt ein *2 am Ende dazu, gehts schief, dann haben wir eine Abweichung von 2, weil er statt der 6 an Pos. 10 eine 2 stehen hat.

Wie würde oben genanntes Beispiel als Baumstruktur gelöst? Oder wie kann man das sonst lösen dass der Array richtig zugeordnet wird?


Xardas008 - Mo 02.04.07 06:51

Das Problem ist immer noch nicht gelöst.


Xardas008 - Di 03.04.07 06:30

So, hab das Problem mal auf eine andere Weise gelöst, nur an einer Stelle hapert es irgendwie, wodurch eine Endlosschleife endsteht.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
while s > 0 do
  begin
    term_str := copy(Input, s+1,pos(copy(Input, s+1, length(Input)), ')')-1);
    erg := GetResult(term_str);
    Input := copy(Input, 0, s-1)+ erg + copy(Input,s+1, pos(copy(Input, s+1, length(Input)), ')')+1);
    s := Get_Pos_In_Str(Input, s, Ebene);
  end;


term_str soll bei folgendem Beispiel: 1+(2*3-(1+2))die innerste Klammer nehmen, und den Teilstring 1+2 in den term_str kopieren, nur irgendwie kopiert er dort nur einen Leeren String rein, obwohl er bei Get_Pos_In_Str die richtige Position bekommt. Warum????