Beliebig viele Werte in Array zwischenspeichern

The_Virus

Mitglied
Ich soll mal wieder ein Programm für die Uni schreiben. Es geht um die Berechnung von Rationalen Zahlen. In meinem Programm wird eine Rechnung ausgeführt z.B. Bruch1 + Bruch2 und das Ergebnis ausgegeben. Die Aufgabe (Bruch1 + Bruch2 = Ergebnis) soll nun in einem Array gespeichert werden. Danach wird abgefragt, ob nochmal gerechnet werden soll und das Programm läuft von vorne. Wenn man beenden will (Abfrage auf "nein") soll das Programm alle gespeicherten Aufgaben nochmal ausgeben. Doch ein Array hat eine feste Länge und ist nicht variabel. Wenn ich nun mein Array auf 5 festlege und 6 Berechnungen durchführe, gibt es ExceptionOutOfBounds.

Eine mögliche Lösung wäre eine ArrayList, denn die ist variabel. Doch in der Aufgabe steht eigentlich explizit Array nicht ArrayList. Und vielleicht gibt es ja da einen Trick, um das doch mit einem Array zu lösen ?!
Eine andere unschöne aber simple Lösung wäre, dem Array einfach 1000 Stellen zu geben und dann am Ende alle null Stellen irgendwie "abzuschneiden" bzw. sie einfach nicht auszugeben.

Hier mal die main() zu meinem Prog. Hab es jetzt erstmal mit ArrayList gelöst.
Java:
package paketRationaleZahlen;
import java.util.ArrayList;

public class Start {

	public static void main(String[] args) {
		
		RationaleZahl bruch1 = new RationaleZahl(0,0);
		RationaleZahl bruch2 = new RationaleZahl(0,0);
		ArrayList<String> rechnungListe = new ArrayList<String>();
		int durchlauf = 1;
		
		do{
			bruch1 = Rechnung.einlesen();
			Rechnung.operation();
			bruch2 = Rechnung.einlesen();
			if(Rechnung.getOperator().equals("+")) {
				System.out.println(Rechnung.addieren(bruch1, bruch2));
				rechnungListe.add(Rechnung.addieren(bruch1, bruch2));
			}
			if(Rechnung.getOperator().equals("-")) {
				System.out.println(Rechnung.subtrahieren(bruch1, bruch2));
				rechnungListe.add(Rechnung.subtrahieren(bruch1, bruch2));
			}
			if(Rechnung.getOperator().equals("*")) {
				System.out.println(Rechnung.multiplizieren(bruch1, bruch2));
				rechnungListe.add(Rechnung.multiplizieren(bruch1, bruch2));
			}
			if(Rechnung.getOperator().equals("/")) {
				System.out.println(Rechnung.dividieren(bruch1, bruch2));
				rechnungListe.add(Rechnung.dividieren(bruch1, bruch2));
			}
			Rechnung.weiter();
			durchlauf++;
		}while(Rechnung.getWeiter().equals("j"));
		
		if(Rechnung.getWeiter().equals("n")) {
			System.out.println("--------Berechnet wurden--------");
			System.out.println(rechnungListe);
		}	
	}
}
Was meint ihr?
 
...wenn das Array voll ist, ein größeres Array zu erstellen und die Werte rüberkopieren.
Ich hab mich da nochmal eingelesen, und Logaff hat Recht, die ArrayList macht genau das. Denn sie hat intern ein Array mit bestimmter Größe, legt ein neues größeres an, wenn das erste voll ist, und kopiert die Werte ins neue Array.

Daher werde ich doch bei der Arraylist bleiben. Das ist nicht nur deutlich einfacher, weil es mir die "Arbeit abnimmt", sondern auch viel eleganter, weil es weniger Code ist.
 
Unsere Professorin ist da nicht so streng. Solange ich erklären kann, was die ArrayList macht und wie ich das in einem Code verwende, dürfen wir das auch verwenden. Denn wir müssen alle unsere Aufgaben präsentieren, ihr den gesamten Code erklären und vorführen.

Aber rein aus Interesse, wie würde ich denn diese ArrayList Logik selbst programmieren? Also wann weiß das Array, dass es voll ist?
Neues Array anlegen und Werte rüber kopieren sollte ja kein Problem sein. Aber woher weiß das neue Array, an welcher Stelle es dann fortsetzen soll?
 
Ein Quick and dirty Ansatz

Java:
public class ArrayDemo {

	private int[] arr;
	private int lastSet;
	private final int capInc;

	ArrayDemo(int initialCapacity, int capacityIncrement) {
		arr = new int[initialCapacity];
		lastSet = -1;
		capInc = capacityIncrement;
	}

	public void add(int i) {
		if (lastSet == arr.length-1) {
			int[] tmp = new int[arr.length+capInc];
			System.arraycopy(arr, 0, tmp, 0, arr.length);
			arr = tmp;
		}
		arr[++lastSet] = i;
	}

	@Override
	public String toString() {
		String retVal = "[ ";
		for (int i=0; i<=lastSet; i++) {
			retVal += i + " ";
		}
		retVal += "]";
		return retVal;
	}

	public static void main(String[] args) {
		ArrayDemo arrd = new ArrayDemo(1, 2);
		for (int i=0; i<5; i++) {
			arrd.add(i);
			System.out.println(arrd);
		}
	}
}

Ein wesentlich besseres Beispiel, das aber möglicherweise nicht so einfach zu verstehen ist, findest du wohl im Sourceode der ArrayList 🙂
 
Danke für deine Lösung, dennoch verstehe ich sie nicht so ganz. Ist mir irgendwie zu komplex, zu viele Variablen.
Da bleib ich doch lieber bei ArrayList.
 
Der spannende Teil ist der hier:
Java:
        if (lastSet == arr.length-1) {
            int[] tmp = new int[arr.length+capInc];
            System.arraycopy(arr, 0, tmp, 0, arr.length);
            arr = tmp;
        }
In der ArrayList passiert das ähnlich, nur dass da meines Wissens nach mit nem Faktor multipliziert wird.
Analog wird das Array wieder verkleinert wenn wenig werte drin stehen.
 
was bedeudet "arr = tmp" ?
Wird arr dabei mit dem neuen Array tmp überschrieben?

Hab den speziellen Teil mal übernommen und es läuft auch irgendwie. Das Programm kann zwei Rechnungen speichern, obwohl das erste Array nur einen Speicherplatz hat. Dennoch kommt danach ein NullPointerException.
Java:
package paketRationaleZahlen_Test;

public class Start_Test {

	public static void main(String[] args) {
		
		RationaleZahl_Test bruch1 = new RationaleZahl_Test(0,0);
		RationaleZahl_Test bruch2 = new RationaleZahl_Test(0,0);
		String[] rechListe = new String[1];
		int durchlauf = 0; // Zaehler, wie viele Werte geschrieben wurden
		
		do{
			bruch1 = Rechnung_Test.einlesen();
			Rechnung_Test.operation();
			bruch2 = Rechnung_Test.einlesen();
			// geänderter Teil
			if(durchlauf >= rechListe.length) {
				String[] tempListe = new String[rechListe.length + 1];
				System.arraycopy(rechListe, 0, tempListe, 0, rechListe.length);
				rechListe = tempListe;
			} //bis hier		
			if(Rechnung_Test.getOperator().equals("+")) {	
				rechListe[durchlauf] = Rechnung_Test.addieren(bruch1, bruch2);
				System.out.println(rechListe[durchlauf]);
			}
			if(Rechnung_Test.getOperator().equals("-")) {
				rechListe[durchlauf] = Rechnung_Test.subtrahieren(bruch1, bruch2);
				System.out.println(rechListe[durchlauf]);
			}
			if(Rechnung_Test.getOperator().equals("*")) {
				rechListe[durchlauf] = Rechnung_Test.multiplizieren(bruch1, bruch2);
				System.out.println(rechListe[durchlauf]);
			}
			if(Rechnung_Test.getOperator().equals("/")) {
				rechListe[durchlauf] = Rechnung_Test.dividieren(bruch1, bruch2);
				System.out.println(rechListe[durchlauf]);
			}
			durchlauf++;
			Rechnung_Test.weiter();
		}while(Rechnung_Test.getWeiter().equals("j"));
		
		if(Rechnung_Test.getWeiter().equals("n")) {
			System.out.println("--------Berechnet wurden--------");
			for(int i = 0; i < durchlauf; i++) {
				System.out.println(rechListe[i]);
			}
		}	
	}
}
 
Zuletzt bearbeitet:
Na wenn das schon zu komplex ist, viel Spass für die Zukunft ....

Also was
Code:
arr
ist, dürfte ja klar sein. Das ist die Referenz auf den produktiven Array.
Wenn der voll ist, lege ich einen neuen Array an (Arraylist berechnet die neue Länge natürlich etwas komplexer) Die Referenz
Code:
tmp
zeigt da drauf (ich brauche ja den alten noch, weil da die Werte drin stehen)
Dann kopiere ich den Inhalt von arr nach tmp.

Die Zeile
Code:
arr = tmp
bewirkt nur, dass die Referenz arr jetzt auf den neuen Array zeigt.
Der Alte liegt noch im Speicher herum, wird aber bei nächster Gelegenheit vom GarbageCollector weggeräumt.

Code:
lastSet
oder etwas ähnliches brauchst du zwingend auch, sonst weisst du ja nicht wieviele Element du schon geschrieben hast und
Code:
capInc
ist keine Variablen sondern Konstanten die das Testen vereinfacht - die Anfangsgrösse und das Inkrement würde ich natürlich niemals so klein wählen, aber es hilft beim Testen.

Das erstens für das Verständnis und zweitens falls du doch Array verwenden müsstest.

ArrayList ist natürlich so nett und führt das alles schön brav mit, ist also sicher besser geeignet für dich, ausser eben das Ziel der Übung wäre genau diesen Mechanismus zu implementieren um ihn zu verstehen.
 
Zuletzt bearbeitet:
Danke nochmal für deine Erklärung. Ich hab meine main() nun korrigiert und es läuft genau so, wie ich mir das vorgestellt hatte. Diesen Teil hab ich hinzugefügt:
Java:
if(durchlauf >= rechListe.length) {
	String[] tempListe = new String[rechListe.length + 1];
	System.arraycopy(rechListe, 0, tempListe, 0, rechListe.length);
	rechListe = tempListe;
}
Code:
durchlauf
ist bei mir der Zaehler, wie bei dir
Code:
lastSet
.
 
Zuletzt bearbeitet:
Vector ist auch nicht deprecated. Vector ist halt eine synchroniserte Liste. Das letzte was der Vector genießen durfte war die Implementierung des List-Interfaces.
 

Zurück
Oben