Forum: Projeler dkv RSS
Veri Sıkıştırma Modülü
Sayfa:  önceki  1  2  3  sonraki 
Kadir Can #16
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj ID 6666
Sıkıştırma işlemini dediğiniz gibi yaptım ama hala ya çok az sıkıştırıyor, ya da çok az boyutunu artırıyor.Bu sizce algoritma ile mi alakalı, yoksa programda bir hata mı var?
module huffman.d;
import std.stdio;
import std.conv;
import std.algorithm;
import std.string;
import std.math;
struct HuffmanTree
{
    private
    {
        uint[string] compressTable_;
        string[uint] decompressTable_;
        Node top_;
        File fileToCompress_;
        File compressedFile_;
        string fileName_;
    }
 
    public this(string fileName)
    {
        fileToCompress_.open(fileName ~ ".txt", "r");
        compressedFile_.open(fileName ~ "compressed" ~ ".txt", "w");
        fileName_ = fileName ~ ".txt";
    }
 
    ~this()
    {
        auto tables = File("tables.had", "w");
        tables.writeln(compressTable_);
        tables.writeln(decompressTable_);
        fileToCompress_.close();
        compressedFile_.close();
    }
 
    public void setTables(Node top)
    {
        compressTable_ = top_.returnTable;
        foreach(key, value; compressTable_){
            decompressTable_[value] = key;
        }
    }
 
    public void compressFile()
    {
        string lines;
        while(!fileToCompress_.eof()){
            lines ~= fileToCompress_.readln();
        }
        auto nodes = searchLetters(lines);
        top_ = createTree(nodes);
        top_.setBinaryCodes();
        setTables(top_);
        string compressedText;
        foreach(letter; lines){
            compressedText ~= format("%b", compressTable_[to!string(letter)]);
            if(compressedText.length >= 8){
                compressedFile_.writef("%s", toDecimal(compressedText[0 .. 8]));
                compressedText = compressedText[8 .. $];
            }
        }
    }
}
 
ubyte toDecimal(string number)
{
    ubyte result;
    for(int i = number.length - 1; i >= 0; --i ){
        result += to!ubyte(number[i]) * (pow(2, i));
    }
    return result;
}
unittest
{
    assert(toDecimal("110") == 6);
    assert(toDecimal("001") == 1);
}
 
struct Node
{
    private
    {
        string value_;
        uint binaryCode_;
        uint frequency_;
        Node* right_;
        Node* left_;
    }
 
    public this(const uint frequence, string value)
    {
        value_ = value;
        frequency_ = frequence;
    }
 
    public int opCmp(Node another) const
    {
        return frequency_ == another.frequency_ ? cmp(value_, another.value_) : frequency_ - another.frequency_ ;
    }
 
    public string toString() const
    {
        string result;
        result ~= "Binary code: " ~ to!string(binaryCode_) ~ "\n";
        result ~= "Letter: " ~ value_ ~ "\n";
        return result;
    }
 
    public void setBinaryCodes()
    {
        if(right_ && left_)
        {
            right_.binaryCode_ = binaryCode_;
            left_.binaryCode_ = binaryCode_;
            right_.binaryCode_ <<= 1;
            left_.binaryCode_ <<= 1;
            right_.binaryCode_ |= 1;
            right_.setBinaryCodes();
            left_.setBinaryCodes();
        }
    }
 
    public uint[string] returnTable() const @property
    { 
        uint[string] result;
        result[value_] = binaryCode_;
        if(right_ && left_)
        {
            foreach(index, value; left_.returnTable()){
                if(index.length==1){
                    result[index] = value;    
                } 
            }
            foreach(index, value; right_.returnTable()){
                if(index.length==1){
                    result[index] = value;
                } 
            }
        }
        foreach(index, value; result){
            if(index.length != 1){
                result.remove(index);
            }
        }
        return result;
    }
}
 
Node[] searchLetters(string text)
{
    uint[char] letters;
    Node[] result;
    foreach(character; text){
        if(character in letters){
            ++letters[character];
        } else {
            letters[character] = 1;
        }
    }
    foreach(index, value; letters){
        result ~= Node(value, to!string(index));
    }
    return result;
}
 
Node createTree(Node[] nodes)
{
    while(nodes.length > 1)
    {
        nodes.sort();
        auto newNode = Node((nodes[0].frequency_ + nodes[1].frequency_), (nodes[0].value_ ~ nodes[1].value_));
        newNode.left_ = &nodes[0];
        newNode.right_ = &nodes[1];
        nodes ~= newNode;
        nodes = nodes[2 .. $];
    }
    return nodes[0];
}
 
void main() 
{
    string fileName = "text";
    auto tree = HuffmanTree(fileName);
    tree.compressFile();
}
erdem (Moderatör) #17
Üye Tem 2009 tarihinden beri · 902 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Can çok güzel bir konu seçmişsin kendine. Ben de Huffman algoritmasını ilk kez duymuş oldum  :-)

Aslında algoritmayı öğrenip uğraşmak isterdim ama şimdilik ben de başka şeylerle uğraşıyorum.

Kod derleniyor. Ancak çalıştırdığım zaman ilkönce text.txt isimli bir dosyanın olmadığından yakınıyor.
std.exception.ErrnoException@std\stdio.d(288): Cannot open file `text.txt' in mode `r' (No such file or directory)
41CDEC
41CC77
402C03
40C7D0
40C80A
40C42B
421639

text isimli bir dosya oluşturduktan sonra ise şu hatayı veriyor.

core.exception.RangeError@huffman.d(176): Range violation
41CDEC
41CC77
402B9B
4022D4
402C12
40C7D0
40C80A
40C42B
421639
Kadir Can #18
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
@erdem;
Söylediğin hatayı dosya boşken alıyoruz, uyardığın için teşekkür ederim. Dosyanın boş olup olmadığını kontrol eden bir işlev ekliyorum hemen.
Avatar
huseyin #19
Üye Haz 2012 tarihinden beri · 355 mesaj · Konum: Isparta
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Evet haklısın dosya boşken hata veriyor
Huseyin
acehreli (Moderatör) #20
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4412 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #18
number.length'in türü size_t, i'nin türü int olduğu için toDecimal() içinde derleme hatası alınca i'yi size_t olarak değiştirdim.

Ama o zaman da number.length sıfır olduğunda number.length-1'in çok büyük bir değer olma tehlikesi var. Üstelik size_t türündeki bir değer zaten hep >=0 olur:

Ben de daha kolay olduğu için foreach kullandım ama azalan yöndeki sayı aralıklarında onun da sorunu oluyor çünkü (number.length-1)..0 yazınca bu sefer de 0 aralığa dahil olmuyor.

Şu çalıştı:

ubyte toDecimal(string number)
in
{
    assert(number.length != 0);
}
body
{
    ubyte result;
 
    foreach (i; 0 .. number.length) {
        if (number[i] == '1') {
            result += 2 ^^ (number.length - 1 - i);
        }
    }
 
    return result;
}

Dosya boyuyla ilgili olarak: Tamam, artık '1' ve '0' karakterleri yazmıyorsun ama değerleri yine de metin halinde yazıyorsun. Örneğin 245 değerini dosyaya o değerdeki tek bayt olarak değil; '2', '4', ve '5' karakterleri olarak yazıyorsun. writef() ile formatlı olarak değil, rawWrite() ile çiğ olarak yazabilirsin:

                compressedFile_.rawWrite([ toDecimal(compressedText[0 .. 8]) ]);

Şimdi dosyanın boyu örneğin 15 yerine 5 oluyor.

Ali
Kadir Can #21
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Teşekkürler, ben writef()'e byte türünden değer verdiğimde byte yazılacağını düşünmüştüm.
Bu arada ben derlerken hiç hata almadım. Bu tarz hataları yakalayabilmek için hangi seçenekleri kullanmalıyız?Ben sadece -w ve -g kullanıyordum.
acehreli (Moderatör) #22
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4412 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Kadir Can:
writef()'e byte türünden değer verdiğimde byte yazılacağını düşünmüştüm.

Ama her zaman için insanın okuyabileceği biçimde. Hem byte ile int aynı sayılırlar; tek farkları bit uzunlukları. Dikkat edersen, write() ve arkadaşları 42 gibi bir int değerini de '4' ve '2' rakamları olarak yazarlar.

hangi seçenekleri kullanmalıyız?Ben sadece -w ve -g kullanıyordum.

Bu tür hatalar derleme zamanında yakalanamaz. Olsa olsa birim testleri ile olabilir ama onun için de File gibi işleyen ama gerçek bir dosyaya değil de belleğe yazan bir tür olsa iyi olur. O zaman o File'dan okuyarak denetlenebilir. (Aslında std.stream.MemoryStream var ama uzun zaman önce muştulanmış ;) olan eşdeğerleri geleceğin için bütün std.stream modülünü gözardı ediyorum.)

Ayrıca -g'nin hata yakalama ile doğrudan ilgisi yok. O gdb gibi araçlarda kullanılabilsin diye kaynak koddaki isimleri programın içine yerleştirir.

Ali
Bu mesaj acehreli tarafından değiştirildi; zaman: 2012-07-12, 15:01.
Kadir Can #23
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
-g'yi çalışma zamanı hatalarında hangi işlevde sorun olduğunu görebilmek için kullanıyorum.
Bu arada aşağıdaki kod ile yazdığımız baytları okuyamırum.Hata nedir acaba?
module huffman.d;
import std.stdio;
import std.conv;
import std.algorithm;
import std.string;
import std.math;
struct HuffmanTree
{
    private
    {
        uint[string] compressTable_;
        string[uint] decompressTable_;
        Node top_;
        File fileToCompress_;
        File compressedFile_;
        File decompressedFile_;
        string fileName_;
    }
 
    public this(string fileName)
    {
        fileName_ = fileName;
        fileToCompress_.open(fileName ~ ".had", "r");
        compressedFile_.open(fileName ~ "compressed" ~ ".had", "w+");
        decompressedFile_.open(fileName ~ "decompressed.hda", "w");
    }
 
    public ~this()
    {
        auto tables = File("tables.had", "w");
        tables.writeln(compressTable_);
        tables.writeln(decompressTable_);
        fileToCompress_.close();
        compressedFile_.close();
        decompressedFile_.close();
    }
 
    public void setTables(Node top)
    {
        compressTable_ = top_.returnTable;
        foreach(key, value; compressTable_){
            decompressTable_[value] = key;
        }
    }
 
    public void compressFile()
    {
        string lines;
        while(!fileToCompress_.eof()){
            lines ~= fileToCompress_.readln();
        }
        auto nodes = searchLetters(lines);
        top_ = createTree(nodes);
        top_.setBinaryCodes();
        setTables(top_);
        string compressedText;
        foreach(letter; lines){
            compressedText ~= format("%b", compressTable_[to!string(letter)]);
            if(compressedText.length >= 8){
                compressedFile_.rawWrite([toDecimal(compressedText[0 .. 8])]);
                compressedText = compressedText[8 .. $];
            }
        }
        compressedFile_.rawWrite([toDecimal(compressedText[0 .. $])]);
    }
 
    public void decompressFile()
    {
        ubyte[1024] buffer;
        ubyte[] data;
        while(!compressedFile_.eof()){
            data ~= compressedFile_.rawRead(buffer);
        }
        writeln(buffer);
        writeln(data);
    }
}
 
ubyte toDecimal(string number)
in
{
    assert(number.length != 0);
}
body
{
    ubyte result;
 
    foreach (i; 0 .. number.length) {
        if (number[i] == '1') {
            result += 2 ^^ (number.length - 1 - i);
        }
    }
 
    return result;
}
 
struct Node
{
    private
    {
        string value_;
        uint binaryCode_;
        uint frequency_;
        Node* right_;
        Node* left_;
    }
 
    public this(const uint frequence, string value)
    {
        value_ = value;
        frequency_ = frequence;
    }
 
    public int opCmp(Node another) const
    {
        return frequency_ == another.frequency_ ? cmp(value_, another.value_) : frequency_ - another.frequency_ ;
    }
 
    public string toString() const
    {
        string result;
        result ~= "Binary code: " ~ to!string(binaryCode_) ~ "\n";
        result ~= "Letter: " ~ value_ ~ "\n";
        return result;
    }
 
    public void setBinaryCodes()
    {
        if(right_ && left_)
        {
            right_.binaryCode_ = binaryCode_;
            left_.binaryCode_ = binaryCode_;
            right_.binaryCode_ <<= 1;
            left_.binaryCode_ <<= 1;
            right_.binaryCode_ |= 1;
            right_.setBinaryCodes();
            left_.setBinaryCodes();
        }
    }
 
    public uint[string] returnTable() const @property
    { 
        uint[string] result;
        result[value_] = binaryCode_;
        if(right_ && left_)
        {
            foreach(index, value; left_.returnTable()){
                if(index.length==1){
                    result[index] = value;    
                } 
            }
            foreach(index, value; right_.returnTable()){
                if(index.length==1){
                    result[index] = value;
                } 
            }
        }
        foreach(index, value; result){
            if(index.length != 1){
                result.remove(index);
            }
        }
        return result;
    }
}
 
Node[] searchLetters(string text)
{
    uint[char] letters;
    Node[] result;
    foreach(character; text){
        if(character in letters){
            ++letters[character];
        } else {
            letters[character] = 1;
        }
    }
    foreach(index, value; letters){
        result ~= Node(value, to!string(index));
    }
    return result;
}
 
Node createTree(Node[] nodes)
{
    while(nodes.length > 1)
    {
        nodes.sort();
        auto newNode = Node((nodes[0].frequency_ + nodes[1].frequency_), (nodes[0].value_ ~ nodes[1].value_));
        newNode.left_ = &nodes[0];
        newNode.right_ = &nodes[1];
        nodes ~= newNode;
        nodes = nodes[2 .. $];
    }
    return nodes[0];
}
 
void main() 
{
    string fileName = "text";
    auto tree = HuffmanTree(fileName);
    tree.compressFile();
    tree.decompressFile();
}
acehreli (Moderatör) #24
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4412 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Hemen görebildiğim: .had dosyasını türün sonlandırıcı işlevinde oluşturuyorsun. Dolayısıyla senin örneğindeki dosya main'deki işlemlerden sonra oluşacaktır. Yani tree.decompressFile() çağrısından sonra!

Ali
Kadir Can #25
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
O sorunu düzelttim şimdi, ama buradaki sorun sanırım farklı. Dosyaya rawWrite() ile bayt bayt yazdığımız değerleri rawRead() ile aynı şekilde okumaya çalışıyorum ama ne buffer değişkeninde ne de data değişkeninde okuduğum değerleri göremiyorum.
Bunu nasıl çözebiliriz?
acehreli (Moderatör) #26
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4412 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Aynı dosya nesnesini mi kullanıyorsun? Şu çalışıyor:

import std.stdio;
 
void yaz(string isim, size_t adet)
{
    auto dosya = File(isim, "w");
 
    foreach (i; 0 .. adet) {
        immutable bayt = cast(ubyte)i;
        dosya.rawWrite([ bayt ]);
    }
}
 
void oku(string isim, size_t adet)
{
    auto dosya = File(isim, "r");
 
    auto okunan = new ubyte[](adet);
 
    dosya.rawRead(okunan);
 
    foreach (ubyte bayt; okunan) {
        writefln("%02x", bayt);
    }
}
 
void main()
{
    yaz("rawWrite_denemesi", 100);
    oku("rawWrite_denemesi", 100);
}

Ali
Kadir Can #27
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Evet, aynı dosya nesnesini kullanıyorum, bu nedenle dosyayı "w+" yetkisi ile açtım. Acaba sorun aynı nesnenin kullanılması olabilir mi?
acehreli (Moderatör) #28
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4412 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Okuma kafasını rewind() ile başa götürmek gerek:

import std.stdio;
 
void yaz(File dosya, size_t adet)
{
    foreach (i; 0 .. adet) {
        immutable bayt = cast(ubyte)i;
        dosya.rawWrite([ bayt ]);
    }
}
 
void oku(File dosya, size_t adet)
{
    auto okunan = new ubyte[](adet);
 
    dosya.rawRead(okunan);
 
    foreach (ubyte bayt; okunan) {
        writefln("%02x", bayt);
    }
}
 
void main()
{
    auto dosya = File("rawWrite_denemesi", "w+");
 
    yaz(dosya, 100);
 
    dosya.rewind();    // <-- şart!
 
    oku(dosya, 100);
}

Ali
Kadir Can #29
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Teşekkürler, şimdi okuyabildim. :)
erdem (Moderatör) #30
Üye Tem 2009 tarihinden beri · 902 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bu konuyu ilgiyle takip ediyorum.

Bu arada Kadir Can'ın D konusundaki gelişimini, ve yazdığı kodları çok beğendiğimi söylemeliyim  :-)

Kodun nasıl çalıştığına bakarken ben de öylesine tekrardan yazdım kodları..
import std.stdio;
 
void harflereBöl (dstring metin)
{
    int [dchar] harfler = [ 'a' : 1 ];
 
    foreach (karakter; metin) {
        if (karakter in harfler) {
            ++harfler[karakter];
        } else {
            harfler[karakter] = 1;
        }
    }
 
    foreach (harf, kaçtane; harfler) {
        writeln(harf, " : ", kaçtane);
    }
}
 
 
void main()
{
    harflereBöl("Fıstıkçı şahap");
}

Zaten benim beğendiğim kodlama tarzı olduğu için hiç değiştirmedim kodları.

Huffman algoritmasını kodlarken çokuzluları kullanabilirmiydik acaba. Bir de bir karakterin ne kadar tekrarlandığı ya da frekansını kaydetmemize gerek var mı.

Açıkçası Huffman algoritmasını farklı yöntemler, veri yapıları kullanarak kodlayan varsa dinlemeye hazırım  ;-)
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Sayfa:  önceki  1  2  3  sonraki 
Forum: Projeler dkv RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-06-22, 09:30:49 (UTC -07:00)