Upload
herojoon1378
View
250
Download
0
Embed Size (px)
DESCRIPTION
트리를 이용한 상호참조생성기
Citation preview
조 자료구조B2
보고서
상호참조 생성기[Project #4 : ]
조장 고충욱:
조원 강승우:
허규준
최완철
최수영
과제수행일지소속 조원
B2 조장 고충욱: 자료조사 최완철 최수영: , 프로그래밍 강승우 최규준: ,
과제수행기간 일4
계획의 작성I.
연구제목 TREE
연구배경 트리에 대해 이해하고 트리를 이용하여 상호참조 생성기를 만들 수 있다, .
참고자료
참고 서적 로 배우는 쉬운 자료구조 이지영 출판사 한빛미디어C
참고 URL
http://blog.naver.com/ctpoyou?Redirect=Log&logNo=10493277
8 트리의 정의와 트리의 종류-
http://internet512.chonbuk.ac.kr/datastructure/tree/tree8.ht
m 트리의 순회방법-
계획의 실행II.
첫째 날 년 월 일 목요일2012 5 3
오늘의 작업 조원의 업무 분담과 학습할 내용 및 과제에 대한 이해와 숙지
토의 내용
조장 고충욱:
자료조사 강승우 최완철 최수영: , ,
프로그래밍 허규준:
위와 같이 조원의 업무 분담을 하였으며 과제를 위한 자료조사와 프로그래밍에 대한 내
용을 인식하고 개별적으로 분담을 해서 조사를 하고 이해를 해 온 다음 그것을 조원들
에게 설명해주는 것으로 방향을 잡았다.
과제준비에서
느낀 점
이번과제의 내용을 보니 자료조사가 많이 필요할 것 같아서 자료조사를 중점으로 해야
겠다는 생각을 가지게 되었다.
둘째 날 년 월 일 목요일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 .
부모 노드가 된다 하위의 노드는 자식노드가 되고 여러개의 자식노드는 하나의 부모.
노드만 가질 수 있다.
아래의 그림에서 노드와 노드는 각각부모 노드 자식이 된다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)
위와 같은 트리가 있다고 한다면 각각 순회방법은 다음과 같습니다.
전위 순회(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
오늘의 작업 자료조사 내용
토의 내용
트리의 순회
이진 트리의 순회는 일정한 순서로 트리의 모든 노드들을 오직 한번씩만 방문하는 것이
다 트리의 순회는 트리 구조로 된 정보의 검색이나 수식 처리등에 유용하게 사용된다. .
특정 노드에서 자신의 왼쪽 서브 트리를 모두 방문하고 자기 노드를,
방문한 후에 오른쪽 서브 트리를 방문한다 이 원리를 모든 노드에 재.
귀적으로 적용하면 모든 노드들을 한번씩 방문할 수 있다.
특정 노드에서 먼저 자기 노드를 방문하고 왼쪽 서브 트리를 모두,
방문하고 마지막으로 오른쪽 서브 트리를 모두 방문한다 이 원리를, .
모든 노드에 재귀적으로 적용하면 모든 노드를 한번씩 방문할 수 있
다.
특정 노드에서 자신의 왼쪽 서브 트리와 오른쪽 서브 트리를 차례로
방문한 후 마지막으로 자신의 노드를 방문한다 이 원리를 모든 노드, .
에 재귀적으로 적용하면 각 노드를 한번씩 방문할 수 있다.
과제준비에서
느낀 점
순회에 대해 공부하면서 어떤걸 써야지 효과적일지에 대해 생각을 많이 하게 되었다.
그리고 순회를 구현하기 위해서 어떻게 할지 더 많은 회의가 필요할 것 같다.
넷째 날 년 월 일 목요일2012 5 17
오늘의 작업 소스파악
초안
/************************************************************************
* cross_reference_generator.c
단어의 빈도수 및 단어가 위치한 줄번호를 출력하는 프로그램*
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef short bool;
#define FALSE 0
#define TRUE 1
typedef struct _WORDNODE *PWORDNODE;
typedef struct _LINENODE *PLINENODE;
typedef struct _LINENODE 단어가 출현시 그 라인번호에 대한 구조체// .
{
int line_number; 라인번호// .
PLINENODE next_node; 다음 노드//
} LINENODE;
typedef struct _WORDNODE // 의 노드 구조체Binary Search Tree .
{
char word[32]; 단어// .
int frequency; 빈도수//
PLINENODE pLine_node; 단어가 나오는 라인번호// (Linked
로 구현List )
PWORDNODE left_child; 왼쪽자식노드//
PWORDNODE right_child; 오른쪽자식노드//
} WORDNODE;
/************************************************************************
* Function Prototype Declare
************************************************************************/
노드를 삽입//
void InsertNode( PWORDNODE* pRoot, char* aKey, int aLineNumber );
/* 같은 단어가 존재시에는 해당 노드 반환 혹은
* 존재 하지 않을 시 삽입 할 위치의 의 포인터 반환parent node */
PWORDNODE Search( PWORDNODE pRoot , char* key ,bool* exist_same);
/* 사전 순서대로 단어 빈도수 그리고 총 단어수 출력, ,
* (inorder-traversal) */
void PrintTree( PWORDNODE pRoot );
int main( int argc , char* argv[] )
{
PWORDNODE pRoot = NULL ; 트리의 루트//
char string[256] = {0}; 텍스트파일 한 라인의 버퍼//
char* ptr_key; 토큰된 단어에 대한 포인터//
char* ptr_lwr_key; 소문자로 변환된 단어// lower key ,
의 포인터
int line_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 ) 트리에 노드가 존재 한다면// .
{
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
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 )
{
bool exist_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;
새로운 라인노드를 붙여준다// .
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),
도수를 나타내는 단어가 등장한 라인을 나타내는 다음 노드 구조체 를(data), (data), ( )
가르키는 두 개의 포인터 왼쪽 오른쪽 자식 으로 구성되있는 구조체를 사용 하여 이진트( , )
리를 구성하며 프로그램이 진행된다.
먼저 파일의 한 라인을 읽어와서 앞“`~!@#$%^&*()_-=+[]{};:\'\"|\\/?,.<>\t\n”
의 문자로 끊어 한 단어로 인식 하고 라인 별로 읽기 때문에 다음 라인으로 갈 때 마다
라인넘버를 씩 증가 시켜 로 사용 하게 된다1 data .
한 단어가 트리에 이미 저장되어 있는지 중복 검사 후 중복 되는 단어가 있다면 해당
단어가 저장 되있는 구조체에서 빈도수만 증가 시키고 중복되지 않는다면 처음 등장하, (
는 단어 새로운 구조체를 만들어 저장 하고 빈도수 등장하는 라인도 추가 시킨다) , .
단어를 추가시키는 방법은 접근한 구조체의 단어보다 앞의 단어이면 왼쪽 뒤의 단어이,
면 오른쪽으로 저장한다.
파일의 모든 문자들을 읽은 후 트리의 저장이 완료 되면 중위 순회 방법으로 트리의,
단어 빈도수 라인넘버를 출력 한다 중위 순회는 출력의 우선순위가 왼쪽 노드의 값 현, , >
재 노드의 값 오른쪽 노드의 값 으로 정해져 있고 이 순서대로 단어를 출력 하면 해당>
노드보다 앞의 단어는 왼쪽으로 게속 저장했으므로 이 방법을 사용 하여 사전식순으로
단어를 출력 한다.
출력은 다음 노드의 값이 없을때 까지 반복 하고 프로그램을 종료합니다.
반성.Ⅳ
과제를 마치면서
느낀 점
과제를 마무리하지 못해 알고리즘을 해석하면서 과제를 마무리하였다.
많은 아쉬움을 가진 프로젝트가 되었다.