Salve a tutti. Devo implementare una classe NaturalMergeSort che ordina le linee di un file di testo(in senso lessicografico).
Il mio problema è che quando leggo il file con varie righe che ho scritto, mi stampa le righe e non me le ordina e alcune volte mi cancella anche alcune righe.
Il contenuto del mio file test è questo:
ciao
zio
foca
gilda
trave
bocca
Alla prima esecuzione il programma mi da come risultato:
trave
zio
bocca
Questo comunque è il codice:
codice:
package it.uniba.itps.labinf.lab;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;
/**
* Ordina le linee di un file di testo in senso lessicografico.
* Utilizza l'algoritmo Natural Merge Sort per l'ordinamento.
*/
public class NaturalMergeSorter {
/**
* Contatore del numero di confronti
*/
private int compsNum;
/**
* File da ordinare
*/
private java.io.File fileToSort;
/**
* Prefisso del primo file di supporto
*/
private static String STRATCHA_PREFIX = " SCRATCH-A";
/**
* Prefisso del secondo file di supporto
*/
private static String STRATCHB_PREFIX = " SCRATCH-B";
/**
* Il costruttore - specifica il file da ordinare
*
* @param fileToSort - il File da ordinare
*/
public NaturalMergeSorter(java.io.File fileToSort) {
this.fileToSort = fileToSort;
compsNum = 0;
}
/**
* Confronta due stringhe e aggiorna il contatore di confronti
*
* @param a - prima stringa del confronto
* b - seconda stringa del confronto
*
* @return true se a>b (unsensitive)
*/
protected boolean greaterThan(String a, String b) {
compsNum ++;
if(a.compareToIgnoreCase(b) > 0) return true;
else return false;
}
/**
* Fonde i file scratchA e scratchB in dest.
* La fusione avviene prendendo elementi di scratchA
* e scratchB e inserendo in dest l'elemento minore.
* Quando uno dei due file si esaurisce, si copia il rimanente
* file in dest
*
* @param scratchA - il primo File da fondere
* scratchB - il secondo File da fondere
* dest - il file che deve contenere la fusione
* @return true se il file dest risulta ordinato
* @throws Java.io.IOException
*/
private boolean merge(java.io.File scratchA, java.io.File scratchB,
java.io.File dest) throws IOException {
Scanner scanA = new Scanner(scratchA); //leggo il file A
Scanner scanB = new Scanner(scratchB); //leggo il file B
PrintStream destStream = new PrintStream(dest);
//dirigo il flusso verso dest
String bufferA = "";
String bufferB = "";
boolean nextA = true; //linee consumamte
boolean nextB = true; //linee consumate
boolean sorted = true;
while(scanA.hasNext() || scanB.hasNext()) {
//almeno uno dei due file deve avere linee
if(scanA.hasNext() && scanB.hasNext()) {
//se entrambi hanno linee, si inserisce in
//dest la minore
sorted = false;
bufferA = nextA ? scanA.nextLine() : bufferA;
bufferA = nextB ? scanB.nextLine() : bufferB;
nextA = false;
nextB = false; //le linee non sono ancora consumate
//ora metto il minore in dest
if(greaterThan(bufferA, bufferB)) {
destStream.println(bufferB);
nextB = true;
} else {
destStream.println(bufferA);
nextA = true;
}
} else { //uno dei due file è esaurito
//bisogna consumare le linee non consumate
if(nextA == false) {
destStream.println(bufferA);
}
if(nextB == false) {
destStream.println(bufferB);
}
//poi si scarica il file non esaurito
while (scanB.hasNext()) {
bufferB = scanB.nextLine();
destStream.println(bufferB);
}
while (scanA.hasNext()) {
bufferA = scanA.nextLine();
destStream.println(bufferA);
}
}
}
destStream.close();
scanA.close();
scanB.close();
return sorted;
}
/**
* Esegue l'ordinamento del file. Utilizza l'algoritmo
* Natural Merge Sort per l'ordinamento che opera come suegue:
* <ol>
* <li> Sia F il file da ordinare </li>
* <li> Fintanto che file non è ordinato:
* <ol>
* <li> crea due file di supporto A e B </li>
* <li> separa il file da ordinare in A e B </li>
* <li> fonde i file A e B in F </li>
* </ol>
* </li>
* </ol>
* @throws java.io.IOException
*/
public void sort() throws java.io.IOException {
//fileToSort è il file da ordinare
File A, B;
boolean sorted = false;
compsNum = 0;
while(!sorted) {
A = new File(fileToSort.getName() + STRATCHA_PREFIX);
B = new File(fileToSort.getName() + STRATCHB_PREFIX);
split(fileToSort, A, B);
sorted = merge(A, B, fileToSort);
sorted = true;
}
}
/**
* separa il file source in due file separati
* Il criterio di separazione si basa sulla regola
* che se la linea i è lessicograficamente precedente
* alla linea i+1, allora quest'ultima va nello stesso
* file in cui è inserita la linea i, altrimenti essa
* va memorizzata nell'altro file.
*
* @param source il file da separare
* @param scratchA il primo file destinazione
* @param scratchB il secondo file destinazione
* @throws IOException
*/
private void split(java.io.File source, java.io.File scratchA,
java.io.File scratchB) throws IOException {
PrintStream[] scratchStream = new PrintStream[2];
//gli stream sono in posizione 0 e 1 e quindi si può usare
//il complemento per alternarli
scratchStream[0] = new PrintStream(scratchA);
scratchStream[1] = new PrintStream(scratchB);
Scanner inStream = new Scanner(source);
String previousString = "";
int currentStreamIndex = 0;
while(inStream.hasNext()) {
String currentString = inStream.nextLine();
if(greaterThan(previousString, currentString)) {
//switch del file
currentStreamIndex = 1 - currentStreamIndex;
}
previousString = currentString;
scratchStream[currentStreamIndex].println(currentString);
}
scratchStream[0].close();
scratchStream[1].close();
inStream.close();
}
public static void main(String[] args) throws Exception {
File newFile =new File("test.txt");
NaturalMergeSorter nms = new NaturalMergeSorter(newFile);
nms.sort();
//Stampa file ordinato
Scanner fileInput = new Scanner(newFile);
while (fileInput.hasNextLine()){
System.out.println(fileInput.nextLine());
}
fileInput.close();
}
}
Grazie!!