2016년 5월 15일 일요일

허프만 코딩(Huffman coding)


https://en.wikipedia.org/wiki/Huffman_coding 참고
압축에서 많이 사용하는 개념으로 가변 길이 부호화를 하는 방법을 말합니다.

트리를 생성하는 방법은 다음과 같습니다.

15,7,6,6,5 빈도수와 코드값 A,B,C,D,E 이 아래와 같이 주어진다고 할때 허프만 트리를 만드는 과정은 아래와 같습니다.

설명 a : 빈도수와 코드값을 나열한 상태입니다.
설명 b : 빈도가 가장 작은 두개 노드를 선택하고 이 두 노드를 자식으로 하는 부모 노드 를 만듭니다. D,E가를 가지고 트리를 만들고 새로운 노드는 11이라는 자식노드의 합이 새로운 빈도가 됩니다.
설명 c : 빈도가 가장 작은 두개 노드를 선택하고 이 두 노드를 자식으로 하는 부모 노드 를 만듭니다. 제일 아래 B 7, C 6 이 제일작은 빈도가 됩니다. 그래서 B C노드를 만듭니다.
설명 d : 빈도가 가장 작은 두개 노드를 선택하고 이 두 노드를 자식으로 하는 부모 노드 를 만듭니다. 15,13,11 중 작은 두개는 13,11이 됩니다. 13과 11은  BC,DE입니다. 그래서 새로운 24짜리 node가 만들어집니다.
설명 e : 빈도가 가장 작은 두개 노드를 선택하고 이 두 노드를 자식으로 하는 부모 노드 를 만듭니다. 15,24 인 노드가 남았습니다. 39가 완성된 node입니다.

아래와 같이 부호화가 가능합니다.




위설명을 코드로 구현하였습니다. 순수하게 C언어로만 되어 있고 pointer를 사용하지 않고 구현하였습니다.

Cpasted 1 second ago: 
#include <stdio.h>

#define NODE_MAX        5
#define SymbolIdx       0
#define FrequencyIdx    1
int innode[NODE_MAX][2]={
 {'A',15},
 {'B',7},
 {'C',6},
 {'D',6},
 {'E',5},
};

#define NodeMax          5
#define NodeFrequency    4
#define NodeSymbol       3
#define NodeChild1       2
#define NodeChild2       1
#define NodeParent       0
int pqnode[NODE_MAX*5];

#define QMAX NODE_MAX*5
int qpool[QMAX][NodeMax];

int qinfo[NodeMax];

int pqcount=0;
int realpqcount=0;

int init()
{
 int i;
 for(i=0;i<QMAX;i++){
  qpool[i][NodeFrequency] = -1;
 }
 return 0;
}

int pqput(int idx)
{
 int i;
 for(i=0;i<pqcount;i++){
  if(pqnode[i]==-1) break;
 }
 if(i==pqcount){
  pqcount++;
 }
 realpqcount++;
 pqnode[i]=idx;
 return 0;
}

int getfreepool()
{
 int i;
 for(i=0;i<QMAX;i++){
  if( qpool[i][NodeFrequency] == -1 ) return i;
 }
 return -1;
}

int setqpool(int idx,int symbol,int freq,int parent,int child1,int child2)
{
 printf("setq:%d %d %d\n",idx,symbol,freq);
 qpool[idx][NodeSymbol]=symbol;
 qpool[idx][NodeFrequency]=freq;
 qpool[idx][NodeParent]=parent;
 qpool[idx][NodeChild1]=child1;
 qpool[idx][NodeChild2]=child2;
 return idx;
}

int getpoolNodeFrequency(int idx)
{
 return qpool[idx][NodeFrequency];
}

int getpqcount()
{
 return realpqcount;
}

int pqget()
{
 int i;
 int minidx = -1;
 int minvalue = 100000;
 int curr;
 int pid = -1;
 if( realpqcount== 0 ) return -1;
 for(i=0;i<pqcount;i++){
  if(pqnode[i]==-1) continue;
  curr = getpoolNodeFrequency(pqnode[i]);
  if( curr < minvalue ){
   minidx = i;
   pid = pqnode[i];
   minvalue = curr;
  }
 }
 pqnode[minidx] = -1;
 realpqcount--;
 if( pqcount-1==minidx ) pqcount--;
 return pid;
}

int codes[10];
int DFS(int node,int depth)
{
 int i;
 if(node == -1) return 0;
 if(qpool[node][NodeSymbol]!=-1){
  printf("%c:",qpool[node][NodeSymbol]);
  for(i=0;i<depth;i++){
   printf("%d",codes[i]);
  }
  printf("\n");
  return 0;
 }
 codes[depth]=0;
 DFS(qpool[node][NodeChild1],depth+1);
 codes[depth]=1;
 DFS(qpool[node][NodeChild2],depth+1);
 return 0;
}

int main()
{
 int i;
 int chk1,chk2,root;
 int tmpq[NodeMax];
 
 init();
 
 for(i=0;i<NODE_MAX;i++){
  pqput(setqpool(getfreepool(),innode[i][SymbolIdx],innode[i][FrequencyIdx],-1,-1,-1));
 }

 for(;;){
  if(getpqcount()==1) {
   // queue에 node가 하나남으면 root node 하나만 남은 상태임
   break;
  }
  chk1 = pqget();
  chk2 = pqget();
  pqput(setqpool(getfreepool(),-1,getpoolNodeFrequency(chk1)+getpoolNodeFrequency(chk2),-1,chk1,chk2));

 }
 
 root = pqget();
 
 DFS(root,0);
 return 0;
}


Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
setq:0 65 15
setq:1 66 7
setq:2 67 6
setq:3 68 6
setq:4 69 5
setq:5 -1 11
setq:6 -1 13
setq:7 -1 24
setq:8 -1 39
A:0
E:100
C:101
D:110
B:111





댓글 없음:

댓글 쓰기