this refers to 윤성우의 열혈 자료구조.

tree is data structure of Hierarchical Relationship(계층적 관계).

1-1. basic concept of tree

- node(노드) : part of tree(트리의 구성요소), for example A, B, C, D, E, F node.
- edge(간선) : this connect each other node.(서로 다른 노드를 연결하는 선) 
- root node(루트노드) : top node of tree(트리의 최상위 노드). for example A node
- terminal node(단말 노드): this don't connect another node. for example E, F, C, D node (아래로 다른 노드가 연결 안되어 있다. )
- iternal node(내부 노드) : all node except for terminal node,(단말 노드를 제외한 모든 노드) for example A, B node

1-2. relationship of tree node

1-3. subtree

- tree is recursive.(트리는 재귀적이다) 그래서 재귀 함수를 많이 이용할 수 있다.

1-4. binary tree

- a node has two children.(하나의 노드는 두개의 자식을 가진다)
- root has two subtree. (루트는 두개의 서브트리를 가지고)
- also, the divied subtree is binary tree.(나누어진 서브트리도 이진트리이다.)
- 트리 및 이진 트리는 구조가 재귀적이다. 즉, 트리와 관련해서는 재귀적 사고와 재귀적을 구현하면 좋다. 

1-5. binary tree & null node

1-6. height & level of tree

- full binary tree is that node is full in tree.(포화 이진 트리는 모든 레벨에 노드가 꽉 차있다.)
- complete binary tree is from the up to the down & from the right to the left.
- 완전 이진 트리는 나중에 힙에 사용이 되는 트리이기도 하다. 
- 노드가 채워지는 순서가 있다 위에서 아래로 그리고 오른쪽에서 왼족으로 노드가 채워진다.

1-7. implementation of tree

- 트리는 배열 or 리스트 기반으로 구현을 한다. 

1-8. now source code using LinkedList.

- tree node's structure
- 트리의 모든 노는 직접 간접적으로 연결이 되어 있어 root 주소 값만 알아도 이진 트리 전체를 알 수 있다.
- 하나의 노드는 논리적으로는 이진트리이다. 즉 노드는 이진트리이다. 

// 이진 트리의 노드 모양
typedef struct _bTreeNode
{
    BTData data;
    struct _bTreeNode * left;
    struct _bTreeNode * right;
} BTreeNode;
- 함수를 통해 접근을 하자. 노드에 직접 접근 보다는 

- tree function 

- 위의 함수를 이용한 메인 함수 부분
int main(void)
{
    BTreeNode * ndA = MakeBTreeNode(); // 노드 A 생성
    BTreeNode * ndB = MakeBTreeNode(); // 노드 B 생성
    BTreeNode * ndC = MakeBTreeNode(); // 노드 C 생성
    
    위의 노드를 SetData 통해 데이터를 채운다. 
    
    // A노드에 왼쪽 자식으로 B 노드 연결
    MakeLeftSubTree(ndA, ndB);
    
    
    // A노드에 오른쪽 자식으로  C 노드 연결
    MakeRightSubTree(ndA, ndC);
}

// 앞에 만든 함수를 이용해서 트리를 구현하고 있다. 

// 자 이제 본격적인 이진 트리의 ADT들을 만들어 보자 
BTreeNode * MakeBTreenNode(void)
{
        BTreeNode * nd = (BTreeNode * )malloc(sizeof(BTreeNode));
        nd -> left = NULL;
        nd -> right = NULL;
        return nd;
}

BTData GetData (BTreeNode * bt)
{
        return bt -> data;
}

void SetData(BTreeNode * bt, BTData data)
{
    bt -> data = data;
}

BTreeNode * GetLeftSubTree(BTreeNode *  bt)
{
    return bt -> left;
}

BTreeNode * GetRightSubTree(BTreeNode *  bt)
{
    return bt -> right;
}

void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub)
{
    if(main -> left != NULL)
        free(main -> left);    /// 하지만 이거 서브트리가 자식을 가지고 있는경우
                            ///  memory leak이 발생한다. 
                            
    main -> lenf = sub;
}


void MakeRightSubTree(BTreeNode * main, BTreeNode * sub)
{
    if(main -> right != NULL)
        free(main -> right);    /// 하지만 이거 서브트리가 자식을 가지고 있는경우
                            ///  memory leak이 발생한다. 
                            
    main -> right = sub;
}

/// 위의 두개의 함수에서 메모리 누수가 나면 효과적인 방법이 있다 .
// 바로 트리의 traversal를 이용하면 메모리의 누수가 없을 것이다. 


// 위의  ADT를 이용해서 main function를 이용해보자 
int main(void)
{
    BTreeNode * bt1 = MakeBTreeNode(); // 노드 bt1 생성
    BTreeNode * bt2 = MakeBTreeNode(); // 노드 bt2 생성
    BTreeNode * bt3 = MakeBTreeNode(); // 노드 bt3 생성
    BTreeNode * bt4 = MakeBTreeNode(); // 노드 bt4 생성
    
    //위의 노드를 SetData를 통해 데이터를 채운다. 
    SetData(bt1, 1);   //bt1에 1 저장
    SetData(bt2, 2);   //bt2에 2 저장
    SetData(bt3, 3);   //bt3에 3 저장
    SetData(bt4, 4);   //bt4에 4저장
        

    MakeLeftSubTree(bt1, bt2);     // bt2를 bt1의 왼쪽 자식 노드로 만든다. 
    MakeRightSubTree(bt1, bt3);    // bt3를 bt1의 오른쪽 자식 노드로 만든다. 
    MakeLeftSubTree(bt2, bt4);     // bt4를 bt2의 왼쪽 자식 노드로 만든다. 
    
    // bt1의 왼쪽 자식 노드의 데이터 출력
    printf("%d\n", GetData(GetLeftSubTree(bt1)));
    
    // bt1의 왼쪽 자식 노드의 왼쪽 자식 노드의 데이터 출력
    printf("%d\n", GetData(GetLeftSubTree(GetLeftSebTree(bt1))));
    
    return 0;
}


// 출력결과
// 2
// 4

1-9. binary tree traversal

- 세가지 순회방법 : 루트 노드의 방문 순서에 따라, 
- 자식노드 탐색순서는 왼쪽노드 다음 오른쪽 노드이고 O left O right O 여기서 O에 루트노드가 들어간다.
- 중위(inorder), 후위(postorder), 전위(preorder)

1-10. recursive traversal

- 위의 함수에 기저 조건을 추가

- 아래는 각각의 전위, 후위, 중위 순회를 보여준다. 

  • 위와 같이 노드를 방문을 하면서 우리는 다양한 작업을 트리에서 할 수 있다.
typedef void VisitFuncPtr(BTData data); // 이런 방식으로 커널에 사용 
// typedef void (*VisitFuncPtr) (BTData data);
// 위는 함수 포인터의 데이터 타입 설정 

void InOrderTraverse(BTtreeNode * bt, VisitFuncPtr action)
{
        if(bt == NULL)
            return ;
    
    InOrderTraverse(bt -> left, action);
    action(bt -> data);
    InOrderTraverse(bt -> right, action);
}

void ShowIntData(int data)
{
    printf("%d ", data);
}

// 위와 같은 방식을 활용하여 좀더 트리를 다양하게 이용을 할 수가 있다.