2012 dm 07

21
project #7 Group Codes 이산치 수학 B1 조장 20113318 정예린 조원 20093483 백종근 20093496 윤은영 20093468 김현호 20113311 장동규

Upload: jungyerin

Post on 21-Dec-2014

342 views

Category:

Documents


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: 2012 Dm 07

project #7

Group Codes

이산치 수학 B1

조장

20113318 정예린

조원

20093483 백종근

20093496 윤은영

20093468 김현호

20113311 장동규

Page 2: 2012 Dm 07

순서

•조원별 업무분담

•일정 계획

•문제 파악-문자의 빈도수에 따른 코드를 찾는

허프만 알고리즘으로 설계

•알고리즘 계획

•소스구현

Page 3: 2012 Dm 07

이름 역할

백종근 보고서 작성, 자료 조사

김현호 자료 조사, 보고서 작성

장동규 알고리즘, 자료조사, 보고서 작성

윤은영 보고서 작성, 자료 조사

정예린 코딩, 자료 조사

날짜 계획06.11~06.13 프로젝트에 대한 자료 조사06.14~06.18 알고리즘을 이용해 소스를 작성

06.18~06.20소스의 잘못된 부분 수정, 최종 보고서 작

1) 조원별 업무 분담

2)일정계획

Page 4: 2012 Dm 07

3)문제파악

1. hamming distance

같은 비트 수를 갖는 2진 부호 사이에 대응되는 비트값이 일치하지 않는 개수. 일반적으로

해밍 거리 d가 d≥2a+1이면 a개의 오류를 정정할 수 있다. A:101011, B:110010, A와 B의

해밍 거리는 3이다.

해밍 코드에서 연속하는 두 숫자 코드 사이의 2진수. 즉, 두 개의 n 비트 2진 부호.

(x1, x2,…, xn), (y1, y2,…, yn)

에 있어서

ㅣx1-y1ㅣ+ㅣx2-y2ㅣ+…+ㅣxn-yn

을 해밍 거리라고 한다. 각 x, y는 2진 부호이면서 1, 0 중 하나의 값을 가지므로

ㅣxi+yiㅣ= xi⊕yi=(xi-yi)2

인 성질을 가진다. 따라서

ㅣx1-y1ㅣ+ㅣx2-y2ㅣ+…+ㅣxn-ynㅣ=(x1-y1)2+(x2-y2)2+…+(xn-yn)2

이 되므로 유클리드 거리의 제곱이 된다.

Page 5: 2012 Dm 07

2. coordinate

어느 한 행과 열의 교차점과 같은 특정 위치를 지정하기 위해 사용되는 1쌍의 값. 컴퓨터

그래픽스(CG)와 화면 표시에서 좌표는 직선상의 점, 네모꼴의 각, 화면상의 픽셀의 위치 등

을 지정하는 데 사용된다. 다른 컴퓨터 응용에서 좌표는 스프레드시트상의 셀, 도표상의 데

이터 포인트, 기억 장치 내의 위치 등을 지정하는 데 사용된다. 좌표의 의미와 배열 등을 규

정하는 체계 또는 표준을 좌표계(coordinate system)라고 한다. 가장 보편적인 데카르트 좌

표계에서는 각 축이 교차하는 점을 좌표를 측정하는 원점으로 하여 2차원 및 3차원의 공간

위에 직사각형의 그리드를 겹쳐 놓는다. 2차원에서는 X축과 Y축의 교차점이 원점이 되고, 3

차원에서는 X축, Y축, Z축의 교차점이 원점이 된다. 목적에 따라 여러 가지 좌표계가 사용된

다.

3. n-tuple

한 릴레이션의 애트리뷰트 개수를 차수(degree)라 하는데, N의 차수를 가진 한 행(行)을 말

한다.

4. huffman code

압축기법의 하나.

가변 길이 코드로 문자의 발생빈도를 검사해 발생 빈도가 높은 문자에 적은 수의 비트를,

빈도수가 적은 문자에 많은 수의 비트를 할당한다.

4)-1 heap heap은 프로그램이 실행될 때까지는 알 수 없는 가변적인 량만큼의 데이터를 저장하기 위

해, 프로그램의 프로세스가 사용할 수 있도록 미리 예약되어 있는 메인 메모리의 영역이다.

예를 들면, 하나의 프로그램은 처리를 위해 한 명 이상의 사용자로부터 서로 다른 량의 입

력을 받을 수 있으며, 즉시 모든 입력데이터에 대해 처리를 개시한다. 운영체계로부터 이미

확보된 일정량의 heap 저장 공간을 가지고 있으면, 저장과 관련된 처리를 좀 더 쉽게 할 수

있으며, 일반적으로 필요할 때마다 운영체계에게 매번 저장 공간을 요청하는 것보다 빠르다.

프로세스는 필요할 때 heap 블록을 요구하고, 더 이상 필요 없을 때 반환하며, 이따금씩 "

자투리 모으기"를 수행함으로써 자신에게 할당된 heap을 관리한다. 여기서 자투리 모으기란

더 이상 사용되지 않는 블록들을 사용 가능한 상태로 만들고, 또한 heap 내의 사용 가능한

공간을 인지함으로써 사용되지 않은 작은 조각들이 낭비되지 않도록 하는 것을 말한다.

Page 6: 2012 Dm 07

4)-2 허프만 트리 예

4)알고리즘 계획 1. 문자열을 검사해 각 문자의 빈도수를 조사해 우선순위 큐에 집어넣는다.

(빈도수가 낮을수록 우선순위는 높다)

2. 큐에서 2개의 노드를 추출 이진트리로 만들고 루트는 두 노드의 빈도수 합으로 한다.

3. 생성된 이진트리의 루트노드 x를 다시 우선순위 큐에 삽입

이때 x의 빈도수는 x의 자식노드의 빈도수 합이다.

4. 모든 원소가 이진트리의 원소가 될 때 까지 2,3 과정 반복

5. 트리가 완성되면 루트를 기준으로 왼쪽은0, 오른쪽은 1의 가중치를 부여해 트리의 노드

에 코드를 부여

Page 7: 2012 Dm 07

5)소스 구현-참고소스 및 분석

5)-1//Deap Class and Huffman Tree Library

//created by Kim Yongmook ( http://moogi.new21.org )

//Originically created on June 10, 2003

#include <stdio.h>

#include <time.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

typedef int BOOL;

#define ASSERT(p) assert(p)

template<typename TYPE>

inline void Swap(TYPE &a, TYPE& b)

{

TYPE c; c=a; a=b; b=c;

}

//Deap data structure * * * * * * * * * * * *

template<typename TYPE, typename ARG_TYPE>

class CDeap {

TYPE *m_pData; int m_nSize, m_nCount;

static int GetAdjacentNode(int x, int *dir=NULL)

{

int i; //x must be equal to or greater than 2!

//2->6, 15->11, 7->5 converter

//dir: 0 if 2,4,5,10 (left side, that is min heap), else 3 7 13 (right side,

max heap)

for(i=31;(x&(1<<i))==0;i--); if(dir) *dir=!!(x&(1<<(i-1)));

return x^(1<<(i-1));

}

void AddHelper(ARG_TYPE p, int pos);

public:

CDeap(int siz): m_nSize(siz), m_nCount(2)

{

Page 8: 2012 Dm 07

m_pData=new TYPE[siz]; m_pData-=2; //0, 1 인덱스는 쓰이지 않고 있다.

}

~CDeap() { delete [](m_pData+2); }

int GetSize() const { return m_nSize; }

int GetCount() const { return m_nCount-2; }

//WARN: 최소한 자료가 하나는 있어야 이들 함수를 쓸 수 있다

TYPE GetMax() const { ASSERT(m_nCount>2); return m_pData[m_nCount>3 ? 3:2];

}

TYPE& GetMax() { ASSERT(m_nCount>2); return m_pData[m_nCount>3 ? 3:2]; }

TYPE GetMin() const { ASSERT(m_nCount>2); return m_pData[2]; }

TYPE& GetMin() { ASSERT(m_nCount>2); return m_pData[2]; }

BOOL Add(ARG_TYPE p, int policy=-1);

BOOL RemoveMax();

BOOL RemoveMin();

void Display() const; //디버깅용

};

//DEAP의 정의와, 양쪽 힙의 특성을 유지하게끔, p 위치에 삽입된 원소를

//요리조리 옮겨주는 함수

//단, pos가 MIN 쪽일 때는 트리의 맨 밑바닥 번호여야 하고, (즉 (pos<<1)>=m_nCount )

//MAX 쪽일 때는 자식이 최대 하나만 있어야 한다.

template<typename TYPE, typename ARG_TYPE>

void CDeap<TYPE, ARG_TYPE>::AddHelper(ARG_TYPE p, int pos)

{

int adj, dir, root; //ASSERT((pos<<1)>=m_nCount);

m_pData[pos]=p;

if(m_nCount>3) { //원소가 둘 이상이 되면

adj=GetAdjacentNode(pos, &dir);

//이제 우리가 어느 쪽이냐에 따라 adj 값을 보정한다.

if(dir) {

//우리가 max쪽이면 상대는 min. 우리가 상대의 자식들보다도 큰

지 검사해야 한다.

if((adj<<1)<m_nCount && m_pData[adj]<m_pData[adj<<1]) {

adj<<=1; //two children

if(adj+1<m_nCount && m_pData[adj]<m_pData[adj+1])

adj++;

}

}

else //우리가 min쪽이므로 짝이 존재하지 않을 수도 있다.

Page 9: 2012 Dm 07

if(adj>=m_nCount) adj>>=1; //짝이 존재하는 곳까지 부모 노드

로...

//우리가 왼쪽에 있는데(min side. dir=0, pos) 우리 값이 오른쪽(adj)보다

더 크면

//두 값을 맞바꾸고, adj가 우리 원소가 들어가는 번호가 된다.

if(dir^(m_pData[pos]>m_pData[adj])) {

Swap(m_pData[adj], m_pData[pos]); dir^=1;

}

else adj=pos;

ASSERT(adj>=2 && adj<=m_nCount);

//이제 우리 원소가 소속된 쪽(min or max)에 맞게 힙을 재정렬한다.

while(adj>3) {

root=adj>>1;

//루트가 현재보다 더 크고 최소 트리 모드이거나

//루트가 현재보다 작고 최대 트리 모드이면 서로 위치를 바꾼다

:)

if( (m_pData[root]>m_pData[adj])^dir ) {

Swap(m_pData[adj], m_pData[root]); adj=root;

}

else break;

}

}

}

//policy: 원소 개수가 m_nSize를 넘어갈 때의 정책:

//0: 최소값을 경신. 1: 최대값을 경신.

//-1: 그냥 에러를 반환한다.

template<typename TYPE, typename ARG_TYPE>

BOOL CDeap<TYPE, ARG_TYPE>::Add(ARG_TYPE p, int policy)

{

if(GetCount()==m_nSize)

switch(policy) {

case 0: if(GetMax()<p) return false; else RemoveMax(); break;

case 1: if(GetMin()>p) return false; else RemoveMin(); break;

default: return false;

}

m_nCount++; AddHelper(p, m_nCount-1); return true;

}

template<typename TYPE, typename ARG_TYPE>

Page 10: 2012 Dm 07

BOOL CDeap<TYPE, ARG_TYPE>::RemoveMin()

{

int i,j;

if(m_nCount==2) return false; //no data to delete

for(i=2;(i<<1)<m_nCount;m_pData[i]=m_pData[j], i=j) {

j=(i<<1); if(j+1<m_nCount && m_pData[j+1]<m_pData[j]) j++;

}

//이제 남은 자리에다 마지막 원소를 삽입한다.

m_nCount--; AddHelper(m_pData[m_nCount], i); return true;

}

template<typename TYPE, typename ARG_TYPE>

BOOL CDeap<TYPE, ARG_TYPE>::RemoveMax()

{

int i,j;

switch(m_nCount) {

case 2: return false; //no data to delete

case 4: case 3: m_nCount--; return true; //simply decrease the count

}

for(i=3;(i<<1)<m_nCount;m_pData[i]=m_pData[j], i=j) {

j=(i<<1); if(j+1<m_nCount && m_pData[j+1]>m_pData[j]) j++;

}

m_nCount--; //이제 남은 자리에다 마지막 원소를 삽입한다.

if(m_nCount==i) i>>=1; //min쪽의 밑바닥 검사를 위한 조치이다!!

AddHelper(m_pData[m_nCount], i); return true;

}

template<typename TYPE, typename ARG_TYPE>

void CDeap<TYPE, ARG_TYPE>::Display() const

{

int x,a=1,b=0,c=0;

for(x=2;x<m_nCount;x++) {

printf("%d ", m_pData[x]);

c++; if(c==a) { printf("| "), c=0; if(b==1) a<<=1; b^=1; }

}

puts("");

}

//Huffman tree library * * * * * * * * * * * *

#define NOPARENT 999999

class CHuffman {

Page 11: 2012 Dm 07

struct ENTRY {

//index 멤버는 배열에서는 이 원소의 부모 노드 번호로,

//min 힙 안에서는 이 원소의 원래 배열 번호를 가리킨다. 다용도임.

int index, value;

ENTRY() {}

ENTRY(int a, int b): index(a), value(b) {}

operator int() const { return value; }

};

int m_nCount;

ENTRY *m_pEnt;

CDeap<ENTRY, const ENTRY&> m_Heap;

public:

CHuffman(const int *data, int count): m_Heap(count), m_nCount(count)

{

int i; m_pEnt=new ENTRY[count*2];

for(i=0;i<count;i++) {

m_pEnt[i]=ENTRY(NOPARENT, data[i]); m_Heap.Add(ENTRY(i,

data[i]));

}

}

~CHuffman() { delete []m_pEnt; }

void Solve();

//result retrieve

int GetCode(int n, char *cod=NULL) const;

};

//허프만 나무를 n log n 시간만에 구성한다. 힙 덕분에 가능한 복잡도임

void CHuffman::Solve()

{

int lp=m_nCount; ENTRY a,b;

//가장 작은 놈 둘을 빼낸다.

while(m_Heap.GetCount()>=2) {

a=m_Heap.GetMin(); m_Heap.RemoveMin();

b=m_Heap.GetMin(); m_Heap.RemoveMin();

m_pEnt[a.index].index=-lp; //left (0) side

m_pEnt[b.index].index=lp; //right (1) side

m_pEnt[lp]=ENTRY(NOPARENT, a.value+b.value);

m_Heap.Add(ENTRY(lp, a.value+b.value));

lp++;

}

}

Page 12: 2012 Dm 07

//actual binary code, plus its length as the return value

int CHuffman::GetCode(int n, char *cod) const

{

int j; char *cod2=cod;

for(j=0;m_pEnt[n].index!=NOPARENT;j++) {

if(cod) { *cod='0'+(m_pEnt[n].index>0); cod++; }

n=abs(m_pEnt[n].index);

}

if(cod) { *cod=0; _strrev(cod2); } //reverse the order. _strrev는 표준 함수가 아니

기 때문에 지원하지 않는 컴파일러도 있음.

return j;

}

//Demonstrations * * * * * * * * * * * *

void DeapTest()

{

CDeap<int, int> pk(150); unsigned seee; int i,j, bef,arr[500];

seee=time(0); srand(seee);

for(i=0;i<500;i++) arr[i]=i+1;

for(j=0;j<3;j++) for(i=0;i<200;i++) Swap(arr[i], arr[rand()%100]);

printf("Original order: ");

for(i=0;i<150;i++) printf("%d ", arr[i]); puts("\n");

for(i=0;i<150;i++) pk.Add(arr[i], 0);

printf("Heap form: "); pk.Display(); puts("");

printf("Min form: "); bef=-1;

while(pk.GetCount()>0) {

printf("%d ", pk.GetMin()); ASSERT(bef<=pk.GetMin());

bef=pk.GetMin(); pk.RemoveMin();

}

puts("\n");

for(i=0;i<150;i++) pk.Add(arr[i], 1);

printf("Max form: "); bef=99999;

while(pk.GetCount()>0) {

printf("%d ", pk.GetMax()); ASSERT(bef>=pk.GetMax());

bef=pk.GetMax(); pk.RemoveMax();

}

}

void HuffmanTree()

{

Page 13: 2012 Dm 07

int seq[26]={

1532, 418, 729, 902, 2503, 359, 614, 460, 1765, 67, 530, 1317, 580,

1148, 1266, 549,

51, 1100, 2325, 1277, 840, 280, 249, 137, 850, 214};

int i, sum; char buf[24];

CHuffman huf(seq, 26); huf.Solve();

for(i=sum=0;i<26;i++) {

printf("%c's code size is %d - ", i+'A', huf.GetCode(i, buf));

puts(buf);

sum+=huf.GetCode(i)*seq[i];

}

printf("Compression size %d\n", sum);

for(i=sum=0;i<26;i++) sum+=seq[i]*5;

printf("UnCompression size %d\n", sum);

}

int main()

{

puts("Sorting with Deap:"); DeapTest();

puts("\n\nHuffman tree:"); HuffmanTree();

return 0;

}

5)-2

#include<stdio.h>

#include<stdlib.h>

struct sort

{

char c;

double d;

}; //문자와 확률을 넘겨 받는 구초제형 선언

#define MAX_ELEMENT 100

Page 14: 2012 Dm 07

typedef struct TreeNode{

int weight;

struct TreeNode *left_child;

struct TreeNode *right_child;

}TreeNode;

typedef struct element{

TreeNode *ptree;

int key;

}element;

typedef struct HeapType{

element heap[MAX_ELEMENT];

int heap_size;

}HeapType;

void print(TreeNode *root);

void init(HeapType *h)

{

h->heap_size=0;

}

//삽입함수

Page 15: 2012 Dm 07

void insert_min_heap(HeapType *h, element item)

{

int i;

i = ++(h->heap_size);

//트리를거슬러올라가면서부모노드와비교하는과정그래야인덱스를찾지

while((i != 1) && (item.key < h->heap[i/2].key)){

h->heap[i] = h->heap[i/2];

i /= 2;

}

h->heap[i] = item; //새로운노드삽입

}

//삭제함수

element delete_min_heap(HeapType *h)

{

int parent, child;

element item, temp;

Page 16: 2012 Dm 07

item = h->heap[1];

temp = h->heap[(h->heap_size)--];

parent = 1;

child = 2;

while(child <= h->heap_size){

//현재노드의자식노드중더작은자식노드를찾는다.

if((child< h->heap_size) && (h->heap[child].key > h->heap[child+1].key))

child++;

if(temp.key <= h->heap[child].key) break;

//한단계아래로이동

h->heap[parent] = h->heap[child];

parent = child;

child *= 2;

}

h->heap[parent] = temp;

return item;

}

Page 17: 2012 Dm 07

//이진트리생성함수

TreeNode *make_tree(TreeNode *left, TreeNode *right)

{

TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));

if(node == NULL){

fprintf(stderr,"메모리할당에러\n");

exit(1);

}

node->left_child = left;

node->right_child = right;

return node;

}

//이진트리제거함수

void destroy_tree(TreeNode *root)

{

if(root == NULL) return;

destroy_tree(root->left_child);

destroy_tree(root->right_child);

Page 18: 2012 Dm 07

free(root);

}

//허프만코드생성함수

void huffman_tree(struct sort arr[], int n)

{

int i;

HeapType heap;

element e, e1, e2;

TreeNode *node, *x;

//int k;

init(&heap);

for(i=0;i<n;i++){

node = make_tree(NULL,NULL);

e.key = node->weight = arr[i];

e.ptree = node;

insert_min_heap(&heap, e);

}

//for(i=0;i<=n;i++)

// printf("%d->",heap.heap[i].key);

Page 19: 2012 Dm 07

for(i=1;i<n;i++){

//최소값을가지는두개의노드를삭제

e1 = delete_min_heap(&heap);

/*printf("방금힙에서꺼낸것: %d\n", e1.key);

for(k=1;k<n;k++)

printf("꺼내고난후에힙배열: %d\n",heap.heap[k].key);*/

e2 = delete_min_heap(&heap);

/*printf("그다음힙에서꺼낸것: %d\n", e2.key);

for(k=1;k<n;k++)

printf("꺼내고난후에힙배열: %d\n",heap.heap[k].key);*/

//두개의노드를합친다.

x = make_tree(e1.ptree, e2.ptree);

e.key = x->weight = e1.key + e2.key;

//printf("e.key=%d, x->weight=%d\n",e.key, x->weight);

e.ptree = x;

insert_min_heap(&heap, e);

//printf("%d\n", heap.heap[4].key);

}

Page 20: 2012 Dm 07

e = delete_min_heap(&heap); //최종트리

//print(e.ptree);

//원래나오는최종트리heap배열엔: 4 6 12 15 8

destroy_tree(e.ptree);

}

void print(TreeNode *root)

{

if(root){

print(root->left_child);

print(root->right_child);

printf("(%d)",root->weight);

}

}

void main()

{

struct sort arr[100],; //구조체형 배열을 선언하여 입력받음

int i=0,j=0,m;

Page 21: 2012 Dm 07

for(i=0;i<100;i++)

{

for(j=0;j<100;j++)

{

arr[i].c='\0';

arr[i].d='\0';

}

}

j=0;

while(j!=6)

{

scanf("%c %lf\n",&arr[j].c,&arr[j].d);

j++;

}

for(i=0;i<j;i++)

{

printf("%c %f\n",arr[i].c,arr[i].d);

//printf("i=%d",i);

}

huffman_tree(arr, 5);

}