13
과과과과과과 과과 과과 B2 조조 : 조조조 조조조조 : 조조조,조조조 조조조조조 : 조조조,조조조 과과과과과과 4조 I. 과과과 과과 과과과과 TREE 과과과과 조조조 조조 조조조조, 조조조 조조조조 조조조조 조조조조 조조 조 조조. 과과과과 C 조 조조조 조조 조조조조 조조조 조조조 조조조조조 U R L http://blog.naver.com/ctpoyou? Redirect=Log&logNo=104932778 -조조조 조조조 조조조 조조 http://internet512.chonbuk.ac.kr/datastructure/tree/ tree8.htm -조조조 조조조조 II. 과과과 과과 과과 과 2012 조 5 조 3 조 조조조 과과과 과과 조조조 조조 조조조 조조조 조조 조 조조조 조조 조조조 조조 과과 과과 조조 : 조조조 조조조조 : 조조조,조조조,조조조 조조조조조 : 조조조 조조 조조 조조조 조조 조조조 조조조조 조조조 조조 조조조조조 조조조조조조 조조 조조조 조조조조 조조조조조 조조조 조조 조조조 조조 조조조 조 조 조조 조조조 조조조조조 조조조조조 조조조 조조조 조조조.

자료구조 Project4

Embed Size (px)

Citation preview

Page 1: 자료구조 Project4

과제수행일지소속 조원

B2 조장 : 고충욱 자료조사 : 최완철,최수영 프로그래밍 : 강승우,최규준

과제수행기간 4 일

I. 계획의 작성

연구제목 TREE

연구배경 트리에 대해 이해하고, 트리를 이용하여 상호참조 생성기를 만들 수 있다.

참고자료

C 로 배우는 쉬운 자료구조 이지영 출판사 한빛미디어

U

R

L

http://blog.naver.com/ctpoyou?Redirect=Log&logNo=104932778-

트리의 정의와 트리의 종류

http://internet512.chonbuk.ac.kr/datastructure/tree/tree8.htm-트리의

순회방법

II. 계획의 실행

첫째 날 2012 년 5 월 3 일 목요일

오늘의 작업 조원의 업무 분담과 학습할 내용 및 과제에 대한 이해와 숙지

토의 내용

조장 : 고충욱

자료조사 : 강승우,최완철,최수영

프로그래밍 : 허규준

위와 같이 조원의 업무 분담을 하였으며 과제를 위한 자료조사와 프로그래밍에 대한

내용을 인식하고 개별적으로 분담을 해서 조사를 하고 이해를 해 온 다음 그것을

조원들에게 설명해주는 것으로 방향을 잡았다.

과제준비에 이번과제의 내용을 보니 자료조사가 많이 필요할 것 같아서 자료조사를 중점으로

Page 2: 자료구조 Project4

느낀 점해야겠다는 생각을 가지게 되었다.

둘째 날 2012 년 5 월 8 일 목요일

오늘의 작업 학습할 내용에 대한 설명 및 이해

토의 내용 Tree(나무구조)의 정의

⊙ 1 개 이상의 유한한 개수의 노드의 집합

⊙ 루트 노드와 0 개 이상의 겹치지 않는 하위 나무 구조들의 집합으로 이루어짐

path : edge 에 의해 연결된 node 들의 집합

leaf(잎) : 자식이 없는 node(최하위 계층)

forest :루트를 제외한 나머지 부분

subtree : 큰 tree 에 속한 작은 tree

node 의 degree : 하위 subtree 의 개수, 어느 특정노드의 자식 수

node 의 level : root node 부터 최하위 node 까지의 중첩되지 않은 path 의 node

개수

노드들의 자식 수 중에 가장 큰 자식 수

1) 노드 (Node)

노드는 트리를 구성하는 기본 요소를 말한다. 즉 아래의 그림에서 본다면 a 에서 g 까지의

각 요소

모두가 노드가 된다.

2) 근(Root)

트리의 가장 높은 레벨에 있는 노드를 루트 노드 또는 근 노드라 한다. 이 루트 노드는

모든 노드의

조상이 된다. 아래의 그림에서 a 노드는 루트 노드가 된다.

3) 레벨(level)

레벨은 각 노드가 근노드와 얼마만큼 떨어져 있는가를 알기 위해 상용한다. 예를 들어

아래의

그림에서 e 노드는 루트노드와 3 계층 떨어져 있으므로 level 은 3 이 된다.

4) 부모 노드와 자식 노드

parent node, child node 라 불린다. 서로 아래 위로 붙어 있는 노드로 상위의 노드가

부모 노드가 된다. 하위의 노드는 자식노드가 되고 여러개의 자식노드는 하나의 부모

노드만 가질 수 있다.

Page 3: 자료구조 Project4

아래의 그림에서 e 노드와 g 노드는 각각부모 노드 자식이 된다.

5) 형제 노드

sibling node 라 불린다. 같은 부모 노드를 갖는 자식 노드들은 형제들의 집합으로

구성된다.

아래의 그림에서 b 노드와 c 노드는 sibling nod 가 된다.

Binary Tree(이진 나무, 이진 트리)의 정의

모든 내부 node 들이 둘 이하의 자식 node 를 갖는 나무, 노드가 하나도 없는 공집합

이거나

root node 를 기준으로 왼쪽 이진나무, 오른쪽 이진나무로 이루어진 집합

⊙ Complete Binary tree(완전 이진나무)

가장 마지막 level 을 제외한 모든 node 들이 꽉 차있고 마지막 level 은 왼쪽 부터 마지막

node 까지 빈 칸이 없는 tree

⊙ Full Binary Tree(포화 이진나무)

마지막 level 까지 완전히 꽉 차있는 이진 트리를 말함

이진 나무 순회(Tree Traverse)

Page 4: 자료구조 Project4

위와 같은 트리가 있다고 한다면 각각 순회방법은 다음과 같습니다.

⊙ 전위 순회(preorder traverse) : 뿌리(root)를 먼저 방문

⊙ 중위 순회(inorder traverse) : 왼쪽 하위 트리를 방문 후 뿌리(root)를 방문

⊙ 후위 순회(postorder traverse) : 하위 트리 모두 방문 후 뿌리(root)를 방문

⊙ 층별 순회(level order traverse) : 위 쪽 node 들 부터 아래방향으로 차례로 방문

전위 순회 : 0->1->3->7->8->4->9->10->2->5->11->6

중위 순회 : 7->3->8->1->9->4->10->0->11->5->2->6

후위 순회 : 7->8->3->9->10->4->1->11->5->6->2->0

층별 순회 : 0->1->2->3->4->5->6->7->8->9->10->11

★전위 순회는 뿌리->왼쪽 자식->오른쪽 자식 순

★중위 순회는 왼쪽자식-> 뿌리-> 오른쪽 자식

★후위 순회는 왼쪽자식->오른쪽 자식-> 뿌리

★층별 순회는 그냥 노드의 순서대로

과제준비에

느낀 점

트리에 대한 개념은 어느 정도 이해 할 수 있었으나 이것을 사용하고 구현하기 위해서는

아직 많은 것이 부족한 것 같다. 더 많은 공부가 필요한 것 같다.

셋째 날 2012 년 5 월 10 일 목요일

오늘의 작업 자료조사 내용

Page 5: 자료구조 Project4

토의 내용 트리의 순회

이진 트리의 순회는 일정한 순서로 트리의 모든 노드들을 오직 한번씩만 방문하는

것이다. 트리의 순회는 트리 구조로 된 정보의 검색이나 수식 처리등에 유용하게

사용된다.

특정 노드에서 자신의 왼쪽 서브 트리를 모두 방문하고, 자기 노드를

방문한 후에 오른쪽 서브 트리를 방문한다. 이 원리를 모든 노드에

재귀적으로 적용하면 모든 노드들을 한번씩 방문할 수 있다.

특정 노드에서 먼저 자기 노드를 방문하고, 왼쪽 서브 트리를 모두

방문하고, 마지막으로 오른쪽 서브 트리를 모두 방문한다. 이 원리를

모든 노드에 재귀적으로 적용하면 모든 노드를 한번씩 방문할 수 있다.

Page 6: 자료구조 Project4

특정 노드에서 자신의 왼쪽 서브 트리와 오른쪽 서브 트리를 차례로

방문한 후, 마지막으로 자신의 노드를 방문한다. 이 원리를 모든 노드에

재귀적으로 적용하면 각 노드를 한번씩 방문할 수 있다.

Page 7: 자료구조 Project4

과제준비에

느낀 점

순회에 대해 공부하면서 어떤걸 써야지 효과적일지에 대해 생각을 많이 하게 되었다.

그리고 순회를 구현하기 위해서 어떻게 할지 더 많은 회의가 필요할 것 같다.

넷째 날 2012 년 5 월 17 일 목요일

오늘의 작업 소스파악

초안 /************************************************************************

* cross_reference_generator.c

* 단어의 빈도수 및 단어가 위치한 줄번호를 출력하는 프로그램

************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

typedef short bool;

#define FALSE0

#define TRUE1

typedef struct _WORDNODE *PWORDNODE;

typedef struct _LINENODE *PLINENODE;

typedef struct _LINENODE// 단어가 출현시 그 라인번호에 대한 구조체.

{

intline_number;// 라인번호.

PLINENODEnext_node;// 다음 노드

} LINENODE;

typedef struct _WORDNODE//Binary Search Tree 의 노드 구조체.

{

charword[32];// 단어.

intfrequency;// 빈도수

PLINENODEpLine_node;// 단어가 나오는 라인번호 (Linked List 로 구현)

PWORDNODEleft_child;// 왼쪽자식노드

PWORDNODEright_child;// 오른쪽자식노드

} WORDNODE;

/************************************************************************

* Function Prototype Declare

************************************************************************/

// 노드를 삽입

void InsertNode( PWORDNODE* pRoot, char* aKey, int aLineNumber );

/* 같은 단어가 존재시에는 해당 노드 반환 혹은

*존재 하지 않을 시 삽입 할 위치의 parent node 의 포인터 반환 */

PWORDNODE Search( PWORDNODE pRoot , char* key ,bool* exist_same);

Page 8: 자료구조 Project4

/* 사전 순서대로 단어, 빈도수, 그리고 총 단어수 출력

*(inorder-traversal)*/

void PrintTree( PWORDNODE pRoot );

int main( int argc , char* argv[] )

{

PWORDNODEpRoot= NULL ;// 트리의 루트

charstring[256] = {0};// 텍스트파일 한 라인의 버퍼

char*ptr_key;// 토큰된 단어에 대한 포인터

char*ptr_lwr_key;// lower key , 소문자로 변환된 단어의 포인터

intline_number = 0 ;// 해당 라인 번호

FILE*in_file;// 읽어들일 파일 구조체.

if ( argc != 2 || strlen(argv[1]) == 0) {

printf("Usage : %s filename\n" , argv[0]);

return 0;

}

in_file = fopen(argv[1],"r");// 파일을 읽기전용 모드로 연다.

if (!in_file) {

fprintf(stderr,"Can not open a file. : %s \n",argv[1]);

exit(1);

}

while ( !feof(in_file) ) // in_file 이 끝에 도달 할 때까지 아래 내용을 실행.

{

memset(string,0,sizeof(string));// 한 라인에 대한 버퍼를 초기화.

fgets( string , sizeof(string),in_file);// 파일로 부터 라인을 읽어옴

++line_number;//라인번호 증가.

/*************************************************************************strtok , strlwr

사용법은 C reference manual 참조 바람.

************************************************************************/

// 문자열에서 separator 로 단어들을 추출

ptr_key = strtok( string, " `~!@#$%^&*()_-=+[]{};:\'\"|\\/?,.<>\t\n" );

while( ptr_key != NULL )

{

ptr_lwr_key = strlwr(ptr_key); // 해당 단어를 소문자로 변환

// 해당단어와 라인번호를 binary search 트리에 삽입

InsertNode( &pRoot , ptr_lwr_key , line_number );

// 다음 단어 추출.

ptr_key = strtok( NULL, " `~!@#$%^&*()_-=+[]{};:\'\"|\\/?,.<>\t\n" );

}

}

if ( pRoot )// 트리에 노드가 존재 한다면.

Page 9: 자료구조 Project4

{

printf("--------------------------------------------------------------------\n");

printf("%-19s|%-11s|%-19s\n", " 단어" , " 빈도수"," 라인");

printf("--------------------------------------------------------------------\n");

PrintTree( pRoot );// 트리 내용 출력.

printf("--------------------------------------------------------------------\n");

}

fclose(in_file);// 파일을 닫음.

return 0;

}

/************************************************************************

* 사전 순서대로 단어, 빈도수, 그리고 총 단어수 출력 (inorder-traversal)

************************************************************************/

void PrintTree( PWORDNODE pRoot )

{

PLINENODE tmpLineNode;// 해당 단어의 라인번호를 출력하기 위한 임시 포인터

if ( pRoot )// 루트가 널이 아니라면

{

tmpLineNode = pRoot->pLine_node ;// tmpLineNode 는 라인노드를 가르킴

PrintTree( pRoot->left_child );// 왼쪽 자식노드 출력.

// 중간, 즉 루트 노드 출력.

// 해당 노드의 단어와 빈도수 출력

printf(" %-18s|%9d |", pRoot->word , pRoot->frequency );

while ( tmpLineNode ) {// tmpLineNode 가 널일때 까지.

// 라인번호 출력

printf("%4d",tmpLineNode->line_number);

// 임시포인터는 링키드리스트의 다음 노드를 가리키게 함

tmpLineNode = tmpLineNode->next_node;

}

printf("\n");

PrintTree( pRoot->right_child );// 오른쪽 자식노드 출력

}

}

/************************************************************************

*같은 단어가 존재시에는 해당 노드 반환 혹은

*존재 하지 않을 시삽입 할 위치의 parent node 의 포인터 반환

************************************************************************/

PWORDNODE Search( PWORDNODE pRoot , char* key ,bool* exist_same)

{

PWORDNODE preNode = pRoot;// parent 노드를 기억 할 임시 변수

Page 10: 자료구조 Project4

while ( pRoot )// 해당노드가 널일때 까지.

{

preNode = pRoot;// 해당노드를 기억.

if ( strcmp( key, pRoot->word ) == 0 )// 해당노드가 같은 단어의 노드일경우

{

*exist_same = TRUE;// 같은것이 있다는것을 true 로 표시

return pRoot;// 그 노드를 반환.

}

if ( strcmp( key, pRoot->word ) < 0)// 키가 해당노드의 단어보다 앞쪽이라면

pRoot = pRoot->left_child;// 왼쪽 자식노드로 이동.

else

pRoot = pRoot->right_child;// 뒤쪽의 단어라면 오른쪽 자식노드로 이동

}

// 널이라면 그 전 노드(parent 노드)를 반환

return preNode;

}

/************************************************************************

* Tree 에 노드를 삽입. Binary Search Tree 로 구성.

************************************************************************/

void InsertNode( PWORDNODE* pRoot, char* aKey, int aLineNumber )

{

boolexist_same_word = FALSE;// 같은 단어가 트리내에 존재할시 true

// 같은 단어가 트리 내에 존재 하면 그 단어에 대한 노드,

// 없을 시에 새로 삽입될 위치의 parent 노드

PWORDNODE tmpWordNode = Search( *pRoot , aKey ,&exist_same_word);

PWORDNODE insertWordNode = NULL;// 트리에 삽입 될 노드

PLINENODE ptrLineNode = NULL; // 줄번호를 저장 할 노드.

/************************************************************

*key 가 tree 내에 존재할시.

************************************************************/

if ( exist_same_word )

{

// 반환된 노드 즉, tmpWordNode 는 Key 에 대한 노드

// 노드 내의 빈도수 증가

++(tmpWordNode->frequency);

// 라인번호에 대한 링키드 리스트의 끝 부분으로 이동.

ptrLineNode = tmpWordNode->pLine_node;

while( ptrLineNode->next_node )

ptrLineNode = ptrLineNode->next_node;

// 새로운 라인노드를 붙여준다.

Page 11: 자료구조 Project4

ptrLineNode->next_node = (PLINENODE)malloc(sizeof(LINENODE));

ptrLineNode->next_node->line_number = aLineNumber ; // 라인번호 저장

ptrLineNode->next_node->next_node = NULL;// 다음노드는 NULL 로 처리.

}

else if ( tmpWordNode || !(*pRoot) )

{

/************************************************************

* key 가 트리내에 없음.

************************************************************/

//////////////////////////////////////////////////////////////////////////

// 새로운 노드 생성, 라인번호와 단어를 저장.

insertWordNode = (PWORDNODE)malloc(sizeof(WORDNODE));

if (!insertWordNode) {

fprintf(stderr,"The Memory is full\n");

exit(1);

}

memset( insertWordNode , 0 , sizeof(WORDNODE));// 초기화

strcpy( insertWordNode->word , aKey );// 삽입될 노드에 키 복사

++(insertWordNode->frequency);// 빈도수 증가.

// 새로운 라인노드를 붙여준다.

insertWordNode->pLine_node = (PLINENODE)malloc(sizeof(LINENODE));

// 해당단어가 출현한 라인번호 저장.

insertWordNode->pLine_node->line_number = aLineNumber ;

// 다음노드는 NULL 로 처리.

insertWordNode->pLine_node->next_node = NULL;

//////////////////////////////////////////////////////////////////////////

// 그 노드를 적절한 위치에 삽입

if (*pRoot) // 루트가 널이 아니라면

{ // 키가 해당노드의 단어보다 앞쪽이라면

if ( strcmp( aKey, tmpWordNode->word ) < 0)

tmpWordNode->left_child = insertWordNode;// 왼쪽 자식노드에 삽입.

else

tmpWordNode->right_child = insertWordNode; // 아니라면 오른쪽 노드에 삽입.

}

else// 루트가 널이라면 루트에 해당 노드를 저장.

*pRoot = insertWordNode;

}

}

// cross_reference_generator.c END

알고리즘 단어 빈도수를 찾는 프로그램의 알고리즘은 먼저 단어를 저장할 문자열배열(data),

Page 12: 자료구조 Project4

해석

빈도수를 나타내는(data), 단어가 등장한 라인을 나타내는 (data), 다음 노드(구조체)를

가르키는 두 개의 포인터(왼쪽,오른쪽 자식)으로 구성되있는 구조체를 사용 하여

이진트리를 구성하며 프로그램이 진행된다.

먼저 파일의 한 라인을 읽어와서 “`~!@#$%^&*()_-=+[]{};:\'\"|\\/?,.<>\t\n” 앞의

문자로 끊어 한 단어로 인식 하고 라인 별로 읽기 때문에 다음 라인으로 갈 때 마다

라인넘버를 1 씩 증가 시켜 data 로 사용 하게 된다.

한 단어가 트리에 이미 저장되어 있는지 중복 검사 후 중복 되는 단어가 있다면 해당

단어가 저장 되있는 구조체에서 빈도수만 증가 시키고, 중복되지 않는다면(처음 등장하는

단어) 새로운 구조체를 만들어 저장 하고 빈도수, 등장하는 라인도 추가 시킨다.

단어를 추가시키는 방법은 접근한 구조체의 단어보다 앞의 단어이면 왼쪽, 뒤의 단어이면

오른쪽으로 저장한다.

파일의 모든 문자들을 읽은 후 트리의 저장이 완료 되면, 중위 순회 방법으로 트리의

단어,빈도수,라인넘버를 출력 한다 중위 순회는 출력의 우선순위가 왼쪽 노드의 값>현재

노드의 값>오른쪽 노드의 값 으로 정해져 있고 이 순서대로 단어를 출력 하면 해당

노드보다 앞의 단어는 왼쪽으로 게속 저장했으므로 이 방법을 사용 하여 사전식순으로

단어를 출력 한다.

출력은 다음 노드의 값이 없을때 까지 반복 하고 프로그램을 종료합니다.

Ⅳ. 반성

과제를

마치면서

느낀 점

과제를 마무리하지 못해 알고리즘을 해석하면서 과제를 마무리하였다.

많은 아쉬움을 가진 프로젝트가 되었다.