Hashing

misaki

Mitglied
Hallo!!

Soll dieses Mal eine Liste für Studenten mit Matrikelnummer, Name und eMail über Hashing erzeugen.
Die Matrikelnummer ist der Schlüssel.

Die beiden Hash-Methoden (also mit Weiterstreufunktion) sind gegeben:
int hash(int k){return k%m;} //m == Laenge des arrays
int hash2(int k){return 1+k%(m-2);} //fuer Sondierfolge

Wenn 75 % erreicht sind soll das Array vergrößert werden, hierfür ist eine Folge von Primzahlen gegeben:
1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573

Soweit so gut. Ich bin mir jetzt nicht ganz sicher ob ich das mit dem Hashing richtig verstanden habe ... Aber beim hinzufügen bzw. löschen versuche ich das zuerst mit der normalen hash-Funktion, wenn der Platz aber belegt (bzw frei beim löschen) ist, versuche ich mit der hash2 funktion etwas zu finden. ich bin mir aber noch nicht sicher, was ich mache, wenn ich auch damit nichts finde.

naja, wie auch immer, mein programm hätte ich soweit fertig, aber allein das hinzufügen von studenten funktioniert schon nicht, ich erhalte immer die Ausgabe "Student konnte nicht hinzugefügt werden". Aber einen Fehler in der add-Methode kann ich nicht finden???:L

Java:
public class StudList {

	private int[] primzahlen = {1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573};
	private StudListNodes[] tabelle;
	private int anzahlStuds;
	private int aktuelleLaenge;
	
	
	public StudList() {
		aktuelleLaenge = 0;
		tabelle = new StudListNodes[primzahlen[aktuelleLaenge]];
	}
 
	public void add(int matrNr, String name, String email) {    
	/** neuer Eintrag; ueberschreibt evtl. schon vorhandenen Eintrag mit gleicher matrNr;
		requires: matrNr positiv, name und email nichtleer **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
		// wenn belegt: Matrikelnummer gleich, oder unbelegt
			tabelle[place] = new StudListNodes(matrNr, name, email);
			anzahlStuds++;
		}
		else { // sonst weiterstreuen
			place = hash2(matrNr);
			n = tabelle[place];
			if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
			// muss wieder unbelegt oder gleiche MatrNr sein
				tabelle[place] = new StudListNodes(matrNr, name, email);
				anzahlStuds++;
			}
			else {
				System.out.println("Student konnte nicht eingefuegt werden");
			}
		}
		if ((tabelle.length * 0.75) <= anzahlStuds) { // > 75% eingefügt
			aktuelleLaenge++;
			StudListNodes[] tabelle2 = new StudListNodes[primzahlen[aktuelleLaenge]];
			for (int i = 0; i < tabelle.length; i++) {
				StudListNodes x = tabelle[i];
				if (getStand(x) == 0) { // belegt, muss kopiert werden
					int platz = hash(getNr(x));
					if (getStand(tabelle2[platz]) == 0) { // wenn neuer Platz schon belegt wäre, finde anderne Platz
						platz = hash(getNr(x));
					}
					tabelle2[platz] = new StudListNodes(matrNr, name, email);
				}
			}
			this.tabelle = tabelle2;
		}	
	}

    public void delete(int matrNr) {                             
	/** loescht Eintrag; keine Wirkung, falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0) { // belegt
			n = new StudListNodes(); // leerer Knoten
			anzahlStuds--;
		}
	}

	public String giveName(int matrNr) {
		/** liefert Namen zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0) {
			return getName(n);
		}
		else {
			place = hash2(matrNr);
			n = tabelle[place];
			if (getStand(n) == 0) {
				return getName(n);
			}
			else {
				return " ";
			}
		}
	}

    public String giveMail(int matrNr) {
	/** liefert email-Adresse zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0) {
			return getMail(n);
		}
		else {
			place = hash2(matrNr);
			n = tabelle[place];
			if (getStand(n) == 0) {
				return getMail(n);
			}
			else {
				return " ";
			}
		}
	}
	
	private int hash(int k) {
		return k%(tabelle.length);
	}
	
	private int hash2(int k) {
		return 1+k%(tabelle.length-2);
	} 
	
	private String getName(StudListNodes n) {
		return n.name;
	}
	
	private String getMail(StudListNodes n) {
		return n.mail;
	}
	
	private int getNr(StudListNodes n) {
		return n.matrikelnummer;
	}
	
	private int getStand(StudListNodes n) {
		if (n == null) {
			return -1;
		}
		else {
			return n.stand;
		}
	}
	
	private class StudListNodes {
		
		int matrikelnummer;
		String name;
		String mail;
		int stand; // 0, belegt, -1 leer, -2 gelöscht
		
		StudListNodes () { // leerer Node wird erzeugt, wenn gelöscht wird
			stand = -2;
		}
		
		StudListNodes (int nr, String name, String mail) {
			matrikelnummer = nr;
			this.name = name;
			this.mail = mail;
			stand = 0; // 0 ... belegt
		}
	}
}

ich weiß es ist ein seeehr langer code. aber ich wäre froh wenn jemand drüber schauen könnte. insbesondere über die add-methode ...
danke!
 

Dekker

Bekanntes Mitglied
Naja, der Probing Algorithmus läuft solange bis er auf ein freies Feld trifft (dabei kanns auch sein das ein gelöschtes Element drinnsteht) oder den nötigen Schlüssel findet beim löschen. Dann wird allerdings nur gelöscht markiert, sonst nix. Erst beim Rehashen werden die nichtmehr mit eingefügt.

Der Füllfaktor von 75% bedeutet du fügst einen Wert in die Tabelle ein und überprüfst dann ob der Array zu 75% belegt ist, falls ja musst du rehashen, falls nein musst du nix tun.
 

misaki

Mitglied
Ich versteh jetzt nicht wirklich, was du mir damit sagen willst :oops:
beim Löschen wird bei mir übrigens nicht nur als gelöscht markiert sondern einfach ein neuer Knoten erzeugt, bei dem der Stand allerdings als gelöscht markiert ist.

das mit dem Füllfaktor habe ich verstanden. Ich überprüfe nach jedem Einfügen ob 75 % erreicht sind, falls ja erzeuge ich ein neues Array mit der nächsten Primzahl und hashe alles neu. Aber sonst .. .??
 

Dekker

Bekanntes Mitglied
Ok, beim hinsehen:

hash(blubb) ist die Hashfunktion, hash2 ist deine Probingfunktion (zu deutsch sondierfunktion).

Jetzt überleg mal was passiert wenn du 3 mal was in die Tabelle einfügst das den gleichen Hash hat? Nehmen wir mal folgendes Beispiel:

Arraylänge: 7
Matrikelnummer 1: 3
Matrikelnummer 2: 10
Matrikelnummer 3: 17

Was macht dein Algorithmus wenn du MtK 1 und Mtk 2 eingefügt hast und MtK 3 einfügen willst? Richtig, du gibst deinen Fehler aus. Macht das Sinn? Nein macht es nicht... Der Probing Algorithmus wird solange aufgerufen bis er ein freies Feld in der Tabelle findet. Du sollst hash2 eigentlich nicht mit der Matrikelnummer aufrufen sondern mit dem Index den du gerade berechnet hast. Und wenn an der Stelle die er dann ausrechnet wieder belegt ist, dann berechnest du eine weitere Adresse mit hash2 usw. Bis du ein leeres Feld gefunden hast. Kann nicht eingefügt werden gibts nicht, außer der Key ist komplett Identisch... Was du machst is einfach 2 mal Probieren obs reingeht, und wenn nicht dann Tschüss.

So, warum darf man nicht direkt einfach löschen sondern muss als gelöscht markieren:
Wenn du Daten suchen möchtest, und berechnest mittels hash die erste Position wo sie stehen könnten und sie sind nicht da, dann verfährst du wie beim einfügen mittels hash2 bis du ein leeres Feld gefunden hast. Stell dir mal den Fall mit den oben genannten Daten vor.

add(mtk1);
add(mtk2);
add(mtk3);
delete(mtk2);
getName(mtk3);
=> sollte zurückgeben das der Name nicht vorhanden ist, denn dadurch dass du mtk2 gelöscht und das Feld als leer markierst, endet der Probingalgorithmus nach dem ersten Versuch. Deshalb dürfen Felder nur leer MARKIERT werden, nicht gelöscht, sonst funktioniert das Sondieren nicht mehr. Erst beim Rehashen werden als gelöscht merkierte Arrayinhalte endgültig gelöscht, da sie nicht wieder in die Tabelle eingefügt werden.

Ich hoffe es ist halbwegs verständlich, bin sehr müde grad und hab keine Lust auf rächtschraibunk zu achten grad...
 

misaki

Mitglied
So weit so gut, das versteh ich jetzt endlich.
Aber mir ist noch nicht ganz klar wie ich beim Weiterstreuen vorgehen soll, damit ich keine Endlosschleife erhalte, insbesondere beim Löschen. Denn wenn die matrNr nicht vorkommt, wird nie ein belegter Platz gefunden (und danach suche ich momentan nur, ein belegter Platz bei dem die Matrikelnummer stimmt). Wie mache ich das denn dann???

Java:
public class StudList {

	private int[] primzahlen = {1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573};
	private StudListNodes[] tabelle;
	private int anzahlStuds;
	private int aktuelleLaenge;
	
	public StudList() {
		aktuelleLaenge = 0;
		tabelle = new StudListNodes[primzahlen[aktuelleLaenge]];
	}
 
	public void add(int matrNr, String name, String email) {    
	/** neuer Eintrag; ueberschreibt evtl. schon vorhandenen Eintrag mit gleicher matrNr;
		requires: matrNr positiv, name und email nichtleer **/
		int place = hash(matrNr); // finde Position
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
		// wenn belegt: Matrikelnummer gleich, oder unbelegt
			tabelle[place] = new StudListNodes(matrNr, name, email);
			anzahlStuds++;
		}
		else { // sonst weiterstreuen
			while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
				place = hash2(place);
				n = tabelle[place];
			}
			if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
			// muss wieder unbelegt oder gleiche MatrNr sein
				tabelle[place] = new StudListNodes(matrNr, name, email);
				anzahlStuds++;
			}
			else {
				System.out.println("Student konnte nicht eingefuegt werden");
			}
		}
		if ((tabelle.length * 0.75) <= anzahlStuds) { // > 75% eingefügt
			aktuelleLaenge++;
			StudListNodes[] tabelle2 = new StudListNodes[primzahlen[aktuelleLaenge]];
			for (int i = 0; i < tabelle.length; i++) {
				StudListNodes x = tabelle[i];
				if (getStand(x) == 0) { // belegt, muss kopiert werden
					int platz = hash(getNr(x));
					if (getStand(tabelle2[platz]) == 0) { // wenn neuer Platz schon belegt wäre, finde anderen Platz
						while (getStand(tabelle2[platz]) == 0) {
							platz = hash(platz);
						}
					}
					tabelle2[platz] = new StudListNodes(matrNr, name, email);
				}
			}
			this.tabelle = tabelle2;
		}	
	}

    public void delete(int matrNr) {                             
	/** loescht Eintrag; keine Wirkung, falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0) { // belegt
			tabelle[place] = new StudListNodes(); // leerer Knoten
			anzahlStuds--;
		}
		else { // weiterstreuen
			place = hash2(place);
			while (getStand(tabelle[place]) != 0) {
				place = hash2(place);
			}
			tabelle[place] = new StudListNodes();
			anzahlStuds--;
		}
	}

	public String giveName(int matrNr) {
		/** liefert Namen zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
			return getName(n);
		}
		else {
			while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
				place = hash2(place);
			}
			n = tabelle[place];
			if (getStand(n) == 0) {
				return getName(n);
			}
			else {
				return " ";
			}
		}
	}

    public String giveMail(int matrNr) {
	/** liefert email-Adresse zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
			return getMail(n);
		}
		else {
			while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
				place = hash2(place);
			}
			n = tabelle[place];
			if (getStand(n) == 0) {
				return getMail(n);
			}
			else {
				return " ";
			}
		}
	}
	
	private int hash(int k) {
		return k%(tabelle.length);
	}
	
	private int hash2(int k) {
		return 1+k%(tabelle.length-2);
	} 
	
	private String getName(StudListNodes n) {
		return n.name;
	}
	
	private String getMail(StudListNodes n) {
		return n.mail;
	}
	
	private int getNr(StudListNodes n) {
		return n.matrikelnummer;
	}
	
	private int getStand(StudListNodes n) {
		if (n == null) {
			return -1;
		}
		else {
			return n.stand;
		}
	}
	
	private class StudListNodes {
		
		int matrikelnummer;
		String name;
		String mail;
		int stand; // 0, belegt, -1 leer, -2 gelöscht
		
		StudListNodes () { // leerer Node wird erzeugt, wenn gelöscht wird
			stand = -2;
		}
		
		StudListNodes (int nr, String name, String mail) {
			matrikelnummer = nr;
			this.name = name;
			this.mail = mail;
			stand = 0; // 0 ... belegt
		}
	}
}
 
Zuletzt bearbeitet:

Dekker

Bekanntes Mitglied
Wie zuvor beschrieben: einfügen, suchen und löschen laufen solange, bist du entweder den Schlüssel (was hier die MtKNr ist) gefunden oder ein leeres Feld gefunden hast. Beim einfügen zählen auch als gelöscht markierte Felder als leer, aber auch wirklich NUR beim einfügen.
 

misaki

Mitglied
okay, das hätte ich auch so gemacht:oops: nur irgendwo habe ich eine endlosschleife.
würds gern debuggen aber mit jdb funktionierts nicht besonders gut ;) irgendne empfehlung womit ich das machen könnte? sonst wär ich froh wenn jemand drüber schauen könnte.

Java:
public class StudList {

	private int[] primzahlen = {1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573};
	private StudListNodes[] tabelle;
	private int anzahlStuds;
	private int aktuelleLaenge;
	
	public StudList() {
		aktuelleLaenge = 0;
		tabelle = new StudListNodes[primzahlen[aktuelleLaenge]];
	}
 
	public void add(int matrNr, String name, String email) {    
	/** neuer Eintrag; ueberschreibt evtl. schon vorhandenen Eintrag mit gleicher matrNr;
		requires: matrNr positiv, name und email nichtleer **/
		int place = hash(matrNr); // finde Position
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
		// wenn belegt: Matrikelnummer gleich, oder unbelegt
			tabelle[place] = new StudListNodes(matrNr, name, email);
			anzahlStuds++;
		}
		else { // sonst weiterstreuen
			while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
				place = hash2(place);
				n = tabelle[place];
			}
			if (getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0) { 
			// muss wieder unbelegt oder gleiche MatrNr sein
				tabelle[place] = new StudListNodes(matrNr, name, email);
				anzahlStuds++;
			}
			else {
				System.out.println("Student konnte nicht eingefuegt werden");
			}
		}
		if ((tabelle.length * 0.75) <= anzahlStuds) { // > 75% eingefügt
			aktuelleLaenge++;
			StudListNodes[] tabelle2 = new StudListNodes[primzahlen[aktuelleLaenge]];
			for (int i = 0; i < tabelle.length; i++) {
				StudListNodes x = tabelle[i];
				if (getStand(x) == 0) { // belegt, muss kopiert werden
					int platz = hash(getNr(x));
					if (getStand(tabelle2[platz]) == 0) { // wenn neuer Platz schon belegt wäre, finde anderen Platz
						while (getStand(tabelle2[platz]) == 0) {
							platz = hash(platz);
						}
					}
					tabelle2[platz] = new StudListNodes(matrNr, name, email);
				}
			}
			this.tabelle = tabelle2;
		}	
	}

    public void delete(int matrNr) {                             
	/** loescht Eintrag; keine Wirkung, falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr) { // belegt und richtige Matrikelnummer
			tabelle[place] = new StudListNodes(); // leerer Knoten
			anzahlStuds--;
		}
		else { // weiterstreuen
			place = hash2(place);
			while (getStand(tabelle[place]) != -1 || ! (getStand(tabelle[place]) == 0 && tabelle[place].matrikelnummer == matrNr)) {
				place = hash2(place);
			}
			tabelle[place] = new StudListNodes();
			anzahlStuds--;
		}
	}

	public String giveName(int matrNr) {
		/** liefert Namen zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
			return getName(n);
		}
		else {
			if (getStand(n) == 0) { // nur weitersuchen wenn das Feld belegt, aber falsch war
				while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
					place = hash2(place);
				}
				n = tabelle[place];
				if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
					return getName(n);
				}
				else {
					return " ";
				}
			}
			else { return " "; }
		}
	}

    public String giveMail(int matrNr) {
	/** liefert email-Adresse zu Matrikelnummer; leerer String falls matrNr nicht vorkommt; **/
		int place = hash(matrNr);
		StudListNodes n = tabelle[place];
		if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
			return getMail(n);
		}
		else {
			if (getStand(n) == 0) { // nur weitersuchen wenn das Feld belegt, aber falsch war
				while (!(getStand(n) == 0 && n.matrikelnummer == matrNr || getStand(n) != 0)) {
					place = hash2(place);
				}
				n = tabelle[place];
				if (getStand(n) == 0 && n.matrikelnummer == matrNr) {
					return getMail(n);
				}
				else {
					return " ";
				}
			}
			else { return " "; }
		}
	}
	
	private int hash(int k) {
		return k%(tabelle.length);
	}
	
	private int hash2(int k) {
		return 1+k%(tabelle.length-2);
	} 
	
	private String getName(StudListNodes n) {
		return n.name;
	}
	
	private String getMail(StudListNodes n) {
		return n.mail;
	}
	
	private int getNr(StudListNodes n) {
		return n.matrikelnummer;
	}
	
	private int getStand(StudListNodes n) {
		if (n == null) {
			return -1;
		}
		else {
			return n.stand;
		}
	}
	
	private class StudListNodes {
		
		int matrikelnummer;
		String name;
		String mail;
		int stand; // 0, belegt, -1 leer, -2 gelöscht
		
		StudListNodes () { // leerer Node wird erzeugt, wenn gelöscht wird
			stand = -2;
		}
		
		StudListNodes (int nr, String name, String mail) {
			matrikelnummer = nr;
			this.name = name;
			this.mail = mail;
			stand = 0; // 0 ... belegt
		}
	}
}
 

Dekker

Bekanntes Mitglied
Hast du ein Beispiel bei dems passiert? Maybe kuck ichs mir morgen mittag mal an.

Du könntest dir btw nen Sysout beim Probing machen und kucken was hängt.
 

misaki

Mitglied
Die Aufgabenstellung war noch ein Testprogramm zu schreiben, das die Stud-List mit 1000000 zufälligen Einträgen befüllt (Strings egal, matr nummer random)
Hab darauf hin folgendes Programm geschrieben, das den Fehler (Endlosschleife) liefert:


Java:
import java.util.Random;

public class Bsp10 {
/** Testen Sie Ihre Realisierung und messen Sie auch die Performance, 
indem Sie StudList-Objekte mit Anfangs-array-Länge 1000 mit 1000000 
zufälligen Einträgen (random int-Komponente, Rest des Datensatzes egal) füllen .
**/
	public static void main(String[] args) {
		Random generator = new Random();
		int r;
		StudList liste = new StudList();
		for (int i = 0; i < 1000000; i++) {
			r = generator.nextInt();
			if (r < 0) {
				r = -r;
			}
			liste.add(r, "adasdasjdas", "dasdsasdas");
		}
		for (int i = 0; i < 500; i++) {
			r = generator.nextInt();
			if (r < 0) {
				r = -r;
			}
			liste.delete(r);
		}
		r = generator.nextInt();
		System.out.println(liste.giveName(r));
		r = generator.nextInt();
		System.out.println(liste.giveMail(r));
	}
}
 
S

SlaterB

Gast
was ist 'jdb' mit dem es nicht funktioniert?
ich hab mal das Debuggen angefangen:
es geht bis 764 von den 100.000 (ok, ist ja Zufall, also wechselhaft),
dann in die Schleife Zeile 45 bis 47, dort wird ein Wert immer und immer wieder verwendet,

kein Wunder wenn die Hashfunktion einfach nur '% size' ist, ist einmal ein Platz belegt wird immer wieder derselbe geprüft?
ich weiß nicht genau was an dieser Stelle passieren soll, hab den Rest bisher nicht gelesen, vielleicht einfach nur mit +1 eine Stelle weiter?!
danach dann gerne modulo, um nicht aus dem Array-Indexbereich herauszukommen
 

Dekker

Bekanntes Mitglied
Nope SlaterB, im ersten Post steht:

Java:
int hash2(int k){return 1+k%(m-2);} //fuer Sondierfolge

Die andere Hashfunktion wird nur 1 mal (und zwar als erstes) aufgerufen.
 

misaki

Mitglied
"jdb" ist ein Java Debugger den ich in der Konsole ausführen kann. Aber der hilft mir nicht weiter.

Habe mich jetzt grade gefragt, was mein Ding macht, wenn das Primzahlenarray "aus" ist und keine Erweiterung mehr stattfinden kann. Dachte, darin könnte der Fehler liegen.

Jetzt habe ich eine Abfrage eingebaut dass nicht mehr als 1048573 Studenten eingefügt werden dürfen, sonst gitbs eine Ausgabe.
Und beim Überprüfen der Belegung des Arrays muss die aktuelle Primzahlenarrayposition auch < 10 sein, sodass noch einmal erweitert werden könnte.

Trotzdem funktionierts noch nicht:oops:
 

Dekker

Bekanntes Mitglied
ok, erstmal ist das rehashen sau komisch geschrieben, ich würds auslagern aus der funktion und beim wiedereinfügen einfach dein add aufrufen. Ich bin mir ehrlich gesagt garnicht sicher wo deine Implementation hängt bisher. SlaterB hatte doch recht, seh nu was er eigentlich gemeint hat, sorry ^^
 

Ähnliche Java Themen

Neue Themen


Oben