Hallo,
Ich soll für die Uni MergeSort einmal rekursiv und einmal nicht-rekursiv programmieren. Ausserdem soll ich das "externe Sortieren" implementieren mit MergeSort.
Während die rekursive und nicht-rekursive Version recht übersichtlich und nur knapp 90 Zeilen lang sind ist das externe Sortieren 186 Zeilen lang... Ich denke das muss auch kürzer und einfacher gehen, weiß aber nicht wie (haben bisher noch nichts mit Dateien gemacht)
Kurz zum externen sortieren:
Die zu sortierenden Zahlen liegen in einer Datei.
Man darf die Datei nicht in ein Array einlesen und auch sonst nur von der Eingabegröße unabhängig viele Speicherzellen belegen.
Sinn soll wohl sein das man auch Dateien mit sehr vielen Zahlen sortieren kann.
=> Statt Arrays und "Hilfs-Arrays" nimmt man Dateien und "Hilfs-Dateien"
Das Programm funktioniert so wie es momentan ist, reicht wohl auch völlig für die Abgabe.
Es interessiert mich aber wie man sowas effizienter und übersichtlicher programmieren könnte.
Hier der Code:
(mir ist schon klar das man Variablen normalerweise klein schreibt, in der Vorlesung haben wir die Variablennamen der Dateien und Arrays aber groß geschrieben, daher habe ich das vorerst auch so gemacht um den Überblick zu behalten, werde ich eventuell noch ändern)
Was mich vor allem stört:
1. kann ich die Methode "kopiereDatei(File A, File X)" nicht irgendwie umgehen indem ich die Datei A.txt in X.txt umbenenne? Mit A.rename(new File("A.txt")) hat das irgendwie nicht funktioniert...
2. kann ich die Anzahl der ahlen auch einfacher bestiommen als ich es in "bestimmeAnzahl(File file)" gemacht habe?
3. Sind Scanner zum lesen und Formatter zum schreiben von Zahlen überhaupt sinnvoll?
4. Muss ich die Files, Scanner und Formatter immer zuerst mit null initialisieren, dann im try-Block "richtig" initialisieren und kann sie dann erst benutzen?
Wenn ich diese Instanzen direkt "richtig" initialisieren will meckert er das es in einem try/catch Block stehen muss (klar, kann ja eine IO-Exception auftreten). Schreibe ich es in einen try/catch-Block meckert er das er die Variablen nicht kennt (theoretisch könnte ein Fehler auftreten wodurch nicht alle Variablen erstellt würden, kann bei mir aber nicht passieren da in dem Fall ddas Prograqmm beendet wird)
Gibts da irgendeine bessere Methode das zu realisieren?
5. Ähnliches Problem in Zeile 95. Ich muss die Variablen initialisieren, obwohl die Variablen 100%ig vor der ersten Benutzung initialisiert werden
6. Muss ich die Dateien immer wieder schließen und neu öffnen um wieder von Anfang an auslesen zu können? Oder kann ich irgendwie an den Anfang "zurückspringen" Das würde das Problem 4 schonmal stark reduzieren da diese Initialisierungen nur einmal gemacht werden müssten und es müssten auch nur einmal die Dateien geschlossen werden (unmittelbar bevor das Programm beendet wird).
Hat jemand zu einem oder mehreren Punkten eine Idee wie man das verbessern könnte?
Oder sonst einen Verbesserungsvorschlag?
mfg
Christian
Ich soll für die Uni MergeSort einmal rekursiv und einmal nicht-rekursiv programmieren. Ausserdem soll ich das "externe Sortieren" implementieren mit MergeSort.
Während die rekursive und nicht-rekursive Version recht übersichtlich und nur knapp 90 Zeilen lang sind ist das externe Sortieren 186 Zeilen lang... Ich denke das muss auch kürzer und einfacher gehen, weiß aber nicht wie (haben bisher noch nichts mit Dateien gemacht)
Kurz zum externen sortieren:
Die zu sortierenden Zahlen liegen in einer Datei.
Man darf die Datei nicht in ein Array einlesen und auch sonst nur von der Eingabegröße unabhängig viele Speicherzellen belegen.
Sinn soll wohl sein das man auch Dateien mit sehr vielen Zahlen sortieren kann.
=> Statt Arrays und "Hilfs-Arrays" nimmt man Dateien und "Hilfs-Dateien"
Das Programm funktioniert so wie es momentan ist, reicht wohl auch völlig für die Abgabe.
Es interessiert mich aber wie man sowas effizienter und übersichtlicher programmieren könnte.
Hier der Code:
(mir ist schon klar das man Variablen normalerweise klein schreibt, in der Vorlesung haben wir die Variablennamen der Dateien und Arrays aber groß geschrieben, daher habe ich das vorerst auch so gemacht um den Überblick zu behalten, werde ich eventuell noch ändern)
Code:
import java.io.File;
import java.util.Formatter;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class Externes_sortieren{
public static void main(String[]args){
/* Vorraussetzungen:
* Datei besteht aus Integerwerten getrennt durch Leerzeichen
* A.txt ist die Quelldatei und befindet sich im selben Ordner */
mergesort();
System.exit(0);
}
public static void mergesort(){
int count; // Anzahl Elemente in A.txt
int laenge = 1; // Länge der "Teildateien"
int l = 0; // Position in A (fängt bei 0 an)
File A = null;
Scanner reader_A = null; // Liest Datei A.txt
File A1 = null;
File A2 = null;
Formatter output_A1 = null; // schreibt Datei A1.txt
Formatter output_A2 = null; // schreibt Datei A2.txt
// Bestimme die Anzahl der Zahlen:
count = bestimme_Anzahl(new File("A.txt"));
while (laenge <= count){
for (int anz = count/laenge; anz > 0; anz -= 2){
try {
A = new File("A.txt");
reader_A = new Scanner(A);
A1 = new File("A1.txt");
A2 = new File("A2.txt");
output_A1 = new Formatter(A1);
output_A2 = new Formatter(A2);
} catch (Exception e){
JOptionPane.showMessageDialog(null, "Problem in mergesort\n" + e.toString());
System.exit(1);
}
for (int i = 0; i < l; i++){
reader_A.nextInt(); // überspringen
}
for (int i = 1; (reader_A.hasNextInt() && i <= laenge); i++){
output_A1.format("%s ",reader_A.nextInt());
}
for (int i = 1; (reader_A.hasNextInt() && i <= laenge); i++){
output_A2.format("%s ",reader_A.nextInt());
}
output_A1.close();
output_A2.close();
reader_A.close();
merge(A1,A2,A,l);
A1.delete();
A2.delete();
l += 2*laenge;
}
l = 0;
laenge *= 2; // Größe der zu sortierenden Felder verdoppeln
}
}
public static void merge(File A1, File A2, File A, int l){
Scanner reader_A1 = null; // liest Datei A1.txt
Scanner reader_A2 = null; // liest Datei A2.txt
File X = null;
Scanner reader_X = null; // liest Datei X.txt
Formatter output_A = null; // schreibt Datei A.txt
try {
reader_A1 = new Scanner(A1);
reader_A2 = new Scanner(A2);
X = new File("X.txt");
kopiereDatei(A,X); // A in X kopieren
reader_X = new Scanner(X);
A.delete();
output_A = new Formatter(A);
} catch (Exception e){
JOptionPane.showMessageDialog(null, "Problem in merge\n" + e.toString());
System.exit(1);
}
int count_anz = 0; // Zählt wie oft die Schleife durchlafen wurde
// (=> Anzahl der in X.txt zu überspringenden Werte)
int a1 = 0, a2 = 0;
boolean a1_used = true, a2_used = true;
for (int i = 1; i <= l; i++){
output_A.format("%s ",reader_X.nextInt());
}
while ((reader_A1.hasNextInt()) || (reader_A2.hasNextInt()) || !a1_used || !a2_used){
count_anz++;
if (!reader_A1.hasNextInt() && a1_used){ // falls A1 komplett "verwendet" wurde
if (a2_used){
a2 = reader_A2.nextInt();
}
output_A.format("%s ",a2);
a2_used = true;
continue;
}
if (!reader_A2.hasNextInt() && a2_used){ // falls A2 komplett "verwendet" wurde
if (a1_used){
a1 = reader_A1.nextInt();
}
output_A.format("%s ",a1);
a1_used = true;
continue;
}
if (a1_used){
a1 = reader_A1.nextInt();
a1_used = false;
}
if (a2_used){
a2 = reader_A2.nextInt();
a2_used = false;
}
if (a1 >= a2){
output_A.format("%s ",a2);
a2_used = true;
} else {
output_A.format("%s ",a1);
a1_used = true;
}
}
for (int i = 1; i <= count_anz; i++){
reader_X.nextInt(); // überspringen
}
while (reader_X.hasNextInt()){
output_A.format("%s ",reader_X.nextInt());
}
reader_X.close();
X.delete();
output_A.close();
reader_A1.close();
reader_A2.close();
}
public static int bestimme_Anzahl(File file){
int count = 0;
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNextInt()){
scanner.nextInt();
count++;
}
scanner.close();
} catch(Exception e){
JOptionPane.showMessageDialog(null, e.toString());
System.exit(1);
}
return count;
}
public static void kopiereDatei(File A, File X){
Formatter output_X = null;
Scanner reader_A = null;
try {
output_X = new Formatter(X);
reader_A = new Scanner(A);
} catch (Exception e){
JOptionPane.showMessageDialog(null, "Problem in kopiereDatei\n" + e.toString());
System.exit(1);
}
while (reader_A.hasNextInt()){
output_X.format("%s ",reader_A.nextInt());
}
output_X.close();
reader_A.close();
}
}
Was mich vor allem stört:
1. kann ich die Methode "kopiereDatei(File A, File X)" nicht irgendwie umgehen indem ich die Datei A.txt in X.txt umbenenne? Mit A.rename(new File("A.txt")) hat das irgendwie nicht funktioniert...
2. kann ich die Anzahl der ahlen auch einfacher bestiommen als ich es in "bestimmeAnzahl(File file)" gemacht habe?
3. Sind Scanner zum lesen und Formatter zum schreiben von Zahlen überhaupt sinnvoll?
4. Muss ich die Files, Scanner und Formatter immer zuerst mit null initialisieren, dann im try-Block "richtig" initialisieren und kann sie dann erst benutzen?
Wenn ich diese Instanzen direkt "richtig" initialisieren will meckert er das es in einem try/catch Block stehen muss (klar, kann ja eine IO-Exception auftreten). Schreibe ich es in einen try/catch-Block meckert er das er die Variablen nicht kennt (theoretisch könnte ein Fehler auftreten wodurch nicht alle Variablen erstellt würden, kann bei mir aber nicht passieren da in dem Fall ddas Prograqmm beendet wird)
Gibts da irgendeine bessere Methode das zu realisieren?
5. Ähnliches Problem in Zeile 95. Ich muss die Variablen initialisieren, obwohl die Variablen 100%ig vor der ersten Benutzung initialisiert werden
6. Muss ich die Dateien immer wieder schließen und neu öffnen um wieder von Anfang an auslesen zu können? Oder kann ich irgendwie an den Anfang "zurückspringen" Das würde das Problem 4 schonmal stark reduzieren da diese Initialisierungen nur einmal gemacht werden müssten und es müssten auch nur einmal die Dateien geschlossen werden (unmittelbar bevor das Programm beendet wird).
Hat jemand zu einem oder mehreren Punkten eine Idee wie man das verbessern könnte?
Oder sonst einen Verbesserungsvorschlag?
mfg
Christian