Download - Project#4상호참조 생성기 Hwp
project #4상호참조 생성기
자료구조 01조 : C3
조장 김창헌:조원 이상현:
김시백박가혜김정무
순 서순 서순 서순 서
프로젝트 설명프로젝트 설명프로젝트 설명프로젝트 설명1.1.1.1.트리1) (trees)프로젝트 전체일정프로젝트 전체일정프로젝트 전체일정프로젝트 전체일정2.2.2.2.업무분담업무분담업무분담업무분담3.3.3.3.초안초안초안초안4.4.4.4.문제점문제점문제점문제점5.5.5.5.최종안최종안최종안최종안6.6.6.6.느낀점느낀점느낀점느낀점7.7.7.7.
프로젝트 설명프로젝트 설명프로젝트 설명프로젝트 설명1.1.1.1.1) 트리 란( Tree ) ?
트리는 비선형 자료구조 배열이나 리스트는 선형 구조이다 기차 처럼 내 다음에 누가 있고 내 다음에( .
누가 있는.. )
와 로 구성됨 를 라고도 하고 를 라고도 표현한다Node( vertex ) Link( edge ) ( Node vertex Link edge . )
는 정보 를 포함하고 있음. Node ( data )
는 두 간의 연결 관계를 나타냄. Link Node
다음의 특징을 만족해야 함
. Root가 하나 존재 : 는 최상위Root Node
를 제외한 모든 는 하나의 부모를 가져야 함. Root Node
는 여러개의 자식을 가질 수 있음. Node
한 로 부터 다른 로 가는 경로는 유일해야 함. Node Node
• 전형적인 예 의 디렉토리 구조 이걸 볼때마다 이건 트리구조다 하고 생각하자) Windows ( . . )
트리의 예
는 가 아니다 그림이 잘못되었답니다I Leaf Node . .
트리의 용어들
용 어 내 용 설명
Node vertex 정보를 나타냄 그림에서 와 같은 객체를 노A, B, C, D, ...드라고 한다.
Link edge 의 연결관계를 나타Node냄 그림에서 선으로 나타낸것을 링크라고 한다.
Root Node 부모가 없는 최상위 노드 하나만 존재해야 한다.
Leaf Node
Termina lNodeE x t e r n a lNode
자식이 없는 최하위 노드 그림에서 하늘색으로 색칠된 노드들이 Leaf(잎 이다) Node .
Internal Node Non-Terminal Node 가 아닌 노드Leaf Node 자식이 하나라도 있는 노드 그림에서 A, B,
가 인터널 노드가 된다C, I .
Sub tree 트리의 부분집합 를 시작으로 트리를 떼어내면 가B Sub tree된다.
Path 한 로 부터 다른Node
로 가는 경로Node
그림에서 에서 로 가는 경로는E C이다 이 경로는 유일해야 한다E->B->A->C . .
다른 경로는 없다 중복이 없어야 한다( . ) .만약 가 연결되어 있다면 이것은 트리라, G-C고 할 수 없다 이런 자료구조는 그래프라. (고 부른다. )
최소 공통 선조
L e a s tCommonAncestors
두 노드의 공통적인 선조중 가장 레벨이 높은 선조 노드
그림에서 와 를 보면 두 노드의 공통 선H J조는 가 있는데 그중 는 이 이A, C C Level 2므로 가 의 최소 공통 선조가 된다C H, J .
자식 Children 자신의 아래로 연결된 노드 의 자식 노드는 와 가 있다C H I .
부모 Parent 자신의 위로 연결된 노드 의 부모는 이고 의 노드는 이다I C C A .
조부모 G r a n dParent 자신의 부모의 부모노드 조부모란 할아버지급 노드를 말한다 즉 의. I
조부모는 이고 의 조부모는 이다A J C .
레벨 Level 에서 특정 노드로Root가는 경로의 노드 수
그림에서 를 보면 경로에 개의 노I A, C, I 3드를 갖는다 그래서 은 이다. Level 3 .
높이 Height 가장 높은 레벨 가 로써 제일 높은 레벨이 된다J 4 .
이진 트리7.2 ( Binary Tree )• 이진 트리의 정의
• Full Binary Tree
이진 트리 의 정의( Binary Tree )
이진 트리의 정의
모든 가Internal Node 두개 이하의 자식을 갖는 트리
와 두개의 자식을 가질 수 있음Left Child Right Child
가장 쓰임새가 많은 트리
이진 트리의 용도
수식 계산에 사용Parse Tree :
정렬 에 사용Heap : ( Sorting )
검색에 사용Binary Search Tree :
Full Binary Tree
Full Binary Tree
마지막 레벨을 제외한 모든 레벨에 노드가 꽉차있음
Complete Binary Tree
모든 레벨에 노드가 꽉 차있음
와<full binary tree complete binary tree>
왼쪽의 그림을 보자 자식이 많아 봐야 개이다 이런 트리를 이진트리라고 하는 것이다 그런데 이진. 2 . .
트리 중에서도 와 가 있는데 왼쪽은 마지막 레벨 즉 레벨Full binary tree Complete binary tree , , H, I, J 4
에서는 노드가 꽉 차있지 않지만 마지막 레벨을 제외한 모든 레벨에 노드가 꽉 차 있으므로 Full binary
라고 하고 오른쪽 그림 처럼 모든 레벨에 노드가 꽉 차있으면 완벽한 라고tree , Complete( ) binary tree
부른다.
의 성질Full Binary Tree
레벨과 노드의 수 관계
레벨이 d일때, 트리의 노드수 N은 다음을 만족
2d-1 N 2≤ ≤ d - 1
개의 노드를 가진 이진 트리의 레벨 는 다음과 같다N d .
d = [ log2 는 소수점 이하는 버림한다N ] + 1 ( [ ] . )
숫자놀이를 해보자. ( Level = d, Node count = N )
2d-1 N 2≤ ≤ d 노드의 갯수는 이 범위안에 속한다- 1 ( . )
일때d = 2 , 22-1 노드의 갯수 2≤ ≤ 2 - 1
2 N 3≤ ≤ 이 된다.
일때d = 3 , 23-1 노드의 갯수 2≤ ≤ 3 - 1
이 된다4 N 7 .≤ ≤
일때d = 4 8 N 15≤ ≤
그림을 보고 이해해 보도록 하자.
최소 개 최대 이렇게 개가 된다 아마 최대갯수가 홀 수 인것은( A, B, C, D 4 , A, B, C, D, E, F, G 7 .
노드가 홀 수 이기 때문인거 같다Root . 2n으로 표현되는 것은 자식의 노드가 2n만큼 늘어나기 때문인
것 같은데 최소 노드의 갯수가, 2n-1인 것은 예를들어 이 이면 인 노드를 기준으로, Level 4 Level 1 Root 2
개씩 번 나누어졌기 때문에 개가 되고 최대 노드의 갯수가3 , 8 2n 인 것은 번씩 나뉜 만큼의 수에- 1 2
서 노드를 뺀 갯수가 되는 것이다Root . )
를 구하는 이 증명은 자료구조 시험문제에 가끔 나오니 알아두도록 하자Level d .
2d-1 N 2≤ ≤ d - 1
부등식에 log2를 취하면,
d - 1 log≤ 2N log≤ 2( 2d - 1 )
log2( 2d 는- 1 ) log22
d - log2 즉1 , log2와 가 소거되어 가 되고2 d - log2 은 이 된다1 - 0 . ( 2n 일때= 1
은n 0 )
결국 수식을 정리해 보면
d - 1 log≤ 2N <d 이렇게 되는데 부등식에 을 더하면, 1
d log≤ 2 여기에서N + 1 <d + 1 log2 의 소수점 이하 부분을 잘라낸 것과 같다는 의미가 된다N + 1 . (
log2 = 0.3010 )
그래서 d = [ log2N ] + 1 이다.
이진 트리의 구현7.3 ( Project : Tree )• 이진 트리 구현 방법
• 이진 트리 모델링
• Skeleton
이진 트리의 구현 방법
배열로 구현하는 방법
인 경우에만 사용가능. Full Binary Tree
이진 트리의 특징을 이용한 인덱스 조작.
에서 자세히 살펴볼 것임. Heap Sort
연결 리스트로 구현하는 방법
클래스가 하나의 노드를 나타냄. Node
이 노드는 와 로 두 자식을 가리킴. pLeft pRight
모든 자료구조의 기본이 되는 배열과 연결 리스트가 또 나왔다.
이진트리를 이중 연결리스트 로 구현하는 법에 대해서 알아보자( Doubly Linked List ) .
이진 트리 모델링
시작 과 끝 을 나타내는 가짜 노드 사용Head( ) Tail( )
. m_pNodeHead / m_pNodeTail
. Root Node == m_pNodeHead->pLeft
모든 의 와. Leaf Node pLeft pRight == m_pNodeTail
와 를 보면 이 객체가 무엇을 의미하는지는 변수명을 보자 은 클래스의m_pNodeHead m_pNodeTail .. ( . m
멤버 변수라는 뜻이고 의 와 의 이라는 뜻이다, Node Head Node Tail . )
일단 비어있는 한 트리로 시작하게 되는데 헤드 노드의 와 는 꼬리 노드의 시작주( Empty ) pLeft pRight
소를 가리키고 있고 꼬리 노드의 와 는 자기 자신의 시작주소를 가리키고 있다, pLeft pRight .
여기서 클래스와 객체의 구분은 는 멤버 변수와 함수들을 정의 해 놓은 것이고 객체는 그 클래스( class
를 이용해 만들어 낸 것을 말한다.
이게 클래스이고class People { m_pName, m_pAge, void SetName() }; ,
김철수 여기서 이 객체가 되는것이다People p1( " ", 26 ); p1 . )
오른쪽 그림을 보면 로 나타낸 개념적 트리가 있는데 이것을 물리적 트리로 오른쪽 그림과A, B, C, D
같이 표현할 수 있다.
가짜 노드 는 리스트의 시작을 의미하고 에 노드 를 링크하게 된다m_pNodeHead( ) pLeft Root A . pRight
에는 가짜 노드 를 가리키게 된다 의 는 잘 사용하지 않을 것이다m_pNodeTail( ) . m_pNodeHead pRight .
이제 노드 를 보자 노드의 에는 노드가 에는 노드가 있고 다시 노드의 에Root A . A pLeft B pRight C B pLeft
는 노드가 있으며 가 없는 노드들은 모두 끝 을 가리키고 있다D pRight m_pNodeTail( ) .
Binary Tree Skeleton
구성
• 노드를 나타내는 struct Node
• 시작과 끝을 나타내는 m_pNodeHead, m_pNodeTail
• Ctors / Dtors
• 제거를 위한 RemoveAll
도 어떤 객체들의 컨테이너 역할을 하는 것이기 때문에 를 사용 하였다고 한다Binary Tree template .
클래스의 뼈대를 간단히 살펴보면 위의 구성 내용과 같다Binary Tree .
template<class TYPE >
class BinaryTree
{
public:
BinaryTree();
~BinaryTree();
void RemoveAll();
protected:
struct Node
{
TYPE data;
Node* pLeft;
Node* pRight;
};
Node* m_pNodeHead;
Node* m_pNodeTail;
void RemoveSubtree( Node* pNode );
};
일단 가 있고struct Node{ TYPE data, Node* pLeft, Node* pRight }; ,
이를 로 표현 하려면 이 필요하다 구class BinaryTree [Head] - [Node1] - [Node2] - [ ... ] - [Tail] . Node
조체를 안에 포함 시키고 시작 주소를 나타내는 와 을class Node* m_pNodeHead Node* m_pNodeTail
추가시켜 주자.
그리고 클래스의 기능에 필요한 멤버 함수들을 추가시켜 주자 여기에서는 모든 노드를 소거BinaryTree .
시키는 기능과 를 소거 시키는 기능이 추가되어 있다SubTree .
기능과 기능이 없는 이유는 에는 다양한 가 있는데 이는 나중에 이 기본 클래Insert() Remove() Tree Tree
스에서 계승 받아 구현하려고 하기 때문이다 일단 그렇게 알아두자 이라는 전체적으. . void RemoveAll()
로 필요한 기능만 추가되어 있는 것이다.
생성자와 제거자의 약자Ctors / Dtors ( )
Constructor
시작과 끝을 나타내는 가짜노드 두개를 만듦
Desturctor
을 호출한 뒤 가짜 노드를 지움RemoveAll ,
의 모든 를 지우기 위해서 모든 노드를 방문하는 방법이 필요함Tree Node
생성자에서는 그러니까 나중에 함수에서 이 클래스를 사용해 객체를 만들때.. void Main() , BinaryTree
객체 이 생성될때 어떠한 구조로 생성이 되는가b1(); b1 ?
인 은 메모리상에 가짜노드와 가짜노드가 만들어 지고 그 와 의BinaryTree b1 Head Tail Head Tail pLeft,
는 저 기 위쪽 그림과 같이 연결되어 있다pRight ~ .
그럼 이 의 객체에 홍길동 하게 되면 그 노드가 삽입되어 연결되는 것이다b1 b1.Insert( " " ); .
생성자에서 어떤 구조를 형성하는지 잘 생각해보고 넘어가자.
template<class TYPE >
BinaryTree< TYPE >::BinaryTree()
{
m_pNodeHead =new Node;
m_pNodeTail =new Node;
m_pNodeHead->pLeft = m_pNodeTail;
m_pNodeHead->pRight = m_pNodeTail;
m_pNodeTail->pLeft = m_pNodeTail;
m_pNodeTail->pRight = m_pNodeTail;
}
제거자에서는 이 객체가 사라질때 객체에서 사용한 모든 메모리를 해제시켜주는 역할을BinaryTree b1 b1
하게 된다.
이렇게 형성된 메모리를 전부 날려버리는 것이다[Head] - [Node1] - [Node2] - [ ... ] - [Tail] .
template<class TYPE >
BinaryTree< TYPE >::~BinaryTree()
{
RemoveAll(); 중간 노드들 제거//
if( m_pNodeHead )delete m_pNodeHead; 가짜 노드 와// Head
if( m_pNodeTail )delete m_pNodeTail; 제거// Tail
}
트리 순회7.4 Tree Traversal ( )• Pre-order Traversal
• In-order Traversal
• Post-order Traversal
• Level-order Traversal
이 필요한 이유Tree Traversal ?
• 비선형 구조여서 전체 노드를 방문하는 방법이 필요함.
여러가지 방법이 존재함 선형구조라면 으로 간다던가 으로 간다던가 하는데( -> <- .. )
기반 이런 방법들이 있다. Stack : Pre-order, Post-order, In-order ( . )
기반. Queue : Level-order
전산학 학부생 같은경우 이 내용이 시험에 자주 나올 만큼 중요한 부분이다 정보처리 기사 시험에서도.
자주 나오는 내용이다.
Pre-Order Traversal
• 알고리즘
1. Root를 방문한다
1. 왼쪽 Subtree를 방문한다.
1. 오른쪽 Subtree를 방문한다.
을 방문하고 를 방문하고 을 방문한다 안에서 또 가 있다면 왼쪽부터 방문하게 된다1 2 3 . ( 2 subTree . ==
재귀호출의 맛보기.. )
void BinaryTree::PreOrderTraverse( Node* pNode ) 부터 시작해서 방문// pNode
{
if( pNode != m_pNodeTail ) 재귀 호출 함수는 종료 조건이 꼭 필요하다// .
{
Visit( pNode ); // Do Something
PreOrderTraverse( pNode->pLeft ); 방문했으면 에 결린다 그리고 가// Do Something . pNode
이 아니면 또 왼쪽으로 링크된 노드에 방문하게 되어있다Tail .
PreOrderTraverse( pNode->pRight ); 위 함수가 종료되면 여기부터 시작//
}
}
이런식으로 방문하게 되는 가 앞 순서 방문 이 된다Tree Pre-order Traversal( ) .
를 방문하는 타이밍에 대해 자세히 보자Root .
In-Order Traversal
• 알고리즘
1. 왼쪽 를 방문한다Subtree .
1. 를 방문한다Root .
1. 오른쪽 를 방문한다Subtree .
을 방문하고 를 방문하고 을 방문한다1 2.Root 3 .
void BinaryTree::InOrderTraverse( Node* pNode )
{
if( pNode != m_pNodeTail )
{
InOrderTraverse( pNode->pLeft );
Visit( pNode ); // Do Something
InOrderTraverse( pNode->pRight );
}
}
InOrderTraverse( pNode->pLeft );를 계속 만나게 되므로일단 까지 내려 간다 그다음 에 다다랐을G . Tail
때 함수가 종료되고 다음 라인 함수를 만나게 되어 방문하게 된다Visit( pNode ); . Do Something(
라던가 를 하고 나서 함수가 발동되는데 노드에는 도printf .. ) pRight G pRight Tail if( pNode !=
m_pNodeTail ) 이니까 재귀호출 함수를 빠져나가게 된다 그럼 노드의 함수부터 시작. D Visit( pNode );
하게 되고 노드의 를 방문하게 된다, D pRight .
Post-Order Traversal
• 알고리즘
1. 왼쪽 를 방문한다Subtree .
1. 오른쪽 를 방문한다Subtree .
1. 를 방문한다Root .
void BinaryTree::InOrderTraverse( Node* pNode )
{
if( pNode != m_pNodeTail )
{
InOrderTraverse( pNode->pLeft );
InOrderTraverse( pNode->pRight );
Visit( pNode );
}
}
를 호출하였다면InOrderTraverse( A );
InOrderTraverse( A->pLeft ); 가 링크되어 있다 재귀호출 함수에 의해// B .
InOrderTraverse( B->pLeft );
InOrderTraverse( D->pLeft );
InOrderTraverse( G->pLeft ); 모두 하여 를 출력// pLeft, pRight Tail.. Visit G
InOrderTraverse( D->pRight );
InOrderTraverse( H->pLeft ); 모두 하여 를 출력// pLeft, pRight Tail.. Visit H
의 를 방문함수 재귀호출 를 이행하였으므로 그 다음라인D pLeft, pRight ( ) Visit( D ); 를 출력// D
InOrderTraverse( B->pRight );
// ...
그림을 놓고 이해를 하는게 빠르다.
버전Pre-Order Traversal : Stack
재귀 호출은
일반적으로 을 사용하여 방식으로 바꿀 수 있다stack non-recursive .
는 다소 복잡하다Post-Order, In-Order .
재귀호출을 사용하면 코드가 깔끔하지만 성능이 않좋아서 옛날에 사용..
이 함수는 재귀호출이 아니다.
void BinaryTree::PreOrderTraverse_Stack( Node* pNode )
{
ListStack< Node*> stack;
stack.Push( pNode );
while(!stack.IsEmpty())
{
pNode = stack.Pop();
if( pNode != m_pNodeTail )
{
Visit( pNode );
stack.Push( pNode->pRight );
stack.Push( pNode->pLeft );
}
}
}
여기서 Node* 를 사용하여 노드포인터 를 가져오는 것은 만약 가져오는 객체의 크기가( pNode )
라면 가져오기 난감할 것이다 포인터로 주소를 가져오게 되면 그 객체에 접근할 수가 있다 함100byte . .
수 구현 첫번째 라인을 보면 Node* 포인터를 스택에 담는것을 알 수 있다 큰 객체를 다 담아버리게 되.
면 말도 안되는 메모리를 사용하게 되므로 그 객체를 포인팅 하고 있는 포인터를 담아두면 언제든지 그
객체에 접근할 수 있기 때문이다 에 넣는다는것은 프링글즈를 생각하면 되는데 소스 코드를 보면. stack ..
일단 함수 호출을 통해 가지고 온 노드를 에 한번 하고 다시 빼내어 방문하게 되는것을 볼 수stack Push
있다.
를 먼저 하는 이유는 이기 때문이다 먼저 하면 바닥쪽에 깔리고 나중에 하면pRight Push stack . Push Push
윗쪽으로 올라가기 때문에 할때는 부터 나오기 때문이다Pop pLeft .
재귀호출 방식을 이용하는게 좋으나 알고리즘 구현 방식에도 다양한 방법이 있다는 것을 상기하자, .
Level-Order Traversal
가장 직관적인 Traversal
위에서 아래로 좌에서 우로 진행, ( A ~ I )
로 진행을 하는데 앞 소스와 거의 똑같은데 과 의 차이점에 의해 방문순서가 이렇게Queue , Stack Queue
된다.
void BinaryTree::LevelOrderTraverse( Node* pNode )
{
ListQueue< Node*> queue;
queue.Put( pNode );
while(!queue.IsEmpty())
{
pNode = queue.Get();
if( pNode != m_pNodeTail )
{
Visit( pNode );
queue.Put( pNode->pLeft );
queue.Put( pNode->pRight );
}
}
}
노드를 가져오고 에 하고 다시 꺼내어 그 노드를 방문하고 를 에 하고A queue Put pLeft queue Put pRight
를 하고 꺼내어 하게 된다 는 은행 번호표를 생각하면 되는데 에 된 순서로 빠Put Visit . Queue queue Put
져나오기 때문에 의 순서가 나오게 된다A~I .
수식 트리7.5 ( Parse Tree )• 수식 트리 개념
• 수식 트리 구축법
수식트리의 개념
정의
수식을 연산순서에 따라 트리로 구성.
. 에 에 를 배치Root Oeprator, Child Operand
모든 는 는. Operator Non-Terminal, Operand Terminal Node
( ( A + B ) * ( C - D ) ) / E + ( F * G )
를 더하고 와 를 뺼셈하고 그 값을 곱하고A B C D ...
수식 트리를
1. 하면In-Order Traverse Infix Notation
1. 하면Pre-Order Traverse Prefix Notation
1. 하면Post-Order Traverse Postfix Notation
후위 표기 에서 수식 트리 구성( Post-Order )
후위 표기는 컴퓨터가 이해하기 가장 편리하게 되어있다.
알고리즘
는 를 만들어1. Operand Node Stack에 Push
를 만나면 를 생성하여2. Operator Node
에서 한 노드를 오른쪽 자식으로 하고1. Stack Pop
에서 또 한 노드를 왼쪽 자식으로 하고2. Stack Pop
와 링크된 두 자식 노드 자체를 에3. Operator Node Stack Push
에 마지막으로 남은 노드가 이다3. Stack Root .
위에 그림과 같이 되게 된다.
수식 트리의 구현7.6• Skeleton
• BuildParseTree
ParseTree skeleton
구성
의 로 부터 계승을 받음. template instance
구성. BuildParseTree : ParseTree
. Traversal Functions
상위 클래스에서 이미 구현된 부분은 구현할 필요가 없다 이게 계승의 장점이다. .
class ParseTree :public BinaryTree< String > 이진 트리// TYPE : String
{
public:
void BuildParseTree(const String& strPostfix );
bool IsOperator(char c )
{
return( c =='+'|| c =='-'|| c =='*'|| c =='/');
}
void PreOrderTraverse( Node* pNode =0);
void PostOrderTraverse( Node* pNode =0);
void InOrderTraverse( Node* pNode =0);
void LevelOrderTraverse( Node* pNode =0);
void Visit( Node* pNode );
};
함수에서 만드는거나 함수 안에서 만드는 거나 그게 그거// Main .. ..
void ParseTree::BuildParseTree(const String& strPostfix )
{
Node* pNode; 의 포인터를 준비// Node
int i =0;
ListStack< Node*> NodeStack; 스택 리스트를 준비//
RemoveAll();
while( strPostfix[ i ]) 을 읽자// String .
{
while( strPostfix[ i ]==' ')
i++; 공백 문자는 무시//
pNode =new Node;
if( IsOperator( strPostfix[ i ])) 연산자이면//
{
pNode->data = strPostfix[ i ];
i++;
pNode->pRight = NodeStack.Pop();
pNode->pLeft = NodeStack.Pop();
}
else 피연산자 숫자 이면// ( )
{
do
{
pNode->data += strPostfix[ i ];
i++;
}
while( strPostfix[ i ]!=' '&& i < strPostfix.GetLength());
pNode->pLeft = m_pNodeTail;
pNode->pRight = m_pNodeTail;
}
NodeStack.Push( pNode );
}
m_pNodeHead->pLeft = NodeStack.Pop(); // Root
}
결론7.트리는 노드와 링크로 구성된 비선형 자료구조
이진 트리는 두개 이하의 자식을 가지는 트리
이진 트리의 은 트리의 모든 노드를 방문하기 위한 방법이다Traversal .
가 있다InOrder, PreOrder, PostOrder, LevelOrder .
스택을 이용하여 후위 표기로 부터 수식 트리 를 만들었다( Parse Tree ) .
방법에 따라 다른 수식 표기가 나옴Traversal
출처출처출처출처[[[[ http://blog.naver.com/hkn10004?Redirect=Log&logNo=20109208779
프로젝트 전체일정프로젝트 전체일정프로젝트 전체일정프로젝트 전체일정2.2.2.2.기 간 5 / 8 5 / 10
내 용- 조원별 업무 분담 및 계획 작성프로젝트 문제파악-
- 프로젝트에필요한학습내용토의프로젝트 진행방향 토의-
- 알고리즘에 대해 토의하고 이해문제점 토의-
기 간 5 / 15 5 / 17
내 용 소스 구현 및 보고서 작성-프로젝트 검토-최종보고서 작성-발표준비-
업무분담업무분담업무분담업무분담3.3.3.3.이 름이 름이 름이 름 업 무업 무업 무업 무김창헌 보고서 작성 및 회의 진행 프로젝트에 필요한 학습내용 숙지,
김시백 알고리즘 설계와 소스에 대한 문제점 검토와 보완
박가혜 소스구현 및 코딩 문제의 해결을 위한 방안 제시
김정무 알고리즘 설계 및 프로젝트 수행 시 필요한 자료 수집
이상현 알고리즘 설계 및 프로젝트 수행 시 필요한 자료 수집
초안초안초안초안4.4.4.4.#include <stdio.h>#include <stdio.h>#include <stdio.h>#include <stdio.h>#include <string.h>#include <string.h>#include <string.h>#include <string.h>#include <stdlib.h>#include <stdlib.h>#include <stdlib.h>#include <stdlib.h>
#define MAX 1000#define MAX 1000#define MAX 1000#define MAX 1000
char SIGN[] = " .,!?:\"\t\r\n";char SIGN[] = " .,!?:\"\t\r\n";char SIGN[] = " .,!?:\"\t\r\n";char SIGN[] = " .,!?:\"\t\r\n";
typedef struct Listtypedef struct Listtypedef struct Listtypedef struct List{{{{
char *word;char *word;char *word;char *word;int count;int count;int count;int count;struct List *next;struct List *next;struct List *next;struct List *next;
} List;} List;} List;} List;
List head={0,};List head={0,};List head={0,};List head={0,};List* tail = &head;List* tail = &head;List* tail = &head;List* tail = &head;
int word_count = 0; // # of wordsint word_count = 0; // # of wordsint word_count = 0; // # of wordsint word_count = 0; // # of wordsList **W = 0;List **W = 0;List **W = 0;List **W = 0;
void array(List *head, List **W)void array(List *head, List **W)void array(List *head, List **W)void array(List *head, List **W){{{{
List *temp = head->next;List *temp = head->next;List *temp = head->next;List *temp = head->next;int i = 0;int i = 0;int i = 0;int i = 0;while (temp)while (temp)while (temp)while (temp){{{{
W[i++] = temp;W[i++] = temp;W[i++] = temp;W[i++] = temp;temp = temp->next;temp = temp->next;temp = temp->next;temp = temp->next;
}}}}}}}}
void printW(List **W, int n)void printW(List **W, int n)void printW(List **W, int n)void printW(List **W, int n){{{{
int i;int i;int i;int i;for(i=0; i < n; i++) {for(i=0; i < n; i++) {for(i=0; i < n; i++) {for(i=0; i < n; i++) {
printf("%20s : %d\n",W[i]->word, W[i]->count);printf("%20s : %d\n",W[i]->word, W[i]->count);printf("%20s : %d\n",W[i]->word, W[i]->count);printf("%20s : %d\n",W[i]->word, W[i]->count);}}}}
}}}}
List* F_Token(const char* token)List* F_Token(const char* token)List* F_Token(const char* token)List* F_Token(const char* token){{{{
List *temp = head.next;List *temp = head.next;List *temp = head.next;List *temp = head.next;while (temp)while (temp)while (temp)while (temp){{{{
if (strcmp(temp->word,token)==0)if (strcmp(temp->word,token)==0)if (strcmp(temp->word,token)==0)if (strcmp(temp->word,token)==0)return temp;return temp;return temp;return temp;
temp = temp->next;temp = temp->next;temp = temp->next;temp = temp->next;}}}}return 0;return 0;return 0;return 0;
}}}}
void InsertList(char *token)void InsertList(char *token)void InsertList(char *token)void InsertList(char *token){{{{
List *temp = F_Token(token);List *temp = F_Token(token);List *temp = F_Token(token);List *temp = F_Token(token);if (temp) // Found,if (temp) // Found,if (temp) // Found,if (temp) // Found,{{{{
temp->count++;temp->count++;temp->count++;temp->count++;}}}}elseelseelseelse{{{{
int len = strlen(token)+1;int len = strlen(token)+1;int len = strlen(token)+1;int len = strlen(token)+1;temp = (List*)malloc(sizeof(List));temp = (List*)malloc(sizeof(List));temp = (List*)malloc(sizeof(List));temp = (List*)malloc(sizeof(List));temp->word = (char*)malloc(sizeof(char)*len);temp->word = (char*)malloc(sizeof(char)*len);temp->word = (char*)malloc(sizeof(char)*len);temp->word = (char*)malloc(sizeof(char)*len);strncpy(temp->word, token, len);strncpy(temp->word, token, len);strncpy(temp->word, token, len);strncpy(temp->word, token, len);temp->count = 1;temp->count = 1;temp->count = 1;temp->count = 1;temp->next = 0;temp->next = 0;temp->next = 0;temp->next = 0;tail->next = temp;tail->next = temp;tail->next = temp;tail->next = temp;tail=temp;tail=temp;tail=temp;tail=temp;
word_count++;word_count++;word_count++;word_count++;}}}}
}}}}
void free_token()void free_token()void free_token()void free_token(){{{{
List *temp;List *temp;List *temp;List *temp;while (temp = head.next)while (temp = head.next)while (temp = head.next)while (temp = head.next){{{{
if (temp->word)if (temp->word)if (temp->word)if (temp->word)free(temp->word);free(temp->word);free(temp->word);free(temp->word);
head.next = temp->next;head.next = temp->next;head.next = temp->next;head.next = temp->next;
free(temp);free(temp);free(temp);free(temp);}}}}tail = &head;tail = &head;tail = &head;tail = &head;
}}}}
typedef List *T;typedef List *T;typedef List *T;typedef List *T;
void swap(T *a, T *b)void swap(T *a, T *b)void swap(T *a, T *b)void swap(T *a, T *b){{{{
T t = *a;T t = *a;T t = *a;T t = *a;*a = *b;*a = *b;*a = *b;*a = *b;*b = t;*b = t;*b = t;*b = t;
}}}}
int comp(const void *pa, const void *pb)int comp(const void *pa, const void *pb)int comp(const void *pa, const void *pb)int comp(const void *pa, const void *pb){{{{
const T a = *(const T *)pa;const T a = *(const T *)pa;const T a = *(const T *)pa;const T a = *(const T *)pa;const T b = *(const T *)pb;const T b = *(const T *)pb;const T b = *(const T *)pb;const T b = *(const T *)pb;
return strcmp(a->word,b->word);return strcmp(a->word,b->word);return strcmp(a->word,b->word);return strcmp(a->word,b->word);}}}}
int partition(T *A, int left, int right, int pivot)int partition(T *A, int left, int right, int pivot)int partition(T *A, int left, int right, int pivot)int partition(T *A, int left, int right, int pivot){{{{
int i, index;int i, index;int i, index;int i, index;T value = A[pivot];T value = A[pivot];T value = A[pivot];T value = A[pivot];
swap(&A[pivot],&A[right]);swap(&A[pivot],&A[right]);swap(&A[pivot],&A[right]);swap(&A[pivot],&A[right]);index = left;index = left;index = left;index = left;for (i = left; i < right; i++) {for (i = left; i < right; i++) {for (i = left; i < right; i++) {for (i = left; i < right; i++) {
if (comp(&A[i],&value) < 0) {if (comp(&A[i],&value) < 0) {if (comp(&A[i],&value) < 0) {if (comp(&A[i],&value) < 0) {swap(&A[i],&A[index]);swap(&A[i],&A[index]);swap(&A[i],&A[index]);swap(&A[i],&A[index]);++index;++index;++index;++index;
}}}}}}}}swap(&A[index],&A[right]);swap(&A[index],&A[right]);swap(&A[index],&A[right]);swap(&A[index],&A[right]);return index;return index;return index;return index;
}}}}
void quick_p(T *A, int left, int right)void quick_p(T *A, int left, int right)void quick_p(T *A, int left, int right)void quick_p(T *A, int left, int right){{{{
int pivot;int pivot;int pivot;int pivot;int index;int index;int index;int index;
if (right > left) {if (right > left) {if (right > left) {if (right > left) {pivot = (right+left)/2;pivot = (right+left)/2;pivot = (right+left)/2;pivot = (right+left)/2;index = partition(A, left, right, pivot);index = partition(A, left, right, pivot);index = partition(A, left, right, pivot);index = partition(A, left, right, pivot);quick_p(A, left, index-1);quick_p(A, left, index-1);quick_p(A, left, index-1);quick_p(A, left, index-1);quick_p(A, index+1, right);quick_p(A, index+1, right);quick_p(A, index+1, right);quick_p(A, index+1, right);
}}}}}}}}
void quicksort(T *A, int n)void quicksort(T *A, int n)void quicksort(T *A, int n)void quicksort(T *A, int n){{{{
quick_p(A,0,n-1);quick_p(A,0,n-1);quick_p(A,0,n-1);quick_p(A,0,n-1);}}}}
int main(void)int main(void)int main(void)int main(void){{{{
char *str;char *str;char *str;char *str;char *token;char *token;char *token;char *token;long length;long length;long length;long length;int i=0;int i=0;int i=0;int i=0;
FILE* fp = fopen("C:\\test.txt", "rt");FILE* fp = fopen("C:\\test.txt", "rt");FILE* fp = fopen("C:\\test.txt", "rt");FILE* fp = fopen("C:\\test.txt", "rt");
if (fp==NULL)if (fp==NULL)if (fp==NULL)if (fp==NULL){{{{
puts("File open fail!");puts("File open fail!");puts("File open fail!");puts("File open fail!");return -1;return -1;return -1;return -1;
}}}}
fseek(fp, 0, SEEK_END);fseek(fp, 0, SEEK_END);fseek(fp, 0, SEEK_END);fseek(fp, 0, SEEK_END);length = ftell(fp);length = ftell(fp);length = ftell(fp);length = ftell(fp);rewind(fp);rewind(fp);rewind(fp);rewind(fp);
str = (char*)malloc(sizeof(char)*length+1);str = (char*)malloc(sizeof(char)*length+1);str = (char*)malloc(sizeof(char)*length+1);str = (char*)malloc(sizeof(char)*length+1);memset(str, 0, sizeof(char)*length+1);memset(str, 0, sizeof(char)*length+1);memset(str, 0, sizeof(char)*length+1);memset(str, 0, sizeof(char)*length+1);
상호참조 생성기상호참조 생성기상호참조 생성기상호참조 생성기puts("***************** *****************");puts("***************** *****************");puts("***************** *****************");puts("***************** *****************");단어 빈도수단어 빈도수단어 빈도수단어 빈도수puts("**************** : ******");puts("**************** : ******");puts("**************** : ******");puts("**************** : ******");
fread(str, 1, length, fp);fread(str, 1, length, fp);fread(str, 1, length, fp);fread(str, 1, length, fp);fclose(fp);fclose(fp);fclose(fp);fclose(fp);token=strtok(str,SIGN);token=strtok(str,SIGN);token=strtok(str,SIGN);token=strtok(str,SIGN);while (token!=NULL)while (token!=NULL)while (token!=NULL)while (token!=NULL){{{{
InsertList(token);InsertList(token);InsertList(token);InsertList(token);
token=strtok(NULL,SIGN);token=strtok(NULL,SIGN);token=strtok(NULL,SIGN);token=strtok(NULL,SIGN);}}}}
W = (List **)malloc(sizeof(List*)*word_count);W = (List **)malloc(sizeof(List*)*word_count);W = (List **)malloc(sizeof(List*)*word_count);W = (List **)malloc(sizeof(List*)*word_count);array(&head, W);array(&head, W);array(&head, W);array(&head, W);
quicksort(W,word_count);quicksort(W,word_count);quicksort(W,word_count);quicksort(W,word_count);// qsort(W,word_count,sizeof(T),comp);// qsort(W,word_count,sizeof(T),comp);// qsort(W,word_count,sizeof(T),comp);// qsort(W,word_count,sizeof(T),comp);
printW(W,word_count);printW(W,word_count);printW(W,word_count);printW(W,word_count);
free(W);free(W);free(W);free(W);free_token();free_token();free_token();free_token();
system("pause");system("pause");system("pause");system("pause");return 0;return 0;return 0;return 0;
}}}}
문제점문제점문제점문제점5.5.5.5.
단어별 라인이 나오지 않음.단어의 대소문자 구별해서 나옴.단어의 총 개수가 출력되지 않음.
최종안최종안최종안최종안6.6.6.6.#include <stdio.h>#include <string.h>#include <stdlib.h>
#define MAX 1000
char SIGN[] = " .,!?:\"\t\r\n";
typedef struct List{
char *word;int count;struct List *next;
} List;
List head={0,};List* tail = &head;
int word_count = 0; // # of wordsList **W = 0;
void list2array(List *head, List **W){
List *temp = head->next;int i = 0;while (temp){
W[i++] = temp;temp = temp->next;
}}
void printW(List **W, int n){
int count=0;int i;for(i=0; i < n; i++) {
printf("%20s : %d\n",W[i]->word, W[i]->count);count++;
}
printf("\t\ttotal=%d",count);
}
List* FindToken(const char* token){
List *temp = head.next;while (temp){
if (strcmp(temp->word,token)==0)return temp;
temp = temp->next;}return 0;
}
void InsertList(char *token){
List *temp = FindToken(token);if (temp) // Found,{
temp->count++;}else{
int len = strlen(token)+1;temp = (List*)malloc(sizeof(List));temp->word = (char*)malloc(sizeof(char)*len);strncpy(temp->word, token, len);temp->count = 1;temp->next = 0;tail->next = temp;tail=temp;
word_count++;}
}
void print_token()
{List *temp = head.next;FILE* fw = fopen("daul\\Ouput.txt", "wt");
while (temp){
fprintf(fw, "%s : %d\n", temp->word, temp->count);temp = temp->next;
}fclose(fw);
}
void free_token(){
List *temp;while (temp = head.next){
if (temp->word)free(temp->word);
head.next = temp->next;free(temp);
}tail = &head;
}
정렬할 자료형typedef List *T; // T
void swap(T *a, T *b){
T t = *a;*a = *b;*b = t;
}
int comp(const void *pa, const void *pb){
const T a = *(const T *)pa;const T b = *(const T *)pb;
return strcmp(a->word,b->word);}
int partition(T *A, int left, int right, int pivot){
int i, index;T value = A[pivot];
swap(&A[pivot],&A[right]);index = left;for (i = left; i < right; i++) {
if (comp(&A[i],&value) < 0) {swap(&A[i],&A[index]);++index;
}}swap(&A[index],&A[right]);return index;
}
void quickpart(T *A, int left, int right){
int pivot;int index;
if (right > left) {pivot = (right+left)/2;index = partition(A, left, right, pivot);quickpart(A, left, index-1);quickpart(A, index+1, right);
}}
void quicksort(T *A, int n){
quickpart(A,0,n-1);}
int main(void){
char *str; // File total Length,char *token; // token,
파일전체길이long length; //int i=0;
텍스트모드로 읽기FILE* fp = fopen("cmake.txt", "rt"); //
// Open not file,if (fp==NULL){
puts("File open fail!");return -1;
}
fseek(fp, 0, SEEK_END);length = ftell(fp);rewind(fp);
str = (char*)malloc(sizeof(char)*length+1);memset(str, 0, sizeof(char)*length+1);
상호참조 생성기상호참조 생성기상호참조 생성기상호참조 생성기puts("***************** *****************");puts("***************** *****************");puts("***************** *****************");puts("***************** *****************");단어 빈도수단어 빈도수단어 빈도수단어 빈도수puts("**************** : ******");puts("**************** : ******");puts("**************** : ******");puts("**************** : ******");
자료주소값 바이트크기 개수 파일포인터fread(str, 1, length, fp); // , , ,파일 닫기fclose(fp); //
단어 수집//문자열자르기token=strtok(str,SIGN); //
while (token!=NULL){
InsertList(token);두번째토큰 호출부터는 첫 번째 인수자리에 기입// , NULL
token=strtok(NULL,SIGN);}
단어의 포인터 배열//W = (List **)malloc(sizeof(List*)*word_count);
리스트에서 배열로list2array(&head, W); //
정렬quicksort(W,word_count); //정렬// qsort(W,word_count,sizeof(T),comp); //
정렬 출력printW(W,word_count); //
free(W);free_token();return 0;
}
느낀점느낀점느낀점느낀점7.7.7.7.
초안에서의 문제점은 아래와 같다.단어별 라인이 나오지 않음 개선.-> X
를 이용하여라인출력을 하고자 하였으나 실패함:fscanf , , .
단어의 대소문자 구별해서 나옴 개선.-> X을 이용하여 단어를 구분해주었는데 여기서 대소문자 구별하는 방법을 찾아내지 못함strtok , , .
단어의 총 개수가 출력되지 않음 개선.-> O