Aufgabenstellung: Ein vom Benutzer angegebener arithmetischer

Werbung
Algorithmen und Datenstrukturen
Übung 17: Externes Sortieren1
Natürliches Zwei-Wege Mischsortieren
Einführung. 2 geordnete Teilsequenzen mit den Längen M und N werden direkt zu einer Sequenz mit
M + N Elementen gemischt. Das natürliche Mischen mischt immer längste möglichen Teilfolgen.
Vereinbarung. Eine Teilsequenz X[I] ..
X[J] heißt (maximaler) Lauf, wenn folgende
Bedingungen erfüllt sind:
1. X[K] <= X[K + 1]
2. X[I - 1] > X[I]
3. X[J] > X[J + 1]
(für K = I .. J - 1)
Die natürliche Mischsortierung mischt (maximale) Läufe statt fester Sequenzen mit vorbestimmter
Länge. Jede Folge von natürlichen Zahlen zerfällt in eine solche Folge, so z.B.:
5
3
2
7 10
4
1 7
3
6
8
2 geordnete Sequenzen sind dann jeweils zu einer einzigen, geordneten Sequenz zu vereinigen.
Verfahrensaufwand. Er wird danach gemessen, wie oft Läufe in die Betrachtung eingehen. Läufe
haben die Eigenschaft, daß beim Mischen von 2 Sequenzen mit L Läufen eine einzige Sequenz mit
genau L Läufen entsteht.
So ergibt sich für die folgenden beiden Sequenzen
8
7
6
5
4
3
2
1
mit jeweils 4 Läufen die Sequenz
7
8
5
6
3
4
1
2
, die genau 4 Läufe besitzt. Die Zahl der Läufe wird in jedem Durchlauf halbiert. Im schlimmsten Fall
ergibt sich dann die Anzahl der Bewegungen zu: L ld(L).
Der Algorithmus.
Ablauf: Die zu sortierenden Daten liegen im File F vor und sollen am Schluß in sortierter Form unter
demselben Namen zurückgegeben werden. Die beiden Hilfsfiles sind G1 und G2. Jeder Durchlauf
umfaßt eine Verteilungsphase (distribution), die Läufe gleichmäßig von F auf G1 und G2 verteilt, und
eine Mischphase, die Läufe von G1 und G2 auf F mischt.
1
vgl. Skriptum, 3.1.1.2.2
1
Algorithmen und Datenstrukturen
G1
F
G1
G1
F
F
F
F
.......
G2
G2
G2
Mischphase
Verteilungsphase
Abb.:
Das Sortieren ist beendet sobald F nur noch ein Lauf ist.
Für die Definition des momentanen Zustands eines Files stellt man sich am
Positionszeiger vor. Er wird beim Schreiben um je eine Einheit vorwärts geschoben.
Beschreibung: Sie erfolgt nach der Methode „stepwise refinement“.
Grobstruktur des Prozesses:
Wiederhole
Setze die Zeiger aller 3 Files auf den Anfang;
Verteile;
Setze die Zeiger aller 3 Files auf den Anfang;
Mische;
bis L = 1;
(* L ist die Anzahl der Läufe auf dem File F *)
Verfeinerungsschritt:
Verteile
Wiederhole
Kopiere ein Lauf F auf G1
Falls
noch nicht eof(F),
kopiere einen Lauf von F auf G2;
bis Ende von F erreicht;
Mische
2
besten
einen
Algorithmen und Datenstrukturen
Setze L = 0;
Solange weder eof(G1) noch eof(G2) fuehre aus:
Mische je einen Lauf von G1 und G2 auf F;
Erhoehe L um 1;
Solange eof(G1) noch nicht erreicht, fuehre aus:
Kopiere einen Lauf von G1 auf F;
Erhöhe L um 1;
Solange eof(G2) noch nicht erreicht, fuehre aus:
Kopiere einen Lauf von G2 auf F;
Erhöhe L um 1;
Bsp.: Gegeben ist das File F, das die folgenden 17 Zahlen enthält
F: 13 44 7 3 3 9 99 37 61 71 6 8 11 14 15 1
F wird gemäß bereits sortiert vorliegender Teilfolgen zerlegt:
F: [13 44] [7] [3 3 9 99] [37 61 71] [2 6 8 11 14 15] [1]
Die Teilfolgen (Läufe) werden verteilt auf G1 und G2:
G1: [13 44] [3 3 9 99] [37 61 71][2 6 8 11 14 15]
G2: [7] [37 61 71][1]
Die ersten beiden Teilfolgen von G2 können als eine Teilfolge betrachtet werden.
F: [13 44] [7] [3 3 9 99] [37 61 71] [2 6 8 11 14 15][1]
G1: [13 44] [3 3 9 99] [2 6 8 11 14 15]
G2: [7 37 61 71][1]
Zusammenmischen von G1 und G2 zu F:
F: [7 13 37 44 61 71] [1 3 3 9 99] [2 6 8 11 14 15]
Weiteres Aufteilen (Split) und Mischen führt zu:
G1: [7 13 37 44 61 71] [2 6 8 11 14 15]
G2: [1 3 3 9 99]
F: [1 3 3 7 9 13 37 44 61 71 99] [2 6 8 11 14 15]
G1: [1 3 3 7 9 13 37 44 61 71 99]
G2: [2 6 8 11 14 15]
F: [1 2 3 3 6 7 8 9 11 13 14 15 37 44 61 71 99]
3
Algorithmen und Datenstrukturen
Implementierung in Java2.
ExternalSort
SortFileStream
Die Klasse ExternalSort3 implementiert das natürliche 2-Wege-Mischen.
Die Klasse SortFileStream implementiert eine Klasse zur Verarbeitung einer binären Datei mit
„Comparable“-Objekten.
Das natürliche
ExternalSort:
Mischsortieren
übernimmt
die
Methode
naturalMerge()
der
Klasse
/**
* naturalMerge – implementiert den Algorithmus fuer natuerliches Mischen:
*
- verteilt Laeufe
*
- mischt
*
- wiederholt das bis nur noch ein einziger Lauf existiert
*/
public static void naturalMerge(SortFileStream inFile)
throws IOException
{
SortFileStream fileA, fileB, sortFile;
int numRuns;
fileA = new SortFileStream("outfile1");
fileB = new SortFileStream("outfile2");
sortFile = new SortFileStream("outfile3");
// Initialisieren Verteilungsphase.
System.out.println("\nDistribute:");
distribute(inFile, fileA, fileB);
System.out.print("
File A: ");
fileA.list(true);
System.out.print("
File B: ");
fileB.list(true);
// Alternativ mische und verteile zurueck.
do {
System.out.print("\nMerge: ");
numRuns = merge(fileA, fileB, sortFile);
sortFile.list(true);
if (numRuns > 1)
{ System.out.println(
"--------------------------------------------------------------");
System.out.println("Distribute:");
distribute(sortFile, fileA, fileB);
System.out.print("
File A: ");
fileA.list(true);
System.out.print("
File B: ");
fileB.list(true);
}
} while (numRuns > 1);
}
naturalMerge() führt das natürliche Mischsortieren aus und verteilt bzw. mischt solange bis die
Zahl der Läufe größer als 1 ist mit den beiden Methoden merge() und distribute():
/*
* merge - mischt alle Laeufe aus fileA und fileB auf destFile,
2
Nach einer Vorlage der Harvard University, vgl.:
http://www.fas.harvard.edu/~libs111/unit7/assign/ExternalSort.java
3 vgl. pr31122
4
Algorithmen und Datenstrukturen
* beruecksichtigt dabei, dass die Zahl der Laeufe in den beiden
* Dateien ungleich sein kann. Zaehlt und gibt die Zahl der Laeufe
* zurueck in destFile.
*/
private static int merge(SortFileStream fileA, SortFileStream fileB,
SortFileStream destFile) throws IOException
{
int numRuns = 0;
fileA.openRead();
fileB.openRead();
destFile.openWrite();
// Mische Laeufe.
while (!(fileA.endOfFile() || fileB.endOfFile()))
{
mergeRun(fileA, fileB, destFile);
numRuns++;
}
// Copy tail of fileA if necessary.
while (!fileA.endOfFile()) {
copyRun(fileA, destFile);
numRuns++;
}
// Copy tail of fileB if necessary.
while (!fileB.endOfFile())
{
copyRun(fileB, destFile);
numRuns++;
}
destFile.close();
return numRuns;
}
/*
* distribute – verteile alle Laeufe von der sourceFile alternately
* alternierend auf fileA und fileB
*/
private static void distribute(SortFileStream sourceFile,
SortFileStream fileA, SortFileStream fileB) throws IOException
{
sourceFile.openRead();
fileA.openWrite();
fileB.openWrite();
do {
copyRun(sourceFile, fileA);
if (!sourceFile.endOfFile())
copyRun(sourceFile, fileB);
} while (!sourceFile.endOfFile());
fileA.close();
fileB.close();
}
merge() und distribute() werden ergänzt durch die Methoden mergeRun(), copy() und
copyRun()
private static void mergeRun(SortFileStream fileA, SortFileStream fileB,
SortFileStream destFile) throws IOException
{
//
// Bis beide Dateien das Ende eines Laufs erreichen, erfolgt die .
// Bearbeitung in einer Schleife. Nur wenn beide Dateien das endOfRun// Flag gesetzt haben, ist das Mischen beendet
do {
5
Algorithmen und Datenstrukturen
Comparable nextA = fileA.peekNextObject();
Comparable nextB = fileB.peekNextObject();
if (nextA.compareTo(nextB) < 0)
{
copy(fileA, destFile);
if (fileA.endOfRun())
copyRun(fileB, destFile);
} else {
copy(fileB, destFile);
if (fileB.endOfRun())
copyRun(fileA, destFile);
}
} while (!(fileA.endOfRun() && fileB.endOfRun()));
}
private static void copy(SortFileStream fRead, SortFileStream fWrite)
throws IOException
{
fWrite.writeObject(fRead.readObject());
}
private static void copyRun(SortFileStream fRead, SortFileStream fWrite)
throws IOException
{
do {
copy(fRead, fWrite);
} while (! fRead.endOfRun());
}
Test:
6
Algorithmen und Datenstrukturen
Lösungen:
/*
* ExternalSort.java
*
* Computer Science S-111, Harvard University
*/
import java.io.*;
// import utils.SavitchIn;
/**
* ExternalSort - a class containing implementations of two external
* sorting algorithms--i.e., methods for sorting sequential files
* without reading them into an array.
*/
public class ExternalSort
{
private static void copy(SortFileStream fRead, SortFileStream fWrite)
throws IOException
{
fWrite.writeObject(fRead.readObject());
}
private static void copyRun(SortFileStream fRead, SortFileStream fWrite)
throws IOException
{
do {
copy(fRead, fWrite);
} while (! fRead.endOfRun());
}
private static void mergeRun(SortFileStream fileA, SortFileStream fileB,
SortFileStream destFile) throws IOException
{
//
// Keep looping until *both* files reach the end of a run.
// At the end of the first iteration, the file from which we don't
// read may "falsely" have its endOfRun flag set, but we will only
// find both files' flags set if the merge is actually done.
//
do {
Comparable nextA = fileA.peekNextObject();
Comparable nextB = fileB.peekNextObject();
if (nextA.compareTo(nextB) < 0)
{
copy(fileA, destFile);
if (fileA.endOfRun())
copyRun(fileB, destFile);
} else {
copy(fileB, destFile);
if (fileB.endOfRun())
copyRun(fileA, destFile);
}
} while (!(fileA.endOfRun() && fileB.endOfRun()));
}
/*
* distribute - distribute all runs from sourceFile alternately
* into fileA and fileB
*/
private static void distribute(SortFileStream sourceFile,
SortFileStream fileA, SortFileStream fileB) throws IOException
{
7
Algorithmen und Datenstrukturen
sourceFile.openRead();
fileA.openWrite();
fileB.openWrite();
do {
copyRun(sourceFile, fileA);
if (!sourceFile.endOfFile())
copyRun(sourceFile, fileB);
} while (!sourceFile.endOfFile());
fileA.close();
fileB.close();
}
/*
* merge - merge all runs from fileA and fileB onto destFile,
* remembering that there might be unequal numbers of runs in the
* two files. Count and return the number of runs in the
* resulting destFile.
*/
private static int merge(SortFileStream fileA, SortFileStream fileB,
SortFileStream destFile) throws IOException
{
int numRuns = 0;
fileA.openRead();
fileB.openRead();
destFile.openWrite();
// Merge runs.
while (!(fileA.endOfFile() || fileB.endOfFile()))
{
mergeRun(fileA, fileB, destFile);
numRuns++;
}
// Copy tail of fileA if necessary.
while (!fileA.endOfFile())
{
copyRun(fileA, destFile);
numRuns++;
}
// Copy tail of fileB if necessary.
while (!fileB.endOfFile())
{
copyRun(fileB, destFile);
numRuns++;
}
destFile.close();
return numRuns;
}
/**
* naturalMerge - perform the natural merge algorithm:
*
- distribute runs as evenly as possible
*
- merge
*
- repeat until there's only one run
*/
public static void naturalMerge(SortFileStream inFile)
throws IOException
{
SortFileStream fileA, fileB, sortFile;
int numRuns;
fileA = new SortFileStream("outfile1");
fileB = new SortFileStream("outfile2");
sortFile = new SortFileStream("outfile3");
// Initial distribution phase.
System.out.println("\nDistribute:");
distribute(inFile, fileA, fileB);
System.out.print("
File A: ");
8
Algorithmen und Datenstrukturen
fileA.list(true);
System.out.print("
File B: ");
fileB.list(true);
// Alternately merge and redistribute.
do {
System.out.print("\nMerge: ");
numRuns = merge(fileA, fileB, sortFile);
sortFile.list(true);
if (numRuns > 1) {
System.out.println(
"--------------------------------------------------------------");
System.out.println("Distribute:");
distribute(sortFile, fileA, fileB);
System.out.print("
File A: ");
fileA.list(true);
System.out.print("
File B: ");
fileB.list(true);
}
} while (numRuns > 1);
}
/*
* fibDistrib - do the initial distribution of runs according to
* the Fibonacci merge algorithm
*/
private static void fibDistrib(SortFileStream file0, SortFileStream
file1,
SortFileStream file2) throws IOException
{
Comparable nextObj0, lastWrite1, lastWrite2;
int lastFib, nextLastFib;
file0.openRead();
file1.openWrite();
file2.openWrite();
//
// Start with targets of 1 run for each file.
// At this point, they're all dummy runs.
//
file1.runs = 1;
file2.runs = 1;
file1.dummyRuns = 1;
file2.dummyRuns = 1;
//
// Initialize the variables used to update the targets/totals
// according to the Fibonacci sequence.
//
nextLastFib = 0;
lastFib = 1;
// Distribute the runs
while (!file0.endOfFile()) {
//
// If the current targets have both been met, increase
// them by adding new dummy runs to both files.
//
if ((file1.dummyRuns == 0) && (file2.dummyRuns == 0)) {
System.out.println("Adding " + lastFib +
" dummy runs to file 1, " + nextLastFib + " to file 2");
file1.dummyRuns = lastFib;
file2.dummyRuns = nextLastFib;
9
Algorithmen und Datenstrukturen
file1.runs += lastFib;
file2.runs += nextLastFib;
// Generate next set of Fibonacci numbers.
lastFib = lastFib + nextLastFib;
nextLastFib = lastFib - nextLastFib;
}
//
// Add a run to a file that hasn't met its target (i.e.,
// that still has dummy runs), giving preference to file1.
//
nextObj0 = file0.peekNextObject();
lastWrite1 = file1.getLastWritten();
lastWrite2 = file0.getLastWritten();
if (file1.dummyRuns == 0) {
// Copy a run to file2.
if (lastWrite2 == null ||
nextObj0.compareTo(lastWrite2) < 0) {
//
// NOT a contination - a new real run, so
// we need one fewer dummy run.
//
file2.dummyRuns -= 1;
}
copyRun(file0, file2);
} else {
// Copy a run to file1.
if (lastWrite1 == null ||
nextObj0.compareTo(lastWrite1) < 0) {
// a new real run
file1.dummyRuns -= 1;
}
copyRun(file0, file1);
}
}
}
/*
* fibMerge - merge as many runs as there are in infile2
*/
private static void fibMerge(SortFileStream infile1,
SortFileStream infile2, SortFileStream outfile) throws IOException
{
//
// infile2 should already be open for reading--because
// we were reading from it during the last phase of the
// algorithm, or because we opened it in fibonacci().
//
infile1.openRead();
outfile.openWrite();
outfile.runs = 0;
outfile.dummyRuns = 0;
// Merge enough runs to use up infile2.
for (int run = 1; run <= infile2.runs; run++) {
outfile.runs++;
infile1.runs--;
if ((infile1.dummyRuns > 0) && (infile2.dummyRuns > 0)) {
// "Merge" a pair of dummy runs, adding one to outfile.
infile1.dummyRuns--;
infile2.dummyRuns--;
10
Algorithmen und Datenstrukturen
outfile.dummyRuns++;
} else if (infile1.dummyRuns > 0) {
//
// "Merge" a dummy run with a real run from infile2,
// copying the real run.
//
copyRun(infile2, outfile);
infile1.dummyRuns--;
} else if (infile2.dummyRuns > 0) {
// same as above, but we copy a run from infile1
copyRun(infile1, outfile);
infile2.dummyRuns--;
} else {
// no dummies left on either file
mergeRun(infile1, infile2, outfile);
}
}
infile2.runs = 0;
outfile.close();
}
/**
* fibonacci - perform the Fibonacci merge algorithm:
*
- distribute runs so that there are consecutive fibonacci
*
numbers of runs in two files;
*
- keep merging the files, reusing a file for output as soon as
*
it becomes empty
*/
public static void fibonacci(SortFileStream infile) throws IOException
{
SortFileStream[] file = new SortFileStream[3];
int bigIn, smallIn, out;
file[0] = new SortFileStream("outfile0");
file[1] = new SortFileStream("outfile1");
file[2] = new SortFileStream("outfile2");
// Empty this out for the purposes of the listing below.
file[2].openWrite();
file[2].runs = file[2].dummyRuns = 0;
// Do the initial distribution of runs and display the results.
fibDistrib(infile, file[0], file[1]);
System.out.println("\nfname (runs, dummy): contents");
for (int i = 0; i < 3; i++) {
System.out.print("f" + i + " (" + file[i].runs + ", " +
file[i].dummyRuns + "): ");
file[i].list(true);
}
// Initialize index numbers.
bigIn = 0;
smallIn = 1;
out = 2;
file[1].openRead();
// file0 will be opened in fibMerge()
do {
fibMerge(file[bigIn], file[smallIn], file[out]);
// Display files after the merge.
System.out.println(
"--------------------------------------------------------------");
for (int i = 0; i < 3; i++) {
11
Algorithmen und Datenstrukturen
System.out.print("f" + i + " (" + file[i].runs + ", " +
file[i].dummyRuns + "): ");
if (i == out)
file[i].list(true);
else
file[i].list(false);
// list from current point to end
}
//
// Rotate files:
// - old output becomes new big input file.
// - old big input becomes small input file.
// - old small input, now empty, becomes output file.
//
bigIn = (bigIn + 2) % 3;
smallIn = (smallIn + 2) % 3;
out = (out + 2) % 3;
} while (file[smallIn].runs > 0);
}
public static void main(String[] args) throws IOException
{
SortFileStream infile;
char reply;
// SortFileStream file;
BufferedReader
ein
=
new
BufferedReader(new
InputStreamReader(System.in));
String name;
int numInt;
System.out.print("file name: ");
name = ein.readLine();
infile = new SortFileStream(name);
if (! infile.exists())
{
System.out.print("How many integers? ");
numInt
=
/*
SavitchIn.readLineInt();
*/
Integer.parseInt(ein.readLine());
infile.openWrite();
for (int i = 0; i < numInt; i++)
{
Integer val = new Integer((int)(100 * Math.random()));
infile.writeObject(val);
}
} else
{
infile.openRead();
// infile.list(true);
}
// infile.close();
// System.out.print("Name of input file to sort: ");
// infile = new SortFileStream(SavitchIn.readLine());
System.out.println("Contents: ");
infile.list(true);
System.out.println();
/*
System.out.print("Fibonacci merge (instead of natural merge)? [Y,N] ");
reply = SavitchIn.readLineNonwhiteChar();
if (reply == 'Y' || reply == 'y')
fibonacci(infile);
else */
naturalMerge(infile);
System.out.println();
}
12
Algorithmen und Datenstrukturen
}
/*
* SortFileStream.java
*
* Computer Science S-111, Harvard University
*/
import java.io.*;
// import utils.SavitchIn;
/**
* Implementation of a class for a binary sequential file
* containing Comparable objects.
*/
public class SortFileStream
{
private String fname;
private File file;
private ObjectInputStream in;
private ObjectOutputStream out;
private boolean endOfRun;
private boolean endOfFile;
private Comparable nextObject;
private Comparable lastWritten;
private int objectNum;
// index of the object to be returned next
/**
* These are used by the Fibonacci merge algorithm, so we
* make them public so it can easily access them.
*/
public int runs;
// the total/target number of runs
public int dummyRuns;
// the number of "dummy" runs
/** constructor */
public SortFileStream(String name)
{
fname = name;
file = new File(fname);
in = null;
out = null;
endOfRun = false;
endOfFile = false;
nextObject = null;
lastWritten = null;
runs = dummyRuns = objectNum = 0;
}
public boolean exists()
{
return (file.exists());
}
/**
* openRead - open a sequential file for reading, starting
* at the beginning of the file.
*/
public void openRead() throws IOException
{
// Close any existing streams attached to the file.
close();
in = new ObjectInputStream(new FileInputStream(fname));
endOfFile = false;
objectNum = 0;
//
13
Algorithmen und Datenstrukturen
// We set nextObject to null to ensure that endOfRun will
// not be set in the call to readObject().
//
nextObject = null;
readObject();
// nextObject now contains the first value in the file.
}
/**
* openWrite - open a sequential file for writing, truncating any
* existing contents
*/
public void openWrite() throws IOException
{
close();
out = new ObjectOutputStream(new FileOutputStream(fname));
lastWritten = null;
endOfFile = false;
endOfRun = false;
}
public void close() throws IOException
{
if (in != null)
{
in.close();
in = null;
}
if (out != null)
{
out.close();
out = null;
}
}
/**
* readObject - read a value from the file--storing it in nextObject
* and testing for end-of-file/end-of-run--and return the
* previously read value. We stay one read ahead so that we are
* able to detect the ends of runs.
*/
public Comparable readObject() throws IOException
{
Comparable obj = nextObject;
try
{
nextObject = (Comparable)in.readObject();
endOfRun = (obj == null ? false : (nextObject.compareTo(obj) < 0));
} catch (EOFException e)
{
// end of file, and thus end of run
endOfFile = true;
endOfRun = true;
}
catch (ClassNotFoundException e)
{
System.out.println("Object read from " + fname +
"is not Comparable.");
System.exit(-1);
}
objectNum++;
return obj;
}
/**
14
Algorithmen und Datenstrukturen
* writeObject - write the specified value to the file and keep track
of
* the last value written
*/
public void writeObject(Comparable obj) throws IOException {
out.writeObject(obj);
lastWritten = obj;
}
/**
* list - lists a sequential file, breaking it into runs
*/
public void list(boolean fromStart) throws IOException
{
int count = 0;
int origObjectNum = objectNum;
if (!fromStart && in == null)
throw new IllegalStateException("fromStart = false and file isn't open");
//
// Only reopen the stream if we're listing
// the entire file.
//
if (fromStart)
openRead();
// Do the actual output.
while(!endOfFile) {
System.out.print(readObject());
count = count + 3;
// Print appropriate separator characters.
if (endOfRun && !endOfFile) {
System.out.print(" | ");
count = count + 3;
} else {
System.out.print(" ");
count = count + 1;
}
// Try to avoid wrap-around.
if (count > 100) {
System.out.print("\n\t");
count = 0;
}
}
System.out.println();
//
//
//
//
//
//
if
If we're listing the remainder of a file that's
being read, we need to return it to the point
in the file from which we began. We're assuming that
there are no repeated values.
(!fromStart) {
openRead();
while (objectNum < origObjectNum)
readObject();
}
}
public boolean endOfRun() {
15
Algorithmen und Datenstrukturen
return endOfRun;
}
public boolean endOfFile() {
return endOfFile;
}
public Comparable peekNextObject() {
return nextObject;
}
public Comparable getLastWritten() {
return lastWritten;
}
public String toString() {
return fname;
}
/**
* main - test the class
*/
/*
public static void main(String[] args) throws IOException
{
SortFileStream file;
BufferedReader ein = new BufferedReader(new InputStreamReader(System.in));
String name;
int numInt;
System.out.print("file name: ");
name = ein.readLine();
file = new SortFileStream(name);
if (! file.exists())
{
System.out.print("How many integers? ");
numInt = /* SavitchIn.readLineInt(); Integer.parseInt(ein.readLine());
file.openWrite();
for (int i = 0; i < numInt; i++)
{
Integer val = new Integer((int)(100 * Math.random()));
file.writeObject(val);
}
} else
{
file.openRead();
file.list(true);
}
file.close();
} */
}
16
Herunterladen