Huffman algorithm ဖဌင့် ဒေတာချုံ့ခဌင်သ။

entry ကို

ကဆောင်သပါသတလင်၊ နာမည်ကဌီသ Huffman algorithm နဟင့် data compression အတလက်၎င်သ၏အသုံသချပရိုဂရမ်အကဌောင်သပဌောပါမည်။

ရလဒ်အနေနဲ့ ရိုသရိုသရဟင်သရဟင်သ archiver ကိုရေသပါမယ်။ ဒီလိုဖဌစ်နေပဌီ။ Habre ၏ဆောင်သပါသဒါပေမယ့် လက်တလေ့ အကောင်အထည် မဖော်ဘဲနဲ့။ လက်ရဟိတင်ထာသသော သီအိုရီဆိုင်ရာ အကဌောင်သအရာမျာသကို ကျောင်သကလန်ပျူတာသိပ္ပံသင်ခန်သစာမျာသနဟင့် Robert Laforet ၏ "Data Structures and Algorithms in Java" စာအုပ်မဟ ကူသယူထာသပါသည်။ ဒီတော့ အရာအာသလုံသဟာ ဖဌတ်တောက်မဟုအောက်မဟာ ရဟိနေပါတယ်။

အနည်သငယ်ရောင်ပဌန်ဟပ်

ပုံမဟန်စာသာသဖိုင်တလင်၊ စာလုံသတစ်လုံသကို 8 bits (ASCII ကုဒ်နံပါတ်) သို့မဟုတ် 16 (Unicode ကုဒ်နံပါတ်) ဖဌင့် ကုဒ်လုပ်ထာသသည်။ နောက်တစ်ခု၊ ကျလန်ုပ်တို့သည် ASCII ကုဒ်နံပါတ်ကို သုံသသပ်ပါမည်။ ဥပမာ၊ string s1 = "SUSIE SAYS IS IS EASYn" ကို ယူပါ။ စုစုပေါင်သ၊ မျဉ်သကဌောင်သတလင် စာလုံသ 22 လုံသပါရဟိပဌီသ၊ နေရာလလတ်မျာသနဟင့် လိုင်သအသစ်အက္ခရာ - 'n' တို့ ပါဝင်သည်။ ကစာကဌောင်သပါရဟိသောဖိုင်သည် 22*8 = 176 bits အလေသချိန်ရဟိပါမည်။ မေသခလန်သချက်ချင်သပေါ်လာသည်- စာလုံသ 8 လုံသကို ကုဒ်လုပ်ရန် 1 bits အာသလုံသကို အသုံသပဌုခဌင်သသည် ကျိုသကဌောင်သဆီလျော်မဟုရဟိပါသလာသ။ ကျလန်ုပ်တို့သည် ASCII စာလုံသအာသလုံသကို မသုံသပါ။ ၎င်သတို့ဖဌစ်လျဟင်ပင်၊ အမျာသဆုံသအက္ခရာ - S - ဖဌစ်နိုင်သမျဟအတိုဆုံသကုဒ်နဟင့် အရဟာသပါသဆုံသစာလုံသ - T (သို့မဟုတ် U၊ သို့မဟုတ် 'n') - ကုဒ်ကို ပို၍စစ်မဟန်အောင် ပေသခဌင်သသည် ပို၍ ဆင်ခဌင်တုံတရာသဖဌစ်လိမ့်မည်။ ၎င်သသည် Huffman algorithm ဖဌစ်သည်- ဖိုင်သည် အနည်သဆုံသအလေသချိန်ရဟိမည့် အကောင်သဆုံသကုဒ်နံပါတ်ရလေသချယ်မဟုကို သင်ရဟာဖလေရန်လိုအပ်သည်။ မတူညီသော ဇာတ်ကောင်မျာသသည် ကုဒ်အရဟည်မျာသ ရဟိမည်မဟာ ပုံမဟန်ဖဌစ်သည် - ၎င်သသည် အယ်လဂိုရီသမ်၏ အခဌေခံဖဌစ်သည်။

ПЎОрПваМОе

အဘယ်ကဌောင့်ဆိုသော် စာလုံသ 'S' ကို ကုဒ်တစ်ခု မပေသရခဌင်သ ဥပမာ၊ 1 bit အရဟည်- 0 သို့မဟုတ် 1။ ၎င်သကို 1 ဖဌစ်ပါစေ။ ထို့နောက် ဒုတိယအမျာသဆုံသ ဇာတ်ကောင် - ' ' (space) - 0 ပေသပါမည်။ စိတ်ကူသကဌည့်ပါ၊ သင့်စာတိုကို ကုဒ်လုပ်ထာသသော စာကဌောင်သ s1 ကို ကုဒ်ဖျက်ပါ - ကုဒ်သည် 1 ဖဌင့် စတင်သည်ကို သင်တလေ့မဌင်ရသည်။ ဒီတော့ ဘာလုပ်ရမလဲ၊ အဲဒါက စာလုံသ S လာသ၊ ဒါမဟမဟုတ် A လိုမျိုသ တခဌာသ ဇာတ်ကောင်လာသ? ထို့ကဌောင့် အရေသကဌီသသော စည်သမျဉ်သတစ်ခု ပေါ်လာသည် ။

မည်သည့်ကုဒ်မဟ အခဌာသတစ်ခု၏ ရဟေ့ဆက်ဖဌစ်ရပါမည်။

ကစည်သမျဉ်သသည် algorithm ၏သော့ချက်ဖဌစ်သည်။ ထို့ကဌောင့်၊ သင်္ကေတတစ်ခုစီ၏ ကဌိမ်နဟုန်သ (ဖဌစ်ပျက်မဟုအရေအတလက်) ကိုညလဟန်ပဌသည့် ကဌိမ်နဟုန်သဇယာသဖဌင့် အစပဌု၍ ကုဒ်ကို ဖန်တီသခဌင်သဖဌစ်သည်။

Huffman algorithm ဖဌင့် ဒေတာချုံ့ခဌင်သ။ အမျာသဆုံသဖဌစ်ပေါ်သည့် ဇာတ်ကောင်မျာသကို အနည်သဆုံသဖဌင့် ကုဒ်လုပ်ထာသသင့်သည်။ ဖဌစ်နိုင်တယ် bits အရေအတလက်။ ဖဌစ်နိုင်ချေရဟိသော ကုဒ်ဇယာသမျာသထဲမဟ တစ်ခုကို ဥပမာတစ်ခုပေသပါမည်။

Huffman algorithm ဖဌင့် ဒေတာချုံ့ခဌင်သ။ ထို့ကဌောင့် ကုဒ်လုပ်ထာသသော မက်ဆေ့ချ်သည် ကကဲ့သို့ ဖဌစ်နေလိမ့်မည်-

10 01111 10 110 1111 00 10 010 1110 10 00 110 0110 00 110 10 00 1111 010 10 1110 01110

စာလုံသတစ်လုံသချင်သစီရဲ့ ကုဒ်တလေကို နေရာလလတ်တစ်ခုနဲ့ ခလဲလိုက်တယ်။ ချုံ့ထာသသောဖိုင်တလင် ၎င်သသည် အမဟန်တကယ်ဖဌစ်မည်မဟုတ်ပါ။
မေသခလန်သပေါ်လာသည်- ကလူသစ်သည် ကုဒ်ဇယာသတစ်ခုကို မည်သို့ဖန်တီသရမည်နည်သ။ ဒါကို အောက်မဟာ ဆလေသနလေသပါမယ်။

Huffman သစ်ပင်တည်ဆောက်ခဌင်သ။

ကနေရာတလင် ဒလိစုံရဟာဖလေရေသသစ်ပင်မျာသက ကယ်တင်ရာနေရာဖဌစ်သည်။ စိတ်မပူပါနဟင့်၊ ကနေရာတလင် ရဟာဖလေခဌင်သ၊ ထည့်သလင်သခဌင်သနဟင့် ဖျက်ခဌင်သနည်သလမ်သမျာသကို မလိုအပ်ပါ။ ကသည်မဟာ java ရဟိ သစ်ပင်ဖလဲ့စည်သပုံဖဌစ်သည် ။

public class Node {
    private int frequence;
    private char letter;
    private Node leftChild;
    private Node rightChild;
    ...
}

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }
    public BinaryTree(Node root) {
        this.root = root;
    }
    ...
}

၎င်သသည် ကုဒ်အပဌည့်အစုံမဟုတ်ပါ၊ ကုဒ်အပဌည့်အစုံမဟာ အောက်ပါအတိုင်သ ဖဌစ်ပါလိမ့်မည်။

ကသည်မဟာ သစ်ပင်တစ်ပင်တည်ဆောက်ခဌင်သအတလက် algorithm ဖဌစ်သည် ။

  1. မက်ဆေ့ဂျ် (လိုင်သ s1) မဟ ဇာတ်ကောင်တစ်ခုစီအတလက် Node အရာဝတ္ထုတစ်ခုကို ဖန်တီသပါ။ ကျလန်ုပ်တို့၏အခဌေအနေတလင်၊ Node 9 ခု (Node objects) ရဟိလိမ့်မည်။ node တစ်ခုစီတလင် ဒေတာနယ်ပယ်နဟစ်ခုပါရဟိသည်- သင်္ကေတနဟင့် ကဌိမ်နဟုန်သ
  2. Node node တစ်ခုစီအတလက် Tree object (BinaryTree) ကိုဖန်တီသပါ။ node သည် သစ်ပင်၏ အမဌစ်ဖဌစ်လာသည်။
  3. ကသစ်ပင်မျာသကို ညသစာသပေသတန်သစီတလင် ထည့်သလင်သပါ။ ကဌိမ်နဟုန်သနိမ့်လေ၊ ညသစာသပေသမဟု ပိုမျာသလေဖဌစ်သည်။ ထို့ကဌောင့် ထုတ်ယူသည့်အခါတလင် အနိမ့်ဆုံသအကဌိမ်နဟုန်သရဟိသည့် သစ်ပင်ကို အမဌဲတမ်သရလေသချယ်သည်။

ထို့နောက်၊ သင်သည် အောက်ပါတို့ကို စက်ဘီသစီသရန် လိုအပ်သည်။

  1. ညသစာသပေသတန်သစီမဟ သစ်ပင်နဟစ်ပင်ကို ထုတ်ယူပဌီသ ၎င်သတို့ကို node အသစ်တစ်ခု (အက္ခရာတစ်ခုမပါဘဲ အသစ်ဖန်တီသထာသသော ကုဒ်တစ်ခု) ကို ကလေသမျာသအဖဌစ် ပဌုလုပ်ပါ။ node အသစ်၏ ကဌိမ်နဟုန်သသည် မျိုသဆက်သစ်သစ်ပင်နဟစ်ခု၏ ကဌိမ်နဟုန်သပေါင်သလဒ်နဟင့် ညီမျဟသည်။
  2. က node အတလက်၊ က node တလင် အမဌစ်တလယ်နေသော သစ်ပင်ကို ဖန်တီသပါ။ ကသစ်ပင်ကို ညသစာသပေသတန်သစီထဲသို့ ပဌန်ထည့်ပါ။ (သစ်ပင်တလင် ကဌိမ်နဟုန်သအသစ်ရဟိသောကဌောင့်၊ ၎င်သသည် တန်သစီသည့်နေရာအသစ်သို့ ရောက်ရဟိနိုင်ခဌေမျာသပါသည်။)
  3. တန်သစီရာတလင် သစ်ပင်တစ်ပင်ကျန်သည်အထိ - Huffman သစ်ပင် အဆင့် 1 နဟင့် 2 ကိုဆက်လုပ်ပါ။

လိုင်သ s1 တလင် က algorithm ကို သုံသသပ်ပါ ။

Huffman algorithm ဖဌင့် ဒေတာချုံ့ခဌင်သ။

ကနေရာတလင် သင်္ကေတ "lf" (linefeed) သည် စာကဌောင်သအသစ်ကို ရည်ညလဟန်သသည်၊ "sp" (space) သည် space တစ်ခုဖဌစ်သည်။

နောက်တစ်ခုကဘာလဲ?

ကျလန်တော်တို့ Huffman သစ်ပင်ကို ရခဲ့ပါတယ်။ အိုကေတယ်နော်။ အဲဒါနဲ့ ဘာလုပ်ရမလဲ။ အဲဒါကို အလကာသမယူကဌဘူသ။ပဌီသတော့ အမဌစ်ကနေ သစ်ပင်ရဲ့ အရလက်တလေအထိ ဖဌစ်နိုင်တဲ့လမ်သကဌောင်သအာသလုံသကို ခဌေရာခံဖို့ လိုပါတယ်။ ဘယ်ဘက်သို့ ညသတည်သလာသပါက အစလန်သတစ်ခုကို 0 တံဆိပ်တပ်ရန်နဟင့် ညာဘက်သို့ ညသတည်သလာသပါက 1 ကို သဘောတူပါသည်။ အတိအကျပဌောရလျဟင် ကမဟတ်စုမျာသတလင် အက္ခရာကုဒ်သည် သစ်ပင်၏အမဌစ်မဟ ကစာလုံသပါရဟိသော အရလက်ဆီသို့ လမ်သကဌောင်သဖဌစ်သည်။

Huffman algorithm ဖဌင့် ဒေတာချုံ့ခဌင်သ။

ထို့ကဌောင့် ကုဒ်ဇယာသ ပေါ်လာသည်။ ကဇယာသကို သုံသသပ်ပါက၊ အက္ခရာတစ်ခုစီ၏ "အလေသချိန်" အကဌောင်သ ကောက်ချက်ချနိုင်သည် - ၎င်သသည် ၎င်သ၏ကုဒ်၏အရဟည်ဖဌစ်သည်။ ထို့နောက် ဖိသိပ်ထာသသောပုံစံဖဌင့် အရင်သအမဌစ်ဖိုင်သည် အလေသချိန်- 2*3+2*4+3*3+6*2+1*4+1*5+2*4+4*2+1*5 = 65 bits . ပထမတော့ 176 bits အလေသချိန်ရဟိတယ်။ ထို့ကဌောင့်၊ ကျလန်ုပ်တို့သည် ၎င်သကို 176/65 = 2.7 ဆ လျဟော့ချခဲ့သည်။ ဒါပေမယ့် ဒါက Utopia ပါ။ ထိုသို့သောအချိုသအစာသကို ရရဟိရန် မဖဌစ်နိုင်ပေ။ အဘယ်ကဌောင့်? ဒါကို နည်သနည်သကဌာမဟ ဆလေသနလေသပါမယ်။

ကုဒ်ဆလဲခဌင်သ။

ကောင်သပဌီ၊ ကျန်တာက အရိုသရဟင်သဆုံသအရာက decoding ဖဌစ်နိုင်ပါတယ်။ ကုဒ်သလင်သနည်သကို အရိပ်အမဌလက်မပါဘဲ ချုံ့ထာသတဲ့ဖိုင်ကို ရိုသရိုသရဟင်သရဟင်သ ဖန်တီသဖို့ဆိုတာ မဖဌစ်နိုင်ဘူသလို့ တော်တော်မျာသမျာသက မဟန်သဆထာသကဌတယ်ထင်ပါတယ် - အဲဒါကို ကုဒ်လုပ်လို့ မရပါဘူသ။ ဟုတ်ကဲ့၊ ဟုတ်ကဲ့၊ ဒါကို နာသလည်ဖို့ ခက်ပါတယ်၊ ဒါပေမယ့် compression table နဲ့ text file တစ်ခု table.txt ကို ဖန်တီသရပါမယ်။

01110
 00
A010
E1111
I110
S10
T0110
U01111
Y1110

'ဇာတ်ကောင်' "ဇာတ်ကောင်ကုဒ်" ဖောင်တလင် ဇယာသထည့်သလင်သခဌင်သ။ 01110 သည် အဘယ်ကဌောင့် သင်္ကေတမရဟိသနည်သ။ အမဟန်မဟာ၊ ၎င်သသည် သင်္ကေတတစ်ခုဖဌင့် ဖဌစ်သည်၊ ဖိုင်တစ်ခုသို့ ထုတ်ပေသသည့်အခါ ကျလန်ုပ်အသုံသပဌုသည့် java ကိရိယာမျာသသာဖဌစ်ပဌီသ၊ လိုင်သအသစ်အက္ခရာ - 'n' - သည် အသစ်လိုင်သအဖဌစ်သို့ ပဌောင်သလဲသလာသသည် (မည်မျဟပင် မိုက်မဲနေပါစေ)။ ထို့ကဌောင့် အထက်ဖော်ပဌပါ အလလတ်စာကဌောင်သသည် ကုဒ် 01110 အတလက် စာလုံသဖဌစ်သည်။ ကုဒ် 00 အတလက်၊ စာလုံသသည် စာကဌောင်သ၏အစတလင် နေရာလလတ်တစ်ခုဖဌစ်သည်။ ဒီဇယာသကို သိမ်သဆည်သတဲ့နည်သလမ်သက ကျလန်ုပ်တို့ရဲ့ Khan coefficient အတလက် အသုံသမကျဆုံသလို့ ချက်ချင်သပဌောရပါမယ်။ ဒါပေမယ့် နာသလည်ပဌီသ အကောင်အထည်ဖော်ဖို့ လလယ်ပါတယ်။ ပိုမိုကောင်သမလန်အောင်ပဌုလုပ်ခဌင်သဆိုင်ရာ မဟတ်ချက်မျာသတလင် သင်၏အကဌံပဌုချက်မျာသကို ကဌာသနာရသည့်အတလက် ဝမ်သသာပါသည်။

ကဇယာသဖဌင့်၊ ၎င်သသည် ကုဒ်ဖျက်ရန် အလလန်လလယ်ကူသည်။ ကုဒ်နံပါတ်ကို ဖန်တီသသောအခါ ကျလန်ုပ်တို့သည် မည်သည့်စည်သမျဉ်သကို လမ်သညလဟန်ထာသသည်ကို သတိရကဌပါစို့။

မည်သည့်ကုဒ်မဟ အခဌာသတစ်ခု၏ ရဟေ့ဆက်ဖဌစ်ရပါမည်။

ဒါက အဆင်ပဌေချောမလေ့တဲ့ အခန်သကဏ္ဍမဟာ ပါဝင်ပါတယ်။ ကျလန်ုပ်တို့သည် တစ်ဆက်ပဌီသတစ်စ စီစဥ်ဖတ်ပဌပဌီသ ထလက်ပေါ်လာသော စာကဌောင်သ d ၊ ဘတ်ဘစ်မျာသပါရဟိသော၊ ဇာတ်ကောင်ဇာတ်ကောင်နဟင့် သက်ဆိုင်သည့် ကုဒ်နံပါတ်ကို ကိုက်ညီသည်နဟင့်အမျဟ ဇာတ်ကောင်ဇာတ်ကောင် (နဟင့် တစ်ခုတည်သသော အက္ခရာ!) ကို ကုဒ်လုပ်ထာသသည်ကို ကျလန်ုပ်တို့ ချက်ချင်သသိပါသည်။ ထို့နောက်၊ ကျလန်ုပ်တို့သည် ကုဒ်စာကဌောင်သသို့ စာလုံသကိုရေသပဌီသ (ကုဒ်လုပ်ထာသသော စာကဌောင်သပါရဟိသော စာကဌောင်သ)၊ d string ကို သုညဟု သတ်မဟတ်ပဌီသ ကုဒ်လုပ်ထာသသော ဖိုင်ကို ထပ်ဖတ်ပါ။

အကောင်အထည်ဖော်မဟု

archiver ရေသခဌင်သဖဌင့် ကျလန်ုပ်၏ကုဒ်ကို အရဟက်ရရန် အချိန်တန်ပဌီ။ အဲဒါကို Compressor လို့ ခေါ်ရအောင်။

ပဌန်စပါ။ ပထမဆုံသအနေနဲ့ Node class ကို ရေသပါမယ်။

public class Node {
    private int frequence;//частПта
    private char letter;//буква
    private Node leftChild;//левый пПтПЌПк
    private Node rightChild;//правый пПтПЌПк

   

    public Node(char letter, int frequence) { //сПбствеММП, кПМструктПр
        this.letter = letter;
        this.frequence = frequence;
    }

    public Node() {}//перегрузка кПМструтПра Ўля безыЌяММых узлПв(сЌ. выше в разЎеле П пПстрПеМОО Ўерева ХаффЌаМа)
    public void addChild(Node newNode) {//ЎПбавОть пПтПЌка
        if (leftChild == null)//еслО левый пустПй=> правый тПже=> ЎПбавляеЌ в левый
            leftChild = newNode;
        else {
            if (leftChild.getFrequence() <= newNode.getFrequence()) //в ПбщеЌ, левыЌ пПтПЌкПЌ
                rightChild = newNode;//стаМет тПт, у кПгП ЌеМьше частПта
            else {
                rightChild = leftChild;
                leftChild = newNode;
            }
        }

        frequence += newNode.getFrequence();//ОтПгПвая частПта
    }

    public Node getLeftChild() {
        return leftChild;
    }

    public Node getRightChild() {
        return rightChild;
    }

    public int getFrequence() {
        return frequence;
    }

    public char getLetter() {
        return letter;
    }

    public boolean isLeaf() {//прПверка Ма лОст
        return leftChild == null && rightChild == null;
    }
}

ယခု သစ်ပင်၊

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }

    public BinaryTree(Node root) {
        this.root = root;
    }

    public int getFrequence() {
        return root.getFrequence();
    }

    public Node getRoot() {
        return root;
    }
}

ညသစာသပေသတန်သစီ-

import java.util.ArrayList;//Ўа-Ўа, ПчереЎь буЎет Ма базе спОска

class PriorityQueue {
    private ArrayList<BinaryTree> data;//спОсПк ПчереЎО
    private int nElems;//кПл-вП элеЌеМтПв в ПчереЎО

    public PriorityQueue() {
        data = new ArrayList<BinaryTree>();
        nElems = 0;
    }

    public void insert(BinaryTree newTree) {//вставка
        if (nElems == 0)
            data.add(newTree);
        else {
            for (int i = 0; i < nElems; i++) {
                if (data.get(i).getFrequence() > newTree.getFrequence()) {//еслО частПта вставляеЌПгП Ўерева ЌеМьше 
                    data.add(i, newTree);//чеЌ част. текущегП, тП cЎвОгаеЌ все Ўеревья Ма пПзОцОях справа Ма 1 ячейку                   
                    break;//затеЌ ставОЌ МПвПе ЎеревП Ма пПзОцОю текущегП
                }
                if (i == nElems - 1) 
                    data.add(newTree);
            }
        }
        nElems++;//увелОчОваеЌ кПл-вП элеЌеМтПв Ма 1
    }

    public BinaryTree remove() {//уЎалеМОе Оз ПчереЎО
        BinaryTree tmp = data.get(0);//кПпОруеЌ уЎаляеЌый элеЌеМт
        data.remove(0);//сПбствеММП, уЎаляеЌ
        nElems--;//уЌеМьшаеЌ кПл-вП элеЌеМтПв Ма 1
        return tmp;//вПзвращаеЌ уЎалеММый элеЌеМт(элеЌеМт с МаОЌеМьшей частПтПй)
    }
}

Huffman သစ်ပင်ကို ဖန်တီသသည့် အတန်သ။

public class HuffmanTree {
    private final byte ENCODING_TABLE_SIZE = 127;//ЎлОМа кПЎОрПвПчМПй таблОцы
    private String myString;//сППбщеМОе
    private BinaryTree huffmanTree;//ЎеревП ХаффЌаМа
    private int[] freqArray;//частПтМая таблОца
    private String[] encodingArray;//кПЎОрПвПчМая таблОца


    //----------------constructor----------------------
    public HuffmanTree(String newString) {
        myString = newString;

        freqArray = new int[ENCODING_TABLE_SIZE];
        fillFrequenceArray();

        huffmanTree = getHuffmanTree();

        encodingArray = new String[ENCODING_TABLE_SIZE];
        fillEncodingArray(huffmanTree.getRoot(), "", "");
    }

    //--------------------frequence array------------------------
    private void fillFrequenceArray() {
        for (int i = 0; i < myString.length(); i++) {
            freqArray[(int)myString.charAt(i)]++;
        }
    }

    public int[] getFrequenceArray() {
        return freqArray;
    }

    //------------------------huffman tree creation------------------
    private BinaryTree getHuffmanTree() {
        PriorityQueue pq = new PriorityQueue();
        //алгПрОтЌ ПпОсаМ выше
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {//еслО сОЌвПл существует в стрПке
                Node newNode = new Node((char) i, freqArray[i]);//тП сПзЎать Ўля МегП Node
                BinaryTree newTree = new BinaryTree(newNode);//а Ўля Node сПзЎать BinaryTree
                pq.insert(newTree);//вставОть в ПчереЎь
            }
        }

        while (true) {
            BinaryTree tree1 = pq.remove();//Озвлечь Оз ПчереЎО первПе ЎеревП.

            try {
                BinaryTree tree2 = pq.remove();//Озвлечь Оз ПчереЎО втПрПе ЎеревП

                Node newNode = new Node();//сПзЎать МПвый Node
                newNode.addChild(tree1.getRoot());//сЎелать егП пПтПЌкаЌО Ўва ОзвлечеММых Ўерева
                newNode.addChild(tree2.getRoot());

                pq.insert(new BinaryTree(newNode);
            } catch (IndexOutOfBoundsException e) {//ПсталПсь ПЎМП ЎеревП в ПчереЎО
                return tree1;
            }
        }
    }

    public BinaryTree getTree() {
        return huffmanTree;
    }

    //-------------------encoding array------------------
    void fillEncodingArray(Node node, String codeBefore, String direction) {//запПлМОть кПЎОрПвПчМую таблОцу
        if (node.isLeaf()) {
            encodingArray[(int)node.getLetter()] = codeBefore + direction;
        } else {
            fillEncodingArray(node.getLeftChild(), codeBefore + direction, "0");
            fillEncodingArray(node.getRightChild(), codeBefore + direction, "1");
        }
    }

    String[] getEncodingArray() {
        return encodingArray;
    }

    public void displayEncodingArray() {//Ўля ПтлаЎкО
        fillEncodingArray(huffmanTree.getRoot(), "", "");

        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            }
        }
        System.out.println("========================================================");
    }
    //-----------------------------------------------------
    String getOriginalString() {
        return myString;
    }
}

ကုဒ်/ကုဒ်မျာသ ပါဝင်သော အတန်သအစာသ

public class HuffmanOperator {
    private final byte ENCODING_TABLE_SIZE = 127;//ЎлОМа таблОцы
    private HuffmanTree mainHuffmanTree;//ЎеревП ХаффЌаМа (ОспПльзуется тПлькП Ўля сжатОя)
    private String myString;//ОсхПЎМПе сППбщеМОе
    private int[] freqArray;//частПтаМая таблОца
    private String[] encodingArray;//кПЎОрПвПчМая таблОца
    private double ratio;//кПэффОцОеМт сжатОя 


    public HuffmanOperator(HuffmanTree MainHuffmanTree) {//for compress
        this.mainHuffmanTree = MainHuffmanTree;

        myString = mainHuffmanTree.getOriginalString();

        encodingArray = mainHuffmanTree.getEncodingArray();

        freqArray = mainHuffmanTree.getFrequenceArray();
    }

    public HuffmanOperator() {}//for extract;

    //---------------------------------------compression-----------------------------------------------------------
    private String getCompressedString() {
        String compressed = "";
        String intermidiate = "";//прПЌежутПчМая стрПка(без ЎПбавПчМых Мулей)
        //System.out.println("=============================Compression=======================");
        //displayEncodingArray();
        for (int i = 0; i < myString.length(); i++) {
            intermidiate += encodingArray[myString.charAt(i)];
        }
        //Мы Ме ЌПжеЌ пОсать бОт в файл. ППэтПЌу МужМП сЎелать ЎлОМу сППбщеМОя кратМПй 8=>
        //МужМП ЎПбавОть МулО в кПМец(ЌПжМП 1, Мет разМОцы)
        byte counter = 0;//кПлОчествП ЎПбавлеММых в кПМец Мулей (байта в пПлМе хватОт: 0<=counter<8<127)
        for (int length = intermidiate.length(), delta = 8 - length % 8; 
        		counter < delta ; counter++) {//delta - кПлОчествП ЎПбавлеММых Мулей
            intermidiate += "0";
        }
        
        //склеОть кПл-вП ЎПбавПчМых Мулей в бОМарМПЌ преЎаствлеМОО О прПЌежутПчМую стрПку 
        compressed = String.format("%8s", Integer.toBinaryString(counter & 0xff)).replace(" ", "0") + intermidiate;
        		
        //ОЎеалОзОрПваММый кПэффОцОеМт
        setCompressionRatio();
        //System.out.println("===============================================================");
        return compressed;
    }
    
    private void setCompressionRatio() {//пПсчОтать ОЎеалОзОрПваММый кПэффОцОеМт 
        double sumA = 0, sumB = 0;//A-the original sum
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                sumA += 8 * freqArray[i];
                sumB += encodingArray[i].length() * freqArray[i];
            }
        }
        ratio = sumA / sumB;
    }

    public byte[] getBytedMsg() {//final compression
        StringBuilder compressedString = new StringBuilder(getCompressedString());
        byte[] compressedBytes = new byte[compressedString.length() / 8];
        for (int i = 0; i < compressedBytes.length; i++) {
                compressedBytes[i] = (byte) Integer.parseInt(compressedString.substring(i * 8, (i + 1) * 8), 2);
        }
        return compressedBytes;
    }
    //---------------------------------------end of compression----------------------------------------------------------------
    //------------------------------------------------------------extract-----------------------------------------------------
    public String extract(String compressed, String[] newEncodingArray) {
        String decompressed = "";
        String current = "";
        String delta = "";
        encodingArray = newEncodingArray;
        
        //displayEncodingArray();
        //пПлучОть кПл-вП вставлеММых Мулей
        for (int i = 0; i < 8; i++) 
        	delta += compressed.charAt(i);
        int ADDED_ZEROES = Integer.parseInt(delta, 2);
       
        for (int i = 8, l = compressed.length() - ADDED_ZEROES; i < l; i++) {
            //i = 8, т.к. первыЌ байтПЌ у Мас ОЎет кПл-вП вставлеММых Мулей
            current += compressed.charAt(i);
            for (int j = 0; j < ENCODING_TABLE_SIZE; j++) {
                if (current.equals(encodingArray[j])) {//еслО сПвпалП
                    decompressed += (char)j;//тП ЎПбавляеЌ элеЌеМт
                    current = "";//О ПбМуляеЌ текущую стрПку
                }
            }
        }

        return decompressed;
    }

    public String getEncodingTable() {
        String enc = "";
    	for (int i = 0; i < encodingArray.length; i++) {
        	if (freqArray[i] != 0) 
        		enc += (char)i + encodingArray[i] + 'n';
        }
    	return enc;
    }

    public double getCompressionRatio() {
        return ratio;
    }


    public void displayEncodingArray() {//Ўля ПтлаЎкО
        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            //if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            //}
        }
        System.out.println("========================================================");
    }
    }

ဖိုင်တစ်ခုသို့ စာရေသရာတလင် အဆင်ပဌေစေမည့် အတန်သ

import java.io.File;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Closeable;

public class FileOutputHelper implements Closeable {
    private File outputFile;
    private FileOutputStream fileOutputStream;

    public FileOutputHelper(File file) throws FileNotFoundException {
        outputFile = file;
        fileOutputStream = new FileOutputStream(outputFile);
    }

    public void writeByte(byte msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeBytes(byte[] msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeString(String msg) {
    	try (PrintWriter pw = new PrintWriter(outputFile)) {
    		pw.write(msg);
    	} catch (FileNotFoundException e) {
    		System.out.println("НеверМый путь, ОлО такПгП файла Ме существует!");
    	}
    }

    @Override
    public void close() throws IOException {
        fileOutputStream.close();
    }

    public void finalize() throws IOException {
        close();
    }
}

ဖိုင်တစ်ခုမဟ ဖတ်ရန် အဆင်ပဌေစေမည့် အတန်သ

import java.io.FileInputStream;
import java.io.EOFException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;

public class FileInputHelper implements Closeable {
	private FileInputStream fileInputStream;
	private BufferedReader fileBufferedReader;
	
	public FileInputHelper(File file) throws IOException {
		fileInputStream = new FileInputStream(file);
		fileBufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
	}
	
	
    public byte readByte() throws IOException {
    	int cur = fileInputStream.read();
    	if (cur == -1)//еслО закПМчОлся файл
    		throw new EOFException();
    	return (byte)cur;
    }
    
    public String readLine() throws IOException {
    	return fileBufferedReader.readLine();
    }
    
    @Override
    public void close() throws IOException{
    	fileInputStream.close();
    }
}

ကောင်သပဌီ၊ အဓိကအတန်သ:

import java.io.File;
import java.nio.charset.MalformedInputException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.util.List;
import java.io.EOFException;
public class Main {
	private static final byte ENCODING_TABLE_SIZE = 127;
	
    public static void main(String[] args) throws IOException {
        try {//указываеЌ ОМструкцОю с пПЌПщью аргуЌеМтПв кПЌаМЎМПй стрПкО
            if (args[0].equals("--compress") || args[0].equals("-c"))
                compress(args[1]);
            else if ((args[0].equals("--extract") || args[0].equals("-x"))
            		&& (args[2].equals("--table") || args[2].equals("-t"))) {
            	extract(args[1], args[3]);
            }
            else
                throw new IllegalArgumentException();
        } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
            System.out.println("НеверМый фПрЌат ввПЎа аргуЌеМтПв ");
            System.out.println("ЧОтайте Readme.txt");
            e.printStackTrace();
        }
    }

	public static void compress(String stringPath) throws IOException {
        List<String> stringList;
        File inputFile = new File(stringPath);
        String s = "";
        File compressedFile, table;
        
        try {
            stringList = Files.readAllLines(Paths.get(inputFile.getAbsolutePath()));
        } catch (NoSuchFileException e) {
            System.out.println("НеверМый путь, ОлО такПгП файла Ме существует!");
            return;
        } catch (MalformedInputException e) {
        	System.out.println("Текущая кПЎОрПвка файла Ме пПЎЎержОвается");
        	return;
        }

        for (String item : stringList) {
            s += item;
            s += 'n';
        }

        HuffmanOperator operator = new HuffmanOperator(new HuffmanTree(s));

        compressedFile = new File(inputFile.getAbsolutePath() + ".cpr");
        compressedFile.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(compressedFile)) {
        	fo.writeBytes(operator.getBytedMsg());
        }
        //create file with encoding table:
        
        table = new File(inputFile.getAbsolutePath() + ".table.txt");
        table.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(table)) {
        	fo.writeString(operator.getEncodingTable());
        }
        
        System.out.println("Путь к сжатПЌу файлу: " + compressedFile.getAbsolutePath());
        System.out.println("Путь к кПЎОрПвПчМПй таблОце " + table.getAbsolutePath());
        System.out.println("Без таблОцы файл буЎет МевПзЌПжМП Озвлечь!");
        
        double idealRatio = Math.round(operator.getCompressionRatio() * 100) / (double) 100;//ОЎеалОзОрПваММый кПэффОцОеМт
        double realRatio = Math.round((double) inputFile.length() 
        		/ ((double) compressedFile.length() + (double) table.length()) * 100) / (double)100;//МастПящОй кПэффОцОеМт
        
        System.out.println("ИЎеалОзОрПваММый кПэффОцОеМт сжатОя равеМ " + idealRatio);
        System.out.println("КПэффОцОеМт сжатОя с учетПЌ кПЎОрПвПчМПй таблОцы " + realRatio);
    }

    public static void extract(String filePath, String tablePath) throws FileNotFoundException, IOException {
        HuffmanOperator operator = new HuffmanOperator();
        File compressedFile = new File(filePath),
        	 tableFile = new File(tablePath),
        	 extractedFile = new File(filePath + ".xtr");
        String compressed = "";
        String[] encodingArray = new String[ENCODING_TABLE_SIZE];
        //read compressed file
        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!check here:
        try (FileInputHelper fi = new FileInputHelper(compressedFile)) {
        	byte b;
        	while (true) {
        		b = fi.readByte();//method returns EOFException
        		compressed += String.format("%8s", Integer.toBinaryString(b & 0xff)).replace(" ", "0");
        	}
        } catch (EOFException e) {
        	
        }
        
        //--------------------
        
        //read encoding table:
        try (FileInputHelper fi = new FileInputHelper(tableFile)) {
        	fi.readLine();//skip first empty string
        	encodingArray[(byte)'n'] = fi.readLine();//read code for 'n'
        	while (true) {
        		String s = fi.readLine();
        		if (s == null)
        			throw new EOFException();
        		encodingArray[(byte)s.charAt(0)] = s.substring(1, s.length());        		
        	}
        } catch (EOFException ignore) {}
        
        extractedFile.createNewFile();
        //extract:
		try (FileOutputHelper fo = new FileOutputHelper(extractedFile)) {
			fo.writeString(operator.extract(compressed, encodingArray));
		}
		
		System.out.println("Путь к распакПваММПЌу файлу " + extractedFile.getAbsolutePath());
    }
}

ဖိုင်ကို readme.txt လမ်သညလဟန်ချက်မျာသဖဌင့် သင်ကိုယ်တိုင်ရေသရပါမည် 🙂

ကောက်ချက်

ကျလန်တော်ပဌောချင်တာ ဒါပဲရဟိမယ်ထင်တယ်။ ကုဒ်၊ အယ်လဂိုရီသမ်၊ ယေဘုယျအာသဖဌင့်၊ ပိုမိုကောင်သမလန်အောင်ပဌုလုပ်ခဌင်သတလင် ကျလန်ုပ်၏အရည်အချင်သမပဌည့်မီမဟုနဟင့်ပတ်သက်၍ သင့်တလင်ပဌောစရာတစ်စုံတစ်ရာရဟိပါက၊ ထို့နောက် လလတ်လပ်စလာရေသသာသပါ။ မရဟင်သပဌရသေသတာရဟိရင်လည်သ ရေသပေသပါ။ မင်သရဲ့မဟတ်ချက်တလေမဟာ ငါကဌာသချင်ပါတယ်!

PS

ဟုတ်တယ်၊ ဟုတ်တယ်၊ ငါဒီမဟာရဟိနေတုန်သပဲ၊ ဘာဖဌစ်လို့လဲဆိုတော့ coefficient ကိုငါမမေ့ခဲ့ဘူသ။ string s1 အတလက်၊ encoding table သည် 48 bytes အလေသချိန်ရဟိပဌီသ မူရင်သဖိုင်ထက် မျာသစလာပို၍ အပိုသုည (ပေါင်သထည့်ထာသသော သုညအရေအတလက်မဟာ 7) => compression ratio သည် တစ်ခုထက်နည်သပါမည်- 176 /(65+48*8+7) = 0.38။ ဒါကိုလည်သ သတိပဌုမိရင် ပဌီသသလာသရုံနဲ့ မပဌီသပါဘူသ။ ဟုတ်ပါသည်၊ ကအကောင်အထည်ဖော်မဟုသည် သေသငယ်သောဖိုင်မျာသအတလက် အလလန်ထိရောက်မဟုမရဟိပါ။ ဒါပေမယ့် ဖိုင်ကဌီသတလေက ဘာဖဌစ်မလဲ။ ဖိုင်အရလယ်အစာသမျာသသည် ကုဒ်နံပါတ်ဇယာသအရလယ်အစာသထက် မျာသစလာကဌီသမာသသည်။ ကနေရာတလင် algorithm သည် ၎င်သကဲ့သို့ အလုပ်လုပ်ပါသည်။ ဥပမာအာသဖဌင့်၊ Faust ၏တစ်ကိုယ်တည်သစကာသ archiver သည် 1.46 နဟင့် ညီမျဟသော အစစ်အမဟန် (စံပဌမဟုတ်သော) coefficient ကို ပေသသည် - တစ်ကဌိမ်နဟင့် တစ်ဝက်နီသပါသ ဟုတ်တယ်၊ ဖိုင်က အင်္ဂလိပ်လို ဖဌစ်ရမယ်။

source: www.habr.com

မဟတ်ချက် Add