417 lines
14 KiB
Java
417 lines
14 KiB
Java
import java.util.HashMap;
|
|
import java.util.*;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Stack;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
|
|
public class Komprimierung
|
|
{
|
|
public static byte[] nullCharBytes = {(byte)0xFF,(byte)0xFF};
|
|
public static void test(String text)
|
|
{
|
|
Map<Character, Integer> zahlen = Zählen.countEachLetter(text);
|
|
Node wurzel = Node.erstellen(zahlen);
|
|
|
|
System.out.println();
|
|
System.out.println("Pre-Order Baum:");
|
|
printBaum(wurzel);
|
|
|
|
System.out.println();
|
|
System.out.println("Anzahl der Zeichen:");
|
|
Zählen.printZahl(zahlen);
|
|
|
|
System.out.println();
|
|
System.out.println("Binärcode der Zeichen:");
|
|
codes(text);
|
|
|
|
System.out.println();
|
|
|
|
decodierungBaum(codierung(text,wurzel), wurzel);
|
|
|
|
System.out.println(binärString_to_character(character_to_binärString(null)));
|
|
System.out.println(binärString_to_character(character_to_binärString('b')));
|
|
System.out.println(binärString_to_character(character_to_binärString('c')));
|
|
System.out.println(binärString_to_character(character_to_binärString('d')));
|
|
System.out.println(binärString_to_character(character_to_binärString('e')));
|
|
System.out.println(binärString_to_character(character_to_binärString('f')));
|
|
System.out.println(binärString_to_character(character_to_binärString('g')));
|
|
System.out.println(binärString_to_character(character_to_binärString('h')));
|
|
|
|
binärString_to_baum(baum_to_binärString(wurzel));
|
|
printBaum(wurzel);
|
|
}
|
|
|
|
public static void test2()
|
|
{
|
|
Map<Character, Integer> zahlen = Zählen.countEachLetter("aaaabbc");
|
|
Node wurzel = Node.erstellen(zahlen);
|
|
printBaum(wurzel);
|
|
|
|
HashMap<Character, String> codes = new HashMap<Character, String>();
|
|
|
|
if(wurzel.getLeft() == null && wurzel.getRight() == null)
|
|
{
|
|
codes.put(wurzel.getBuchstabe(), "0");
|
|
}
|
|
else
|
|
{
|
|
generieren(codes,wurzel,"");
|
|
}
|
|
|
|
for (var entry : codes.entrySet())
|
|
{
|
|
System.out.println("->" + entry.getKey() + ", Code: " + entry.getValue());
|
|
}
|
|
|
|
printBaum(binärString_to_baum(baum_to_binärString(wurzel)));
|
|
}
|
|
|
|
public static void test3()
|
|
{
|
|
System.out.println(decodierungInlkBaum(codierungInklBaum("aaaabbc")));
|
|
}
|
|
|
|
public static void printBaum(Node baum) //gibt den Baum rekurssiv in pre-order aus
|
|
{
|
|
if(baum == null)return;
|
|
System.out.println("Buchstabe: " + baum.getBuchstabe() + ", Anzahl: " + baum.getAnzahl());
|
|
printBaum(baum.getLeft()); //ruft die Methode rekuirsiv auf
|
|
printBaum(baum.getRight());
|
|
}
|
|
|
|
public static void codes(String text) //erstellt die codes für jeden einzelnen Buchstaben
|
|
{
|
|
Node wurzel = Node.erstellen(Zählen.countEachLetter(text)); //erstellt den Baum mithilfe der Node Klasse
|
|
HashMap<Character, String> codes = new HashMap<Character, String>(); //erstellt eine leere Hashmap
|
|
|
|
if(wurzel.getLeft() == null && wurzel.getRight() == null) //überprüft es ob der Baum mehr als ein zeichen lang ist
|
|
{
|
|
codes.put(wurzel.getBuchstabe(), "0");
|
|
}
|
|
else //nutzt generieren um die codes zu generieren
|
|
{
|
|
generieren(codes,wurzel,"");
|
|
}
|
|
|
|
for (var entry : codes.entrySet()) //printet alle codes für das jeweiliege Zeichen
|
|
{
|
|
System.out.println("->" + entry.getKey() + ", Code: " + entry.getValue());
|
|
}
|
|
}
|
|
|
|
|
|
//methode zum generieren der codes für jeden einzelnen Buchstaben
|
|
public static void generieren(HashMap<Character, String> codes, Node node, String code)
|
|
{
|
|
if(node == null)return; //abbruch Bedienung
|
|
if(node.getLeft() == null && node.getRight() == null) //überprüft ob das Node ein "Blatt" ist
|
|
{
|
|
codes.put(node.getBuchstabe(), code); //wenn ja, gibt es den Buchstaben und den jeweiliegen code zurück
|
|
|
|
return;
|
|
}
|
|
generieren(codes, node.getLeft(), code + "0"); //generiert rekursiv den code für die Äste
|
|
generieren(codes, node.getRight(), code + "1");
|
|
}
|
|
|
|
//generiert die Huffman-Codierung
|
|
public static String codierung(String text, Node wurzel)
|
|
{
|
|
HashMap<Character, String> codes = new HashMap<Character, String>(); //erstellt eine leere Hashmap
|
|
|
|
if(wurzel.getLeft() == null && wurzel.getRight() == null) //überprüft es ob der Baum mehr als ein zeichen lang ist
|
|
{
|
|
codes.put(wurzel.getBuchstabe(), "0");
|
|
}
|
|
else //nutzt generieren um die codes zu generieren
|
|
{
|
|
generieren(codes,wurzel,"");
|
|
}
|
|
String code = ""; //erstellt leere Variable
|
|
|
|
for (int i=0; i<text.length();i++) //Codiert den "text" komplett, mithilfe der codes Methode
|
|
{
|
|
char b = text.charAt(i);
|
|
String c = codes.get(b);
|
|
code += c;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
//codiert Buchstaben und speichert den Baum mit
|
|
public static String codierungInklBaum(String text)
|
|
{
|
|
Map<Character, Integer> zahlen = Zählen.countEachLetter(text);
|
|
Node baum = Node.erstellen(zahlen); //erstellt Baum
|
|
|
|
String codierterBaum = baum_to_binärString(baum); //wandelt den Baum in Daten um, mit dem die Baumstruktur geladen werden kann
|
|
String codierterText = codierung(text,baum); //speichert den codierten Text
|
|
|
|
int textErstIndex = codierterBaum.length() + 32; //speichert den ersten Index der Text codierung
|
|
String codiertertextErstIndex = Int_to_binärString(textErstIndex); //wandelt den textErstIndex in Binär um
|
|
|
|
return codiertertextErstIndex + codierterBaum + codierterText;
|
|
}
|
|
|
|
//decodiert Buchstaben und speichert den Baum
|
|
public static String decodierungInlkBaum(String code)
|
|
{
|
|
String codierterTextErstIndex = code.substring(0,32); //holt binärcode vom TextErstIndex
|
|
int textErstIndex = binärString_to_int(codierterTextErstIndex); //wandelt codierterTextErstIndex in eine Integer
|
|
|
|
String codierterBaum = code.substring(32, textErstIndex);
|
|
Node decodierterBaum = binärString_to_baum(codierterBaum);
|
|
|
|
String codierterText = code.substring(textErstIndex, code.length());
|
|
String decodierterText = decodierungBaum(codierterText,decodierterBaum); //decodiert den Text mit dem Baum
|
|
|
|
return decodierterText;
|
|
}
|
|
|
|
//decodiert den Baum
|
|
public static String decodierungBaum(String code,Node baum)
|
|
{
|
|
Node current = baum;
|
|
String decoded = "";
|
|
|
|
boolean hatNurEinBuchstabenart = current.getRight() == null && current.getLeft() == null;
|
|
if(hatNurEinBuchstabenart) //nimmt den einen Buchstabe und fügt ihn für n mal ein
|
|
{
|
|
for(int i=0;i<code.length();i++)
|
|
{
|
|
decoded += baum.getBuchstabe();
|
|
}
|
|
return decoded;
|
|
}
|
|
|
|
for(int i =0;i<code.length();i++) //deocdiert den code einzelnd
|
|
{
|
|
if(code.charAt(i) == '1') //wenn eine 1 im Code steht geht es nach rechts, da 1 für den rechten Ast steht
|
|
{
|
|
current= current.getRight();
|
|
}
|
|
if(code.charAt(i) == '0')
|
|
{
|
|
current = current.getLeft();
|
|
}
|
|
if(current.getRight() == null && current.getLeft() == null) //sind bei einem Blatt angekommen
|
|
{
|
|
decoded += current.getBuchstabe();
|
|
current = baum;
|
|
}
|
|
}
|
|
return decoded;
|
|
}
|
|
|
|
|
|
|
|
public static Byte binärString_to_Byte (String binärString)
|
|
{
|
|
if(binärString.length() != 8) //überprüft ob es ein byte lang ist
|
|
{
|
|
System.out.println(">8");
|
|
return null;
|
|
}
|
|
|
|
byte result = 0;
|
|
for(byte i=0 ;i<8;i++) //geht den binärString durch und wandelt ihn in byte um
|
|
{
|
|
if(binärString.charAt(7-i) == '1')result|=1<<i; //verschiebt die 1 um i binärpositionen nach links
|
|
else if(binärString.charAt(7-i) != '0')
|
|
{
|
|
System.out.println("was flasch");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static String Byte_to_binärString (byte b)
|
|
{
|
|
String result = "";
|
|
|
|
for(byte i=0;i<8;i++)
|
|
{
|
|
boolean bit= ((b>>(7-i))&1)==1; //schaut ob der 7-i ste bit 1 ist
|
|
result+= bit?'1': '0'; //falls bit wert 1 hat addiert es 1 zu dem string, wenn nicht dann addiertes es 0
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static String character_to_binärString (Character c)
|
|
{
|
|
|
|
byte[] b = nullCharBytes;
|
|
|
|
if(c != null) //wandelt character in "byte"
|
|
{
|
|
var byteBuffer = ByteBuffer.allocate(2);
|
|
byteBuffer.putChar(c);
|
|
b = byteBuffer.array();
|
|
}
|
|
|
|
String result = "";
|
|
for(int i=0;i<b.length;i++) //wandelt byte zu String und addiert sie
|
|
{
|
|
result += Byte_to_binärString(b[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static Character binärString_to_character (String binärString)
|
|
{
|
|
byte a = binärString_to_Byte(binärString.substring(0,8));
|
|
byte b = binärString_to_Byte(binärString.substring(8,16));
|
|
byte[] array = new byte[] {a,b};
|
|
if(array[0] == nullCharBytes[0] && array[1] == nullCharBytes[1])return null;
|
|
var byteBuffer = ByteBuffer.wrap(array);
|
|
|
|
return byteBuffer.getChar(0); //erstellt aus den zwei bytes ein char
|
|
}
|
|
|
|
public static String baum_to_binärString (Node baum)
|
|
{
|
|
if(baum == null)return "";
|
|
|
|
String binärString = character_to_binärString(baum.getBuchstabe());
|
|
binärString += baum_to_binärString(baum.getLeft()); //speichert pre order die Buchstaben als binär ab
|
|
binärString += baum_to_binärString(baum.getRight());
|
|
return binärString;
|
|
}
|
|
|
|
public static Node binärString_to_baum (String s)
|
|
{
|
|
Node root = null;
|
|
Stack<Node> äste = new Stack<Node>(); //erstellt ein leeres Stack
|
|
for(int i=0;i<s.length();i+=16)
|
|
{
|
|
String characterString = s.substring(i,i+16); //geht in 16er schritten den binärString durch
|
|
Character c = binärString_to_character(characterString); //wandelt characterString zu character um
|
|
Node node = new Node();
|
|
node.setBuchstabe(c);
|
|
if(i == 0)root = node;
|
|
|
|
if(äste.isEmpty() == false) //baut die Nodes zum Baum bis nur noch die wurzel übrig ist
|
|
{
|
|
Node elternAst = äste.peek();
|
|
|
|
elternAst.add(node);
|
|
if(elternAst.hatPlatzKinder() == false)
|
|
{
|
|
äste.pop();
|
|
}
|
|
}
|
|
|
|
if(c == null)
|
|
{
|
|
äste.push(node);
|
|
}
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
public static Integer binärString_to_int(String binärString)
|
|
{
|
|
if(binärString.length() != 32)
|
|
{
|
|
System.out.println(">32");
|
|
return null;
|
|
}
|
|
|
|
int result = 0;
|
|
for(int i=0 ;i<32;i++) //geht den binärString durch und wandelt ihn int um
|
|
{
|
|
if(binärString.charAt(31-i) == '1')result|=1<<i; //verschiebt die 1 um i binärpositionen nach links
|
|
else if(binärString.charAt(31-i) != '0')
|
|
{
|
|
System.out.println("was flasch");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static String Int_to_binärString (int a)
|
|
{
|
|
String result = "";
|
|
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
boolean bit= ((a>>(31-i))&1)==1;
|
|
result+= bit?'1': '0'; //falls bit wert 1 hat addiert es 1 zu dem string, wenn nicht dann addiertes es 0
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//komprimiert Datei
|
|
public static void compressFile (String source, String target )
|
|
{
|
|
Path sourcePath = Path.of(source);
|
|
Path targetPath = Path.of(target);
|
|
|
|
if(Files.exists(sourcePath) == false) //überprüft ob im Dateipfad eine Datei hinterlegt ist
|
|
{
|
|
System.out.println("Datei nicht gefunden");
|
|
return;
|
|
}
|
|
|
|
String text;
|
|
|
|
try
|
|
{
|
|
text = Files.readString(sourcePath);
|
|
}
|
|
catch(Exception error) //gibt error aus falls einer auftrit
|
|
{
|
|
System.out.println(error);
|
|
return;
|
|
}
|
|
|
|
String compressedText = codierungInklBaum(text);
|
|
|
|
try
|
|
{
|
|
Files.writeString(targetPath, compressedText);
|
|
}
|
|
catch(Exception error)
|
|
{
|
|
System.out.println(error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//liest die Datei
|
|
public static void readFile(String file)
|
|
{
|
|
Path path = Path.of(file);
|
|
|
|
if(Files.exists(path) == false)
|
|
{
|
|
System.out.println("Datei nicht gefunden");
|
|
return;
|
|
}
|
|
|
|
String compressedText;
|
|
|
|
try
|
|
{
|
|
compressedText = Files.readString(path);
|
|
}
|
|
catch(Exception error)
|
|
{
|
|
System.out.println(error);
|
|
return;
|
|
}
|
|
|
|
String text = decodierungInlkBaum(compressedText);
|
|
|
|
System.out.println(file+": " + text);
|
|
}
|
|
}
|