1. 程式人生 > >哈夫曼編碼和譯碼&&c++重點知識的應用

哈夫曼編碼和譯碼&&c++重點知識的應用

哈夫曼編碼和譯碼。將以前學的c++相關知識系統的用了一遍,反正是能想到啥,啥方便就用啥,但是說回來,也沒省多少事。反正比用c語言寫跟簡單一點。
先看題目原型吧!

假設某通訊報文的字符集由A,B,C,D,E,F這6個字元組成,它們在報文中出現的頻度(頻度均為整數值)。
(1)構造一棵哈弗曼樹,依次給出各字元編碼結果。
(2)給字串進行編碼。
(3)給編碼串進行譯碼。

規定:
構建哈弗曼樹時:左子樹根結點權值小於等於右子樹根結點權值。
生成編碼時:左分支標0,右分支標1。

輸入
第一行:依次輸入6個整數,依次代表A,B,C,D,E,F的頻度,用空格隔開。
第二行:待編碼的字串
第三行:待譯碼的編碼串
輸出
前6行依次輸出各個字元及其對應編碼,格式為【字元:編碼】(冒號均為英文符號)
第7行:編碼串
第8行:譯碼串
樣例輸入
3 4 10 8 6 5
BEE
0010000100111101
樣例輸出
A:000
B:001
C:10
D:01
E:111
F:110
001111111
BADBED

所用到的相關知識,最近學的智慧指標,迭代器,STL中的list連結串列,array陣列容器,繼承,就這些吧!我也不怎麼考慮演算法的優劣了。這感覺確實所用到的變數太多了。我得彙總一下~~~
在這裡插入圖片描述
以上為相關類和屬性,其中data類中

  • a 字元出現的頻數
  • ch 對應的字元
  • s 編碼連結串列字元型別,左為0右為1
  • hafu類中的方法全是靜態方法(通過類名來使用)

其中hafu類是繼承data類的。tag屬性是標記當前節點是否存在父節點,不存在為0,存在為l、p、r分別為左孩子下標有孩子下標,p為雙親下標。
首先初始化data連結串列,將字元該放入的放入,該置0的置0,接下來第一核心部分建樹。
難就難在找最小權值下標和次小權值下標,不管了,我的實現方法就是先在無父節點的節點中找最大值,並在findmax函式中記錄無父節點的節點個數,當個數為1時說明我們的樹已經建的差不多了,該收工了,否則,設定min等於那個最大值+1,然後在陣列中和其他節點權值比較,依據題目要求,讓左節點權值小於有節點權值,先獲得的最小權值的下標賦給kl,在第一趟迴圈完了後將以kl為下標的節點的tag置為1,它將是有爸爸的孩子啦!然後再在第二趟迴圈中招最小權值下標,賦給kr,然後就是哈夫曼演算法,讓父節點的做有孩子下標為kl,kr,讓孩子的父親節點的下標為新建立的節點的下標!樹的建立大致思路就是這樣。點到為止!

接下來就是編碼,這在哈夫曼樹演算法中不算核心,很簡單,就根據節點的個數,逐個遍歷,從第一個開始,按照父親節點的下標,然後依據父親節點的下標找到父親節點,然後,看父親節點的孩子下標,判斷當前節點的下標是父節點的左孩子還是右孩子,若是右孩子,往編碼連結串列中追加字元1,否則追加字元0,當遇到當前節點的父節點下標為0時,表示已經到樹頂了!然後將連結串列逆置,因為我們的編碼方向是從樹頂到根,逆置後才是當前節點真正的哈弗曼編碼,直接呼叫函式就行了。然後進行下一個節點的編碼!同樣的方法!

在我看來,最難得就是譯碼了,真是很燒腦。
我是怎麼解決的呢?
方法比較笨!根據輸入的編碼陣列,我們要在指標陣列中根據不同字元的編碼和輸入的字串進行匹配,然後找到匹配的字元輸出。我就是先遍歷物件陣列,用每一個字元的編碼與所輸入的陣列前面的字元進行匹配,若匹配正確就將輸入的陣列中的剛匹配的字元全置為‘#’符號,然後再輸出物件陣列中存的對應字元,再從物件陣列頭開始和匹配陣列非‘#’元素再進行匹配

;當該陣列中元素全為’#'號時,說明匹配完了;若當前物件陣列的當前元素和匹配陣列中前幾個非‘#’元素不匹配,用下一個物件的編碼進行再次匹配即可。不斷迴圈!

main函式

#include<iostream>
#include<stdlib.h>
#include<memory>
#include<list>
#include"hafuman.h"
using namespace std;
int main(){
	//智慧指標陣列
    array<shared_ptr<hafu>,SIZE>arr ;
    //初始化
    hafu::init(arr);
    //建立哈夫曼樹 
    hafu::process(arr);
    //獲取哈夫曼編碼
    hafu::makeCode(arr);
    //返回哈夫曼編碼
    hafu::request(arr);
    //翻譯編碼
    hafu::transform(arr);
}

標頭檔案

#ifndef _HAFU_H_
#define _HAFU_H_
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<memory>
#include<vector>
#include<list>
#include<string.h>
using namespace std;
//SIZE為字元個數
//MAXLINE為使用的字串長度
enum {SIZE = 11,MAXLINE = 100};
class data{
public:  
    int a ;
    char ch ;
    list<char>s;
};

class hafu:public data{
public:
    
    data da;
    int tag ;
    int l,p,r;
    hafu():tag(0){}
    ~hafu(){}
    //找當前陣列中無父節點的節點中字元頻率(權值)最大的節點
    static int findmax(int s,int &kl,array<shared_ptr<hafu>,SIZE>&ls);
    //找當前無父節點的節點中權值最小的兩個節點
    static void find(int s,int& kl,int &kr,array<shared_ptr<hafu>,SIZE>&ls);
    //初始化智慧指標陣列
    static void init(array<shared_ptr<hafu>,SIZE>&ls);
    //建立哈夫曼樹
    static void process(array<shared_ptr<hafu>,SIZE>&ls);
    //便利哈夫曼樹
    static void print(const array<shared_ptr<hafu>,SIZE>&ls);
    //編碼
    static void makeCode(array<shared_ptr<hafu>,SIZE>&ls);
    //逆置連結串列
    static void reverse(list<char>&s);
    //列印各個的編碼
    static void printCodes(array<shared_ptr<hafu>,SIZE>&ls);
    //輸入字元,返回相關編碼
    static void request(const array<shared_ptr<hafu>,SIZE>&ls);
    //列印各自父節點的編碼
    static void printlist( list<char>&s);
    //譯碼
    static void transform(const array<shared_ptr<hafu>,SIZE>&ls);
    static int search(list<char>&s ,char* arr,int i);
};

int hafu::search(list<char>&s,char *arr,int i){

        list<char>::iterator iter ;
        int k = 0 ;
        for(k = 0 ;k < strlen(arr);k++ ){
            if(arr[k]!='#')break ;
        }
        int m = k ;
        int count = 0 ;
        for(iter = s.begin();iter!=s.end();iter++){
                if(*iter == arr[k]){
                    count ++ ;
                    k++ ;
                }
                else{
                    return 0;
                }
        }
            int len = s.size();
            int kk = m;
            for(k = 0 ;k< len ;k++){
                kk = m+k;
                arr[kk] ='#';
            }
            return 1 ;
}

void hafu::transform(const array<shared_ptr<hafu>,SIZE>&ls){
    
    char s[MAXLINE];
    cin>>s;
    int i = 0,j ;
    int len = strlen(s);
    for(i =0 ;i< (SIZE+1)/2;i++){
        i = j ;
        if(s[strlen(s)-1]=='#'){
            break;

        }
        if(search(ls[i]->da.s,s,i)){
                cout<<ls[i]->da.ch<<"";
                j = 0 ;
            }
        else{
                j++ ;
            }
        }
        cout<<endl;
}

void hafu::printlist( list<char>&s){
     list<char>::iterator iter ;
     for(iter=s.begin();iter!=s.end() ;iter++){
                cout<<*iter<<"";
    }
}
void hafu::request(const array<shared_ptr<hafu>,SIZE>&ls){

    char arr[MAXLINE];
    cin>>arr ;
    int len = strlen(arr);
    int i ,j;
    int flag = 0 ;
    for(i = 0 ;i< len ;i++){
        for(j = 0 ;j<(SIZE+1)/2;j++){
            if(ls[j]->da.ch == arr[i]){
                printlist(ls[j]->da.s);
                flag =1 ;
            }
        }
        if(flag==0)return ;
    }
}

void hafu::printCodes(array<shared_ptr<hafu>,SIZE>&ls){
    
    int  i =  0;
    for(i = 0 ; i < (SIZE+1)/2 ;i++){
        list<char>::iterator iter ;
        cout<<ls[i]->da.ch<<":";
        for(iter = ls[i]->da.s.begin() ; iter!=ls[i]->da.s.end();iter++){
            cout<<*iter<<"";
        }
        cout<<endl ;
    }
    
}

void hafu:: reverse(list<char>&s){

    int i ;
    s.reverse();
}

void hafu::makeCode(array<shared_ptr<hafu>,SIZE>&ls){
    int  i  =  0 ;
    int j = 0;
    for(j = 0 ;j < (SIZE+1)/2;j++){
        int index = ls[j]->p;
         int k = j ;
         while(index){
          
            if(ls[index]->l == k){
               
                ls[j]->da.s.push_back('0');
            }
            if(ls[index]->r == k){
               
                ls[j]->da.s.push_back('1');
            }
            k = index ;
            index = ls[index]->p;
        }
        reverse(ls[j]->da.s);
    }
    printCodes(ls);
    
}

int hafu::findmax(int s,int &kl,array<shared_ptr<hafu>,SIZE>&ls){

        int i ,j;
        int temp ;
        kl = -1 ;
        int count = 0; 
        for(i = 0;i < s ;i++){
            if(kl< ls[i]->da.a && ls[i]->tag != 1){
                    kl = i;    
            }
            if(ls[i]->tag == 0)count++ ;
        }
}

void hafu::find(int s,int& kl,int &kr,array<shared_ptr<hafu>,SIZE>&ls){

    int i= 0, j = 0 ;
    int count ;
    count = findmax(s,kl,ls);
    if(count==1){
        kr = -1 ;
        return ;
    }
    
    int mins =ls[kl]->da.a+1;
    
    for(i = 0 ;i < 2 ;i++){
        int min = mins ;
        for(j = 0 ; j < s ; j++){
            
            if(i==0&&ls[j]->da.a < min&&ls[j]->tag == 0){

                   min = ls[j]->da.a ;
                   kl = j ;
            }

            if(i==1&&ls[j]->da.a < min&& ls[j]->tag==0){
                min = ls[j]->da.a ;
                kr = j;
            }
        }
        if(i == 0)ls[kl]->tag = 1 ;
        if(i == 1){
            ls[kr]->tag = 1 ;
            break ;
        }
    }
}
void hafu::print(const array<shared_ptr<hafu>,SIZE>&ls){
    int i = 0 ;
    for(i =0 ;i < SIZE ;i++){
        cout<<ls[i]->da.a<<"   "<<ls[i]->p<<"   "<<ls[i]->l<<"   "<<ls[i]->r<<endl;
    }
}

void hafu::process(array<shared_ptr<hafu>,SIZE>&ls){

    int  j = (SIZE+1)/2;
    int i ;
    int kl=-1,kr=-1 ;
    for(i =j ;i< SIZE;i++){
        find(i,kl,kr,ls);
        if(kr == -1)break ;
        ls[i]->da.a = ls[kr]->da.a + ls[kl]->da.a ;
        ls[i]->l = kl ;
        ls[i]->r = kr ;
        ls[kl]->p = i ;
        ls[kr]->p = i ;
    }
}

void hafu::init(array<shared_ptr<hafu>,SIZE>&ls){
    int j = 0 ;
    
    for(j = 0;j < SIZE;j++){
      shared_ptr<hafu>p(new hafu);
      if(j<6)cin>>p->da.a ;
      ls[j] = p ;
    }

    int i = 0;
    char ch;
    char arr[6] = {'A','B','C','D','E','F'};
        
    for(i = 0 ;i< (SIZE+1)/2;i++){
        ls[i]->da.ch=arr[i];
    }
    i = 0 ;
    while(1){
        if(i == SIZE){
            break ;
        }
        ls[i]->l = 0;
        ls[i]->r = 0;
        ls[i]->p = 0;
        if(i >= (SIZE+1)/2){
            ls[i]->da.ch = '\0';
            ls[i]->da.a = 0;
            i