Skip to content
Home » 이진 트리 구현 | 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] 145 개의 베스트 답변

이진 트리 구현 | 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] 145 개의 베스트 답변

당신은 주제를 찾고 있습니까 “이진 트리 구현 – 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]“? 다음 카테고리의 웹사이트 kk.taphoamini.com 에서 귀하의 모든 질문에 답변해 드립니다: kk.taphoamini.com/wiki. 바로 아래에서 답을 찾을 수 있습니다. 작성자 동빈나 이(가) 작성한 기사에는 조회수 28,864회 및 좋아요 200개 개의 좋아요가 있습니다.

Table of Contents

이진 트리 구현 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] – 이진 트리 구현 주제에 대한 세부정보를 참조하세요

20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] 강의 동영상입니다. 이번 시간에는 이진 트리의 개념에 대해 이해하고 실제로 C언어의 포인터를 이용해 구현한 뒤에 그결과를 확인합니다.

이진 트리 구현 주제에 대한 자세한 내용은 여기를 참조하세요.

자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal)

트리는 배열이나 연결리스트로 구현하는 것이 보편적이다. 배열로 트리를 구현할 때는 노드 넘버링을 할 때 통상 인덱스 1부터 시작함에 유념한다. – Full Binary Tree : …

+ 자세한 내용은 여기를 클릭하십시오

Source: chanhuiseok.github.io

Date Published: 9/10/2021

View: 1621

[자료구조] 이진 트리(Binary Tree) 개념과 구현 – LEEJINSEOP

1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다.

+ 더 읽기

Source: leejinseop.tistory.com

Date Published: 3/19/2021

View: 7086

[C] 이진 트리 구현 코드

이진 트리 노드 구현. 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능 …

+ 여기에 자세히 보기

Source: eunjinii.tistory.com

Date Published: 12/11/2022

View: 7543

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree … – 하루 2시간

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree). by IYK2h 2021. 3. 5. 320×100. 코드 …

+ 여기에 자세히 보기

Source: iyk2h.tistory.com

Date Published: 6/26/2021

View: 9524

python으로 이진트리 구현하기 – 브런치

알고리즘 끝장내기 | 이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다.

+ 여기를 클릭

Source: brunch.co.kr

Date Published: 9/14/2021

View: 8010

[자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해

이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다. 재귀가 아닌 for문을 통해서도 구현이 가능하지만 직관적으로 이해가 쉽게 재귀로 …

+ 여기에 자세히 보기

Source: code-lab1.tistory.com

Date Published: 3/15/2022

View: 5920

[C언어] 포인터를 이용한 이진 트리(Binary Tree) 구현 & 순회

포인터로 이진 트리 구현하고 순회하기. … 각 레벨에 노드가 꽉 찬 이진 트리; 각 레벨 단위로 왼쪽에서 오른쪽으로 번호를 붙일 수 있으며, …

+ 여기를 클릭

Source: velog.io

Date Published: 3/17/2021

View: 201

Top 40 이진 트리 구현 The 81 New Answer

Summary of article content: Articles about [자료구조] 이진 트리(Binary Tree) 개념과 구현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 …

+ 여기를 클릭

Source: toplist.future-user.com

Date Published: 10/3/2022

View: 9531

이진 트리 구현 | 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 …

자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal). 트리는 배열이나 연결리스트로 구현하는 것이 보편적이다. 배열로 트리를 구현할 …

+ 여기에 보기

Source: ppa.dianhac.com.vn

Date Published: 5/1/2022

View: 5211

스위프트로 구현하는 자료구조 7: 트리와 이진 트리(Binary Tree)

서브트리를 구성하는 루트 노드는 자신의 왼쪽과 오른쪽 자식노드가 모두 방문 된 이후에 방문됩니다. 완전 이진 트리 구현하기. 이전에 힙을 구현하면서 …

+ 여기에 보기

Source: jeonyeohun.tistory.com

Date Published: 1/4/2021

View: 276

주제와 관련된 이미지 이진 트리 구현

주제와 관련된 더 많은 사진을 참조하십시오 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

20강 - 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]
20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]

주제에 대한 기사 평가 이진 트리 구현

  • Author: 동빈나
  • Views: 조회수 28,864회
  • Likes: 좋아요 200개
  • Date Published: 2018. 4. 20.
  • Video Url link: https://www.youtube.com/watch?v=z_tzHoPfllA

자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal)

© 2019-2022 ChanhuiSeok . Powered by Jekyll , theme by Chirpy .

The blog posts on this site are licensed under the Creative Commons Attribution 4.0 International License.

[자료구조] 이진 트리(Binary Tree) 개념과 구현

1. 트리

트리(Tree)란 비선형 자료구조 중에서 자료들 간에 계층관계를 가진 계층형 자료구조(Hierarchical Data Structure)를 말합니다.

트리

· 노드(Node): 트리를 구성하는 원소(자료)

· 간선(Edge): 노드를 연결하는 선

· 차수(Dgree): 자식 노드의 수

· 높이(Height): 루트에서 해당 노드에 이르는 경로에 있는 간선의 수

· 루트 노드(Root Node): 트리의 시작 노드

· 형제 노드(Sibling Node): 같은 부모 노드의 자식노드들

· 조상 노드(Ancestor Node): 한 노드에서 간선을 따라 루트 노드까지 이르는 경로에 있는 노드들

· 자손 노드(Descendant Node): 한 노드의 서브 트리에 있는 노드들

· 단말 또는 리프 노드(Leaf Node): 자식이 없는 노드

2. 이진 트리

이진 트리(Binary Tree)란 모든 노드의 차수를 2 이하로 정하여 전체 트리의 차수가 2 이하가 되도록 만든 트리입니다.

이진 트리

· 이진 트리는 왼쪽 자식 노드와 오른쪽 자식 노드 2개만을 가질 수 있으며, 공백 노드도 이진 트리의 노드로 취급합니다.

· 이진 트리에 있는 모든 노드는 왼쪽 자식 노드를 루트로 하는 왼쪽 서브 트리와 오른쪽 자식 노드를 루트로 하는 오른쪽 서브 트리를 가집니다. 그리고 이진 트리의 서브 트리들 모두 이진 트리여야 합니다.

3. 이진 트리의 특징

① n개의 노드를 가진 이진 트리는 항상 (n-1)개의 간선을 갖습니다.

루트 노드 이외의 모든 노드는 한 개의 부모 노드를 가지고 있기 때문에 부모 노드와 연결하는 한 개의 간선을 갖습니다. 따라서 n개의 노드로 구성된 이진 트리에서 루트 노드를 제외한 나머지 노드의 개수가 (n-1)개이므로 (n-1)개의 간선을 갖습니다.

② 높이가 h인 이진 트리가 가질 수 있는 노드의 최소 개수는 (h+1)개, 최대 개수는 (2^(h+1) -1)개입니다.

이진 트리의 높이가 h가 되려면 한 레벨에 최소한 한 개의 노드가 있어야 하므로 높이가 h인 이진 트리의 최소 노드의 개수는 (h+1)개가 됩니다.

하나의 노드는 최대 2개의 자식 노드를 가질 수 있기 때문에 레벨 i에서 노드의 최대 개수는 2^i가 됩니다. 따라서 높이가 h인 이진 트리에서 최대 노드의 개수는 (2^(h+1) -1)개가 됩니다.

4. 이진 트리의 종류

① 포화 이진 트리

모든 레벨에 노드가 꽉 차있는 포화 상태의 이진 트리입니다. 즉 이진 트리의 높이가 h일 때 (2^(h+1) -1)개의 노드를 갖는 이진 트리를 말합니다.

포화 이진 트리

② 완전 이진 트리

높이가 h, 노드의 개수가 n개일 때(단, n < 2^(h+1) -1), 노드의 위치가 포화 이진 트리의 노드 1번 부터 n번까지의 위치와 완전히 일치하는 이진 트리입니다. 따라서 (n+1)번 부터 (2^(h+1) -1)번까지는 공백 노드가 됩니다. 완전 이진 트리 ③ 편향 이진 트리 이진 트리 중에서 최소 개수의 노드를 가지면서 왼쪽이나 오른쪽 서브 트리만 가지고 있는 트리입니다. 즉 이진 트리의 높이가 h일 때 (h+1)개의 노드를 가지면서 한 쪽으로 치우친 이진 트리를 말합니다. 왼쪽 편향 이진 트리와 오른쪽 편향 이진 트리 5. 이진 트리의 구현 · 순차 자료구조 방식 1차원 배열에서 인덱스 계산을 간단히 하기 위해서 인덱스 0번은 사용하지 않고 비워두고, 인덱스 1번에 루트를 저장합니다. 완전 이진 트리의 배열 표현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다. 노드 인덱스 조건 노드 i의 부모 노드 i / 2 i > 1 노드 i의 왼쪽 자식 노드 i * 2 (i * 2) <= n 노드 i의 오른쪽 자식 노드 (i * 2) + 1 (i * 2) + 1 <= n · 연결 자료구조 방식 배열을 이용한 이진 트리의 구현은 인덱스 규칙에 따라 부모 노드와 자식 노드를 찾기 쉽다는 장점이 있습니다. 하지만 메모리 공간의 사용에 있어 완전 이진 트리의 경우에는 최적의 공간 사용이 되지만, 편향 이진 트리의 경우 많은 공간이 낭비됩니다. 따라서 메모리 낭비 문제와 삽입 · 삭제 연산이 비효율적인 순차 자료구조 방식 보다는 연결 자료구조 방식을 많이 사용합니다. 이진 트리의 노드는 왼쪽 자식 노드와 오른쪽 자식 노드를 연결해야 하므로 데이터를 저장하는 데이터 필드, 왼쪽 자식 노드를 연결하는 왼쪽 링크 필드와 오른쪽 자식 노드를 연결하는 오른쪽 링크 필드로 구성된 참조 변수를 사용해야 합니다. public class TreeNode { private Object data; TreeNode left; TreeNode right; public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } 6. 이진 트리의 순회 이진 트리에 있는 모든 노드를 한번씩 모두 방문하여 노드가 가지고 있는 데이터를 처리하는 것을 순회라고 합니다. 선형 자료구조는 순회하는 방법이 한 가지였지만, 트리는 계층적인 구조를 가지고 있기 때문에 여러 가지 순회 방법이 있습니다. 하나의 노드에서 순회를 위해 수행할 수 있는 작업은 (1) 현재 노드를 방문하여 데이터를 읽는 작업, (2) 현재 노드의 왼쪽 서브 트리로 이동하는 작업, (3) 현재 노드의 오른쪽 서브 트리로 이동하는 작업이 있습니다. 그리고 서브 트리를 순회하는 순서는 항상 왼쪽 서브 트리를 먼저 방문하고, 그 후에 오른쪽 서브 트리를 방문하는 것으로 합니다. 따라서 현재 노드를 방문하는 순서에 따라 전위 순회, 중위 순회, 후위 순회로 나눌 수 있습니다. · 전위 순회(Preorder Traversal) 현재 노드를 방문 → 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 preorder(T) if(T != null) then{ visit T.data; preorder(T.left); preorder(T.right); } end preorder() · 중위 순회(Inorder Traversal) 왼쪽 서브 트리 방문 → 현재 노드를 방문 → 오른쪽 서브 트리 방문 inorder(T) if(T != null) then { inorder(T.left); visit T.data; inorder(T.right); } end inorder() · 후위 순회(Postorder Traversal) 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 → 현재 노드를 방문 postorder(T) if(T != null) then { postorder(T.left); postorder(T.right); visit T.data; } end postorder(T) 7. 이진 트리 소스 코드 · TreeNode public class TreeNode { private Object data; // 데이터 필드 TreeNode left; // 왼쪽 링크 필드 TreeNode right; // 오른쪽 링크 필드 public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } · LinkedTree public class LinkedTree { // 이진 트리 노드 생성 public TreeNode makeBT(TreeNode left, Object data, TreeNode right) { TreeNode newNode = new TreeNode(data); newNode.left = left; newNode.right = right; return newNode; } // 전위 순회 public void preorder(TreeNode node) { if (node != null) { System.out.printf("%c", node.getData()); preorder(node.left); preorder(node.right); } } // 중위 순회 public void inorder(TreeNode node) { if (node != null) { inorder(node.left); System.out.printf("%c", node.getData()); inorder(node.right); } } // 후위 순회 public void postorder(TreeNode node) { if (node != null) { postorder(node.left); postorder(node.right); System.out.printf("%c", node.getData()); } } } · MainForLinkedTree public class MainForLinkedTree { public static void main(String[] args) { LinkedTree t = new LinkedTree(); TreeNode n7 = t.makeBT(null, 'D', null); TreeNode n6 = t.makeBT(null, 'C', null); TreeNode n5 = t.makeBT(null, 'B', null); TreeNode n4 = t.makeBT(null, 'A', null); TreeNode n3 = t.makeBT(n6, '-', n7); TreeNode n2 = t.makeBT(n4, '+', n5); TreeNode n1 = t.makeBT(n2, '*', n3); // 전위 순회 System.out.printf("preorder: "); t.preorder(n1); // 중위 순회 System.out.printf(" inorder: "); t.inorder(n1); // 후위 순회 System.out.printf(" postorder: "); t.postorder(n1); } } · 실행 결과

[C] 이진 트리 구현 코드

728×90

1. 이진 트리 노드 구현

이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능하다.

노드 구조체는 다음과 같다.

#include #include typedef struct Node { int data; struct Node *leftChild; struct Node *rightChild; } Node;

하나의 노드는 내부적으로 하나의 data를 가지고 있다. 여기 예시 코드에서는 정수형 데이터 하나만 들어가는 걸로 설정했지만, 실제로는 다양한 데이터가 data에 들어갈 수 있다.

특정 노드를 초기화하는 함수는 다음과 같다.

Node* initNode(int data, Node* leftChild, Node* rightChild) { Node* node = (Node*) malloc(sizeof(Node)); node -> data = data; node -> leftChild = leftChild; node -> rightChild = rightChild; return node; }

이진트리 같은 경우에는 함수의 반환형에서 특정 노드의 포인터가 들어가는 경우가 많다. data, leftNode, rightNode 모두 초기화시켜준 다음, 그 노드의 포인터를 반환해 준다.

2. 이진 트리의 순회 알고리즘

이진 트리는 자료구조이기 때문에 컴퓨터의 메모리상에 올라가 있어 사람이 이진트리에 담긴 데이터를 시각화하기란 어렵다. 따라서 이진트리에 담긴 데이터를 조회해서 출력하는 방법으로는 주로 순회 기법을 사용한다. 크게 세 가지 순회 방법이 있다.

(1) 전위 순회

– 자기 자신을 출력한다 -> 왼쪽 자식을 방문한다. -> 오른쪽 자식을 방문한다.

전위 순회 같은 경우에는 먼저 루트에서 시작하면 자기 자신을 출력하고, 그 다음에 왼쪽 자식노드로 들어가서 데이터를 출력하고, 다시 그 노드의 왼쪽 자식노드로 들어가서 데이터를 출력한다. 마지막에 다다르면 부모 노드로 거슬러 올라갔다가, 부모 노드의 오른쪽 자식 노드로 가서 데이터를 출력한다.

전위 순위법

void preorder(Node* root) { if (root) { printf(“%d “, root -> data); preorder(root -> leftChild); preorder(root -> rightChild); } }

특정한 노드가 주어졌을 때, 그 노드가 null값이 아니라면 재귀적으로 다음 노드를 탐색한다. 먼저 자기 자신을 출력한 후에 왼쪽으로 들어가고, 마지막에 왼쪽 노드가 null이면 이제 오른쪽 노드로 들어가는 것이다.

(2) 중위 순회

– 왼쪽 자식 출력 -> 그 다음 자기 자신 출력 -> 오른쪽 자식 출력

맨 위 노드에서 계속 왼쪽 자식 노드로 내려간 다음, 1을 출력한다. 그 다음 2, 3을 출력한다. 돌아와서 4를 출력하고 같은 과정을 반복한다. 항상 왼쪽으로 쭉 내려갔다가 자신으로 돌아온 후 오른쪽으로 간다. 결과적으로 왼쪽에서부터 오른쪽으로 차례로 출력된다.

중위 순위법

void inorder(Node* root) { if (root) { inorder(root -> leftChild); printf(“%d “, root -> data); inorder(root -> rightChild); } }

전위순위랑 비슷하고 코드의 순서만 바꿔주면 된다. 왼쪽 노드를 먼저 방문 후, 자기 자신을 출력하고 오른쪽을 방문한다.

(3) 후위 순위

– 왼쪽 자식 방문 -> 오른쪽 자식 방문 -> 자기 자신 출력

먼저 왼쪽 최하단 노드 1을 방문한 다음, 그 형제 노드 2를 방문한 후 부모 노드 3을 출력한다. 그리고 루트의 오른쪽 4, 5, 6 노드들에 대해서도 같은 연산을 반복한 다음 루트로 돌아와서 출력한다. 이 알고리즘은 루트가 가장 마지막에 출력된다는 특징이 있다.

후위 순위법

void postorder(Node* root) { if (root) { postorder(root -> leftChild); postorder(root -> rightChild); printf(“%d “, root -> data); } }

마찬가지로 코드의 순서만 바꿔주면 된다. 왼쪽 노드를 먼저 방문 후, 오른쪽을 방문한 다음 자기 자신을 출력한다.

3. 순회 알고리즘 코드로 표현해보기

int main(void) { Node* n7 = initNode(50, NULL, NULL); Node* n6 = initNode(37, NULL, NULL); Node* n5 = initNode(23, NULL, NULL); Node* n4 = initNode(5, NULL, NULL); Node* n3 = initNode(48, n6, n7); Node* n2 = initNode(17, n4, n5); Node* n1 = initNode(30, n2, n3); preorder(n1); printf(”

“); inorder(n1); printf(”

“); postorder(n1); printf(”

“); }

루트 노드를 n1이라고 하고 그 자식을 각각 n2, n3라 한다. 또 각 자식도 자식노드를 가진다. 이 하위 자식노드는 더 이상 자식 노드를 갖지 않기 때문에 왼쪽 노드, 오른쪽 노드 부분에 NULL을 넣어 준다. 차례대로 전위, 중위, 후위순회를 실행해 보면 다음과 같이 출력된다.

30 17 5 23 48 37 50 5 17 23 30 37 48 50 5 23 17 37 50 48 30

728×90

반응형

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree)

728×90

코드

//binary search tree #include #include typedef struct node { int data; struct node* left; struct node* right; }node; node* root; node* insert(node* root,int data) { if(root == NULL) { root = (node*)malloc(sizeof(node)); root->right = root->left = NULL; root->data = data; return root; } else { if(data < root->data) root->left = insert(root->left,data); else root->right = insert(root->right,data); } return root; } node* fMin(node* root) { node* min = root; while(min->left!=NULL) min = min->left; return min; } node* delete(node* root,int data) { node *tmproot = NULL; if(root==NULL) return NULL; if(data < root->data) root->left = delete(root->left,data); else if(data > root->data) root->right = delete(root->right,data); else { if(root -> left!=NULL && root->right != NULL) { tmproot = fMin(root->right); root->data = tmproot->data; root->right = delete(root->right,tmproot->data); } else { tmproot = (root->left == NULL) ? root->right : root->left; free(root); return tmproot; } } return root; } void print(node* root) { if(root==NULL) return; printf(“%d “,root->data); print(root->left); print(root->right); } //전위 순회 void preorderPrint(node* root) { if(root==NULL) return; printf(“%d “,root->data); print(root->left); print(root->right); } //중위 순회 void inorderPrint(node* root) { if(root==NULL) return; print(root->left); printf(“%d “,root->data); print(root->right); } //후위 순회 void postorderPrint(node* root) { if(root==NULL) return; print(root->left); print(root->right); printf(“%d “,root->data); } int main() { root = insert(root,5); root = insert(root,1); root = insert(root,9); printf(“preorder : “); preorderPrint(root); printf(”

“); printf(“inorder : “); inorderPrint(root); printf(”

“); printf(“postorder : “); postorderPrint(root); printf(”

“); printf(“preorder : “); preorderPrint(root); printf(”

“); printf(“delete : 9

“); root = delete(root,9); preorderPrint(root); printf(”

“); root = insert(root,9); printf(“delete : 1

“); root = delete(root,1); preorderPrint(root); printf(”

“); root = insert(root,1); printf(“delete : 5

“); root = delete(root,5); preorderPrint(root); printf(”

“); }

이진트리를 구현하기 위한 이진트리의 조건들

한 부모 노드에 자식 노드는 최소 0부터 최대 2개의 자식 노드를 가질 수 있다.

부모보다 작으면 왼쪽 자식 부모보다 크면 오른쪽 자식으로 보내야 한다.

이진트리를 순회하는 방식은 4가지가 있다. 1. 전위 순회 2. 중위 순회 3. 후위 순회 4. 레벨 순회

c언어 – 이진 트리 레벨 순회 (LevelTraverse)

프로그래밍하면서 배운 부분

구조체를 리턴하기 위해 구조체 반환형으로 함수를 선언해야 한다.

재귀 함수는 함수의 패턴이 있으면 패턴을 단순화시키는 게 중요하다.

단순하고 반복되는 패턴을 찾아 그 패턴을 재귀화로 만드는 게 이번 프로그래밍하면서 느낀 점이다.

이제부터 다른 간단한 함수를 코딩할 때 패턴을 찾으면 재귀 함수로 프로그래밍하려고 시도해볼 것 같다.

재귀 함수가 처리해야 하는 수가 일정 수준을 넘어가면 너무 느려지기 때문에 적당한 수준을 처리한다면 재귀 함수는 매력적인 함수이다.

트리에 재귀 함수가 잘 맞는 이유도 재귀 함수가 쓰이는 이유와 비슷하다.

일정 수준을 넘어가기 전에는 트리는 합리적인 자료구조이나, 일정 수준을 넘어가면 트리를 나눠서 만드는 게 더 좋다.

이렇게 보면 재귀와 트리는 비슷한 부분이 많은 거 같다.

728×90

python으로 이진트리 구현하기

이진트리란

트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다. 맨 꼭 대기에 있는 1번 노드는 루트(Root)라고 한다. 루트 노드의 깊이를 1로 하고 한 단계 내려가면 깊이가 1만큼 증가한다.

트리의 종류

트리 1과 트리 2는 노드와 에지를 가지고 있는 트리다. 1번부터 9번 노드를 가지고 있다. 둘 다 1번 노드가 루트이고 깊이는 4이다. 2번 노드를 보면 두 트리의 차이점을 알 수 있다. 트리 1의 2번 노드는 자식 노드가 3개이지만 트리 2는 2번 노드의 자식 노드는 2개이다.

트리 2처럼 모든 노드가 최대 두 개의 자식을 갖는 트리를 이진트리라고 한다. 이진트리는 깊이 h에 최대 2^{h-1}만큼 노드를 가질 수 있다.

자 이제, 다음과 같은 이진트리를 python으로 생성해보자.

이진트리 만들기

Node는 자기 자신의 값인 item과 자식의 위치인 left와 right를 가진다.

class Node:

def __init__(self, item):

self.item = item

self.left = None

self.right = None

각 노드를 생성한다.

n1 = Node(10)

n2 = Node(20)

n3 = Node(30)

n4 = Node(40)

n5 = Node(50)

n6 = Node(60)

n7 = Node(70)

n8 = Node(80)

각 노드를 엮어주기 위하여 BinaryTree를 만든다.

class BinaryTree():

def __init__(self): #트리 생성

self.root = None

순서에 맞게 노드를 엮는다.

tree = BinaryTree()

tree.root = n1

n1.left = n2

n1.right = n3

n2.left = n4

n2.right = n5

n3.left = n6

n3.right = n7

n4.left = n8

트리 순회란

트리 순회란 트리의 노드를 지정한 순서대로 방문하는 것을 말한다. 이진트리를 순회하는 방법은 대표적으로 3개이다. 여기에 1가지를 더해 총 4가지를 python으로 구현해보자.

전위 순회 (Preorder)

후위 순회 (Postorder)

중위 순회 (Inorder)

레벨 순회 (Levelorder)

트리를 읽을 때에 대전제는 왼쪽부터 오른쪽으로 읽는다는 것이다. 오른쪽에서부터 왼쪽으로는 읽지 않는다. “방문”은 자신의 번호를 출력하는 print() 함수로 표현한다. 이 출력 함수의 위치에 따라서 트리를 순회하는 방법을 구분하는 것이다.

트리 순회

전위 순회 ( Pre order)

자기 자신을 먼저 출력하고 자식 노드를 호출한다. 순서는 다음과 같다.

자기 자신 출력

왼쪽 서브 트리 호출

오른쪽 서브 트리 호출

그렇다면 출력은 어떤 순서로 될까?

우선 맨 위 루트부터 방문하므로 자기 자신인 10을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다.

왼쪽에 있는 20번 노드를 방문했으므로 20을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다.

왼쪽에 있는 40번 노드를 방문했으므로 40을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다.

왼쪽에 있는 80번 노드를 방문했으므로 80을 출력한다. 80번 노드는 자식 노드가 없으므로 더 호출하지 않는다.

40번 노드로 올라간다. 40번 노드의 오른쪽 노드가 없으므로 더 호출하지 않는다.

20번 노드로 올라간다. 20번 노드의 오른쪽 노드인 50번 노드를 방문한다. 50번 노드 출력. 50번 노드가 자식 노드가 없으므로 호출 끝.

20번 노드로 올라간다. 호출할 자식 노드 없으므로 10번 노드로 올라간다.

오른쪽의 30번 노드를 방문한다. 30을 출력한다. 왼쪽 노드인 60번 노드 방문. 60을 호출. 자식 노드 없으므로 호출 끝.

30번 노드로 올라간다. 오른쪽 노드인 70번 노드를 방문한다. 70을 출력한다. 자식 노드 없으므로 호출 끝.

정답 : 10 20 40 80 50 30 60 70

# 전위 순회

def preorder(self, n):

if n != None:

print(n.item, ”, end=”) # 노드 방문

if n.left:

self.preorder(n.left) # 왼쪽 서브 트리 순회

if n.right:

self.preorder(n.right) # 오른쪽 서브 트리 순회

후위 순회 (Postorder)

자기 자신 출력을 가장 나중에 한다.

왼쪽 서브 트리 호출

오른쪽 서브 트리 호출

자기 자신 출력

# 후위 순회

def postorder(self, n):

if n != None:

if n.left:

self.postorder(n.left)

if n.right:

self.postorder(n.right)

print(n.item, ”, end=”) # 노드 방문

호출을 먼저 하고 끝이 보이면 자기 자신을 출력하므로 가장 왼쪽 노드인 80부터 출력된다.

정답 : 80 40 50 20 60 70 30 10

중위 순회 (Inorder)

자기 자신 출력이 중간에 있다.

왼쪽 서브 트리 호출

자기 자신 출력

오른쪽 서브 트리 호출

# 중위 순회

def inorder(self, n):

if n != None:

if n.left:

self.inorder(n.left)

print(n.item, ”, end=”) # 노드 방문

if n.right:

self.inorder(n.right)

정답 : 80 40 20 50 10 60 30 70

레벨 순회 (Levelorder)

레벨 순회는 깊이(레벨) 단위로 출력하는 것이다. 그 순서는 깊이가 낮은 순서이다. 우리가 흔히 생각하는 10 20 30 40 50 60 70 80 순으로 출력하고 싶다면 어떻게 해야 할까? 호출될 때마다 자식 노드를 따로 저장하는 것이다. 선입선출 구조인 큐로 구현한다.

# 레벨 순회

def levelorder(self, n):

q = []

q.append(n)

while q:

t = q.pop(0)

print(t.item, ”, end=”)

if t.left != None:

q.append(t.left)

if t.right != None:

q.append(t.right)

정답 : 10 20 30 40 50 60 70 80

전체 코드

전체 코드는 블로그를 참조하라. 이제 이진 트리라는 자료구조를 구현하는 방법을 알았다. 다음에는 이 구조를 활용하여 결정 트리(Decision Tree)를 만들어 보자.

qqplot의 기술 블로그

https://qqplot.github.io/

[자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해

이진탐색트리(Binary Search Tree)이란?

이진탐색트리란 다음과 같은 특징을 갖는 이진트리를 말한다. ( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리)

1. 각 노드에 중복되지 않는 키(key)가 있다.

2. 루트노드의 왼쪽 서브 트리는 해당 노드의 키보다 작은 키를 갖는 노드들로 이루어져 있다.

3. 루트노드의 오른쪽 서브 트리는 해당 노드의 키보다 큰 키를 갖는 노드들로 이루어져 있다.

4. 좌우 서브 트리도 모두 이진 탐색 트리여야 한다.

예를 들어 다음과 같은 트리가 이진탐색트리이다.

이진탐색트리

이진 탐색 트리의 특징

이진 탐색 트리는 기존 이진트리보다 탐색이 빠르다. 이진 탐색 트리의 탐색 연산은 트리의 높이(height)가 h라면 O(h)의 시간 복잡도를 갖는다. 이러한 효율적인 탐색이 가능한 이유는 탐색 과정에서 자세히 알아보자. 혹시라도 트리에 관한 용어가 헷갈린다면 다음 포스팅을 참고하자.

이진 탐색 트리 탐색(Search)

이진 탐색 트리의 탐색은 다음과 같은 과정을 거친다.

1. 루트 노드의 키와 찾고자 하는 값을 비교한다. 찾고자 하는 값이라면 탐색을 종료한다.

2. 찾고자 하는 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리로 탐색을 진행한다.

3. 찾고자 하는 값이 루트노드의 키보다 크다면 오른쪽 서브트리로 탐색을 진행한다.

위 과정을 찾고자 하는 값을 찾을 때까지 반복해서 진행한다. 만약 값을 찾지 못한다면 그대로 종료한다.

이러한 탐색 과정을 거치면 최대 트리의 높이(h)만큼의 탐색이 진행되게 된다. 예를 들어보자.

탐색과정

위와 같은 트리에서 키가 5인 노드를 찾고자 한다면, 가장 먼저 루트 노드와의 비교가 이루어진다.

5가 7보다 작으므로 왼쪽 서브 트리로의 탐색이 이루어지고, 이후 5가 3보다 크므로 오른쪽 서브트리로 탐색이 이루어진다. 마지막으로 키가 5인 노드를 찾았으므로 탐색이 종료된다. 즉 트리의 높이인 3번 만큼의 탐색이 이루어졌다. 만약 8을 찾는다면 2번의 연산이 진행되었을 것이다. 즉, 트리 안의 값을 찾는다면 무조건 트리의 높이(h) 이하의 탐색이 이루어지게 된다.

트리 안에 찾고자 하는 값이 없더라도 최대 h 번 만큼만의 탐색이 진행된다. 예를 들어 위 트리에서 6이라는 값을 찾는다고 하면 위 그림과 같은 과정을 거치고 탐색이 종료된다. (직접 위 그림에서 과정을 생각해보자) 마지막으로 탐색하게 되는 5를 키로 갖는 노드에서 6은 5보다 크므로 오른쪽 서브트리로 탐색을 진행해야 하는데 오른쪽 서브 트리가 없으므로 탐색이 종료되는 것이다.

이진 탐색 트리 탐색 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TreeNode * search(TreeNode * root, int key){ if (root = = NULL ){ // 값을 찾지 못한 경우 return NULL ; } if (key = = root – > key){ // 값을 찾음 return root; } else if (key < root - > key){ // 왼쪽 서브트리 탐색 search(root – > left, key); } else if (key > root – > key){ // 오른쪽 서브트리 탐색 search(root – > right, key); } } Colored by Color Scripter cs

이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다. 재귀가 아닌 for문을 통해서도 구현이 가능하지만 직관적으로 이해가 쉽게 재귀로 구현하였다. 이진 탐색 트리 삽입(insert) 이진 탐색트리의 삽입은 다음과 같은 과정을 거친다. 탐색과 과정이 비슷하다.

1. 삽입할 값을 루트 노드와 비교해 같다면 오류를 발생한다( 중복 값 허용 X )

2. 삽입할 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리를 탐색해서 비어있다면 추가하고, 비어있지 않다면 다시 값을 비교한다.

3. 삽입할 값이 루트노드의 키보다 크다면 오른쪽 서브트리를 탐색해서 비어있다면 추가하고, 비어있지 않다면 다시 값을 비교한다.

예를 들어 아래와 같은 트리에 6을 키로 가진 노드를 추가한다고 하자.

삽입과정

탐색과 비슷하게 삽입하고자 하는 값을 계속해서 비교해서 삽입할 위치를 찾는다.

삽입완료

삽입할 위치가 5의 오른쪽 서브 트리인 것을 찾았으므로, 5의 오른쪽 자식으로 6을 추가하면 된다.

이진 탐색 트리 삽입 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 void insert(TreeNode * * root, int key){ TreeNode * ptr; // 탐색을 진행할 포인터 TreeNode * newNode = (TreeNode * ) malloc ( sizeof (TreeNode)); // newNode 생성 newNode – > key = key; newNode – > left = newNode – > right = NULL ; if ( * root = = NULL ){ // 트리가 비어 있을 경우 * root = newNode; return ; } ptr = * root; // root 노드부터 탐색 진행 while (ptr){ if (key = = ptr – > key){ // 중복값 printf ( “Error : 중복값은 허용되지 않습니다!

” ); return ; } else if (key < ptr - > key){ // 왼쪽 서브트리 if (ptr – > left = = NULL ){ // 비어있다면 추가 ptr – > left = newNode; return ; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > left; } } else { // key > ptr->key 오른쪽 서브트리 if (ptr – > right = = NULL ){ // 비어있다면 추가 ptr – > right = newNode; return ; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > right; } } } } Colored by Color Scripter cs

이진 탐색 트리의 삭제(delete)

이진탐색트리의 삭제는 삽입보다 조금 더 복잡하다. 이진 탐색 트리에서 특정 노드를 삭제할 때 아래와 같은 3가지 상황을 나누어 구현해야 한다.

1. 삭제하려는 노드가 단말 노드(leaf node) 일 경우

2. 삭제하려는 노드의 서브 트리가 하나인 경우(왼쪽 혹은 오른쪽 서브 트리)

3. 삭제하려는 노드의 서브 트리가 두 개인 경우

1. 삭제하려는 노드가 단말 노드(leaf node) 일 경우

단말노드의 삭제

자식이 없는 단말 노드의 삭제는 간단하다. 삭제할 노드의 부모 노드가 있다면 부모 노드의 자식 노드를 NULL로 만들고, 삭제할 노드를 삭제(메모리 해제) 해주면 된다.

단말노드의 삭제 완료

2. 삭제하려는 노드의 서브 트리가 하나인 경우(왼쪽 혹은 오른쪽 서브 트리)

노드 삭제 과정

삭제하려는 노드의 서브 트리가 하나인 경우도 간단하다. 삭제할 노드의 자식노드를 삭제할 노드의 부모노드가 가리키게 하고 해당 노드를 삭제하면 된다.

3. 삭제하려는 노드의 서브트리가 두 개인 경우

노드 삭제 과정

삭제하려는 노드의 서브트리가 두 개인 경우는 가장 복잡하다. 이 경우 두 가지 방법을 사용할 수 있다.

1) 삭제할 노드 왼쪽 서브 트리의 가장 큰 자손을 해당 노드의 자리에 올린다.

노드 삭제 과정

위와 같이 삭제할 노드의 왼쪽 서브 트리에서 가장 큰 자손을 해당 노드의 자리에 올리면, 이진 탐색 트리의 조건을 만족하면서 트리가 유지되는 것을 확인할 수 있다. 또한 자리를 옮기면서 다른 노드들(4번노드)도 자리가 적절히 이동한 것을 확인 할 수 있다.

2) 삭제할 노드 오른쪽 서브 트리의 가장 작은 자손을 해당 노드의 자리에 올린다.

노드 삭제 과정

위와 같이 삭제할 노드의 오른쪽 서브 트리에서 가장 작은 자손을 해당 노드의 자리에 올리면, 이진 탐색 트리의 조건을 만족하면서 트리가 유지되는 것을 확인할 수 있다. 또한 자리를 옮기면서 다른 노드들(10번노드)도 자리가 적절히 이동한 것을 확인 할 수 있다.

이진 탐색 트리의 삭제 소스코드

그림으로 보면 이해가 쉬우나, 직접 구현하려면 헷갈리는 부분이 많을 것이다. 아래 코드를 보며 자세히 이해해 보자.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 TreeNode * delete_node(TreeNode * root, int key){ TreeNode * del = NULL ; // 삭제할 노드 TreeNode * parent = NULL ; // 삭제할 노드의 부모 노드 TreeNode * successor = NULL ; // 삭제할 노드의 왼쪽 서브트리에서 가장 큰 노드 TreeNode * predecessor = NULL ; // successor의 부모노드 TreeNode * child = NULL ; // 삭제할 노드의 자식 노드 del = root; while (del ! = NULL ){ // 삭제할 노드 탐색 if (key = = del – > key){ break ; } parent = del; if (key < del - > key){ del = del – > left; } else { del = del – > right; } } if (del = = NULL ){ printf ( “Error : 존재하지 않는 키

” ); return root; } if (del – > left = = NULL & & del – > right = = NULL ){ // 삭제할 노드의 자식노드가 없는 경우 if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽노드가 삭제할 노드일 때 parent – > left = NULL ; } else { // 오른쪽 일 때 parent – > right = NULL ; } } else { // 부모노드가 없는 경우 = root 노드 root = NULL ; } } else if (del – > left ! = NULL & & del – > right ! = NULL ){ // 삭제할 노드의 자식 노드가 2개인 경우 predecessor = del; successor = del – > left; while (successor – > right ! = NULL ){ // 왼쪽 서브트리에서 가장 큰 값 찾기 predecessor = successor; successor = successor – > right; } predecessor – > right = successor – > left; // successor의 자식 노드 위치 변경 successor – > left = del – > left; // successor를 삭제할 노드의 위치로 옮긴 것과 같음 successor – > right = del – > right; if (parent ! = NULL ){ // 삭제할 노드의 부모노드가 있을 때 if (parent – > left = = del){ parent – > left = successor; } else { parent – > right = successor; } } else { root = successor; } } else { // 삭제할 노드의 자식 노드가 1개인 경우 if (del – > left ! = NULL ){ // 왼쪽 노드 child = del – > left; } else { // 오른쪽 노드 child = del – > right; } if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽 노드로 삭제할 노드의 자식노드 연결 parent – > left = child; } else { // 부모노드의 오른쪽 노드로 삭제할 노드의 자식노드 연결 parent – > right = child; } } else { root = child; } } free (del); // 메모리해제 return root; } Colored by Color Scripter cs 전체 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 #include < stdio.h > #include < stdlib.h > typedef struct _TreeNode{ int key; // key 값 _TreeNode * left; // left child _TreeNode * right; // right child }TreeNode; TreeNode * search(TreeNode * root, int key){ if (root = = NULL ){ // 값을 찾지 못한 경우 printf ( “Error : 값을 찾을 수 없습니다

” ); return root; } if (key = = root – > key){ // 값을 찾음 return root; } else if (key < root - > key){ // 왼쪽 서브트리 탐색 search(root – > left, key); } else if (key > root – > key){ // 오른쪽 서브트리 탐색 search(root – > right, key); } } TreeNode * insert(TreeNode * root, int key){ TreeNode * ptr; // 탐색을 진행할 포인터 TreeNode * newNode = (TreeNode * ) malloc ( sizeof (TreeNode)); // newNode 생성 newNode – > key = key; newNode – > left = newNode – > right = NULL ; if (root = = NULL ){ // 트리가 비어 있을 경우 root = newNode; return root; } ptr = root; // root 노드부터 탐색 진행 while (ptr){ if (key = = ptr – > key){ // 중복값 printf ( “Error : 중복값은 허용되지 않습니다!

” ); return root; } else if (key < ptr - > key){ // 왼쪽 서브트리 if (ptr – > left = = NULL ){ // 비어있다면 추가 ptr – > left = newNode; return root; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > left; } } else { // key > ptr->key 오른쪽 서브트리 if (ptr – > right = = NULL ){ // 비어있다면 추가 ptr – > right = newNode; return root; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > right; } } } } TreeNode * delete_node(TreeNode * root, int key){ TreeNode * del = NULL ; // 삭제할 노드 TreeNode * parent = NULL ; // 삭제할 노드의 부모 노드 TreeNode * successor = NULL ; // 삭제할 노드의 왼쪽 서브트리에서 가장 큰 노드 TreeNode * predecessor = NULL ; // successor의 부모노드 TreeNode * child = NULL ; // 삭제할 노드의 자식 노드 del = root; while (del ! = NULL ){ // 삭제할 노드 탐색 if (key = = del – > key){ break ; } parent = del; if (key < del - > key){ del = del – > left; } else { del = del – > right; } } if (del = = NULL ){ printf ( “Error : 존재하지 않는 키

” ); return root; } if (del – > left = = NULL & & del – > right = = NULL ){ // 삭제할 노드의 자식노드가 없는 경우 if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽노드가 삭제할 노드일 때 parent – > left = NULL ; } else { // 오른쪽 일 때 parent – > right = NULL ; } } else { // 부모노드가 없는 경우 = root 노드 root = NULL ; } } else if (del – > left ! = NULL & & del – > right ! = NULL ){ // 삭제할 노드의 자식 노드가 2개인 경우 predecessor = del; successor = del – > left; while (successor – > right ! = NULL ){ // 왼쪽 서브트리에서 가장 큰 값 찾기 predecessor = successor; successor = successor – > right; } predecessor – > right = successor – > left; // successor의 자식 노드 위치 변경 successor – > left = del – > left; // successor를 삭제할 노드의 위치로 옮긴 것과 같음 successor – > right = del – > right; if (parent ! = NULL ){ // 삭제할 노드의 부모노드가 있을 때 if (parent – > left = = del){ parent – > left = successor; } else { parent – > right = successor; } } else { root = successor; } } else { // 삭제할 노드의 자식 노드가 1개인 경우 if (del – > left ! = NULL ){ // 왼쪽 노드 child = del – > left; } else { // 오른쪽 노드 child = del – > right; } if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽 노드로 삭제할 노드의 자식노드 연결 parent – > left = child; } else { // 부모노드의 오른쪽 노드로 삭제할 노드의 자식노드 연결 parent – > right = child; } } else { root = child; } } free (del); // 메모리해제 return root; } void print_tree(TreeNode * root){ if (root = = NULL ){ return ; } printf ( “%d

” , root – > key); print_tree(root – > left); print_tree(root – > right); } int main(){ TreeNode * root = NULL ; TreeNode * ptr = NULL ; root = insert(root, 7 ); root = insert(root, 3 ); root = insert(root, 8 ); root = insert(root, 1 ); root = insert(root, 5 ); root = insert(root, 4 ); root = insert(root, 10 ); print_tree(root); printf ( ”

” ); ptr = search(root, 7 ); printf ( “%d

” , ptr – > key); root = delete_node(root, 7 ); ptr = search(root, 7 ); return 0; } Colored by Color Scripter cs

실행결과

반응형

[C언어] 포인터를 이용한 이진 트리(Binary Tree) 구현 & 순회

노드(Node) + 간선(Edge)

계층 구조: 부모-자식 관계

트리에서의 위치에 따라

루트(root) 노드: 최상위 노드

단말(말단, terminal) 노드 / 잎(leaf) 노드: 자식 노드가 없는 노드

내부(internal) 노드: 자식이 1개 이상 있는 노드

노드 사이의 관계 관점에서

부모(parent) 노드: 어떤 노드의 직접적인 상위 노드

자식(child) 노드: 어떤 노드의 직접적인 하위 노드

선조(ancestor) 노드: 어떤 노드의 상위 노드들

후손(descendent) 노드: 어떤 노드의 하위 노드들

형제(sibling) 노드: 같은 부모를 갖는 노드

속성 관점에서

레벨(level): 루트 노드로부터의 거리 ( 루트 노드의 경우 레벨이 1 )

) 높이(height): 단말 노드로부터의 최대 거리 ( 단말 노드의 경우 높이가 1 ) 트리의 높이는 루트 노드의 높이를 말함

) 깊이(depth): 루트에서 어떤 노드에 도달하기 위해 거쳐야 하는 간선의 수

차수(degree): 자식 노드의 개수

기타

서브트리(subtree): 전체 트리의 부분집합

포리스트(forest): 트리들의 집합

이진 트리 (Binary Tree)

최대 차수가 2인 트리

서브 트리 간 순서가 존재

포화 이진 트리(full binary tree)

각 레벨에 노드가 꽉 찬 이진 트리

각 레벨 단위로 왼쪽에서 오른쪽으로 번호를 붙일 수 있으며, 부여된 번호는 항상 일정

트리의 높이가 h h h 일 때 노드의 개수는 2 h − 1 2^h – 1 2 h − 1 개

완전 이진 트리(complete binary tree)

높이가 h h h 일 때, 레벨 1 1 1 부터 h − 1 h-1 h − 1 까지는 포화 이진 트리

일 때, 레벨 부터 까지는 포화 이진 트리 마지막 레벨 h h h 에서는 왼쪽부터 오른쪽으로 순서대로 채워진 이진 트리

에서는 왼쪽부터 오른쪽으로 순서대로 채워진 이진 트리 중간에 빈 곳이 있으면 안 됨

편향 이진 트리(skewed binary tree)

왼쪽이나 오른쪽 서브 트리만 가지는 트리

노드 개수는 높이와 같음

메모리 공간이 낭비되고 성능에 문제 발생 ( l o g 2 n log_2n l o g 2 ​ n 의 탐색 시간을 보장받지 못함)

이진 트리 구현

포인터를 이용한 구현

구조체와 함수 원형

typedef struct BinTreeNodeType { char data ; struct BinTreeNodeType * pLeftChild ; struct BinTreeNodeType * pRightChild ; } BinTreeNode ; typedef struct BinTreeType { struct BinTreeNodeType * pRootNode ; } BinTree ; BinTree * makeBinTree ( BinTreeNode rootNode ) ; BinTreeNode * getRootNodeBT ( BinTree * pBinTree ) ; BinTreeNode * insertLeftChildNodeBT ( BinTreeNode * pParentNode , BinTreeNode element ) ; BinTreeNode * insertRightChildNodeBT ( BinTreeNode * pParentNode , BinTreeNode element ) ; BinTreeNode * getLeftChildNodeBT ( BinTreeNode * pNode ) ; BinTreeNode * getRightChildNodeBT ( BinTreeNode * pNode ) ; void deleteBinTree ( BinTree * * pBinTree ) ; void deleteBinTreeNode ( BinTreeNode * pNode ) ;

이진 트리 생성

BinTree * makeBinTree ( BinTreeNode rootNode ) { BinTree * tree ; tree = ( BinTree * ) calloc ( 1 , sizeof ( BinTree ) ) ; if ( tree == NULL ) return ( NULL ) ; tree -> pRootNode = ( BinTreeNode * ) calloc ( 1 , sizeof ( BinTreeNode ) ) ; if ( tree -> pRootNode == NULL ) { free ( tree ) ; return ( NULL ) ; } * ( tree -> pRootNode ) = rootNode ; return ( tree ) ; }

자식 노드 추가

BinTreeNode * insertLeftChildNodeBT ( BinTreeNode * pParentNode , BinTreeNode element ) { if ( pParentNode == NULL ) { fprintf ( stderr , “ERROR: 트리 없음

” ) ; return ( NULL ) ; } pParentNode -> pLeftChild = ( BinTreeNode * ) calloc ( 1 , sizeof ( BinTreeNode ) ) ; if ( pParentNode -> pLeftChild == NULL ) { fprintf ( stderr , “ERROR: 노드 메모리 할당 X

” ) ; return ( NULL ) ; } * ( pParentNode -> pLeftChild ) = element ; return ( pParentNode -> pLeftChild ) ; } BinTreeNode * insertRightChildNodeBT ( BinTreeNode * pParentNode , BinTreeNode element ) { if ( pParentNode == NULL ) { fprintf ( stderr , “ERROR: 트리 없음

” ) ; return ( NULL ) ; } pParentNode -> pRightChild = ( BinTreeNode * ) calloc ( 1 , sizeof ( BinTreeNode ) ) ; if ( pParentNode -> pRightChild == NULL ) { fprintf ( stderr , “ERROR: 노드 메모리 할당 X

” ) ; return ( NULL ) ; } * ( pParentNode -> pRightChild ) = element ; return ( pParentNode -> pRightChild ) ; }

자식 노드 반환

BinTreeNode * getLeftChildNodeBT ( BinTreeNode * pNode ) { if ( pNode == NULL ) { fprintf ( stderr , “ERROR: 노드 없음

” ) ; return ( NULL ) ; } return ( pNode -> pLeftChild ) ; } BinTreeNode * getRightChildNodeBT ( BinTreeNode * pNode ) { if ( pNode == NULL ) { fprintf ( stderr , “ERROR: 노드 없음

” ) ; return ( NULL ) ; } return ( pNode -> pRightChild ) ; }

이진 트리 삭제

후위 순회로 각 노드를 삭제 (L-R-V)

void deleteBinTree ( BinTree * * pBinTree ) { if ( pBinTree == NULL || * pBinTree == NULL ) { fprintf ( stderr , “ERROR: 트리 없음

” ) ; return ; } deleteBinTreeNode ( ( * pBinTree ) -> pRootNode ) ; free ( * pBinTree ) ; * pBinTree = NULL ; } void deleteBinTreeNode ( BinTreeNode * pNode ) { if ( pNode == NULL ) return ; deleteBinTreeNode ( pNode -> pLeftChild ) ; deleteBinTreeNode ( pNode -> pRightChild ) ; free ( pNode ) ; }

이진 트리 순회(traversal)

루트 노드를 언제 순회하느냐가 기준

재귀를 이용하여 구현

전위 순회: A B D H I E J C F K G L M

중위 순회: H D I B J E A F K C L G M

후위 순회: H I D J E B K F L M G C A

함수 원형

void preorderTraverse ( BinTreeNode * pNode ) ; void inorderTraverse ( BinTreeNode * pNode ) ; void postorderTraverse ( BinTreeNode * pNode ) ;

V : visited, L : left, R : right

전위 순회(preorder traversal)

V-L-R

void preorderTraverse ( BinTreeNode * pNode ) { if ( pNode == NULL ) return ; printf ( “%c ” , pNode -> data ) ; preorderTraverse ( pNode -> pLeftChild ) ; preorderTraverse ( pNode -> pRightChild ) ; }

중위 순회(inorder traversal)

L-V-R

void inorderTraverse ( BinTreeNode * pNode ) { if ( pNode == NULL ) return ; inorderTraverse ( pNode -> pLeftChild ) ; printf ( “%c ” , pNode -> data ) ; inorderTraverse ( pNode -> pRightChild ) ; }

후위 순회(postorder traversal)

L-R-V

Top 40 이진 트리 구현 The 81 New Answer

20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]

20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]

자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal) | ChanBLOG

Article author: chanhuiseok.github.io

Reviews from users: 21707 Ratings

Ratings Top rated: 3.8

Lowest rated: 1

Summary of article content: Articles about 자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal) | ChanBLOG 트리는 배열이나 연결리스트로 구현하는 것이 보편적이다. 배열로 트리를 구현할 때는 노드 넘버링을 할 때 통상 인덱스 1부터 시작함에 … …

Most searched keywords: Whether you are looking for 자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal) | ChanBLOG 트리는 배열이나 연결리스트로 구현하는 것이 보편적이다. 배열로 트리를 구현할 때는 노드 넘버링을 할 때 통상 인덱스 1부터 시작함에 … 트리는 마치 나무를 거꾸로 한 모습과 비슷하다고 해서 붙여진 자료구조의 이름입니다.

Table of Contents:

트리와 관련된 용어 정리

이진트리와 관련한 개념 정리

이진 트리의 순회

이진 트리의 구현

소스코드

자료구조 – 이진 트리 (binary tree) 와 이진트리의 순회(traversal) | ChanBLOG

Read More

[자료구조] 이진 트리(Binary Tree) 개념과 구현

Article author: leejinseop.tistory.com

Reviews from users: 33039 Ratings

Ratings Top rated: 4.5

Lowest rated: 1

Summary of article content: Articles about [자료구조] 이진 트리(Binary Tree) 개념과 구현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다. …

Most searched keywords: Whether you are looking for [자료구조] 이진 트리(Binary Tree) 개념과 구현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다. 1. 트리 트리(Tree)란 비선형 자료구조 중에서 자료들 간에 계층관계를 가진 계층형 자료구조(Hierarchical Data Structure)를 말합니다. · 노드(Node): 트리를 구성하는 원소(자료) · 간선(Edge): 노드를 연결..

Table of Contents:

[자료구조] 이진 트리(Binary Tree) 개념과 구현

Read More

[C] 이진 트리 구현 코드

Article author: eunjinii.tistory.com

Reviews from users: 21237 Ratings

Ratings Top rated: 4.0

Lowest rated: 1

Summary of article content: Articles about [C] 이진 트리 구현 코드 이진 트리 노드 구현. 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능 … …

Most searched keywords: Whether you are looking for [C] 이진 트리 구현 코드 이진 트리 노드 구현. 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능 … 1. 이진 트리 노드 구현 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능하다. 노드 구조체는 다음과 같다. #include #include typed..

Table of Contents:

프린세스 다이어리

[C] 이진 트리 구현 코드

[C] 이진 트리 구현 코드 본문

Read More

python으로 이진트리 구현하기

Article author: brunch.co.kr

Reviews from users: 6867 Ratings

Ratings Top rated: 5.0

Lowest rated: 1

Summary of article content: Articles about python으로 이진트리 구현하기 알고리즘 끝장내기 | 이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다. …

Most searched keywords: Whether you are looking for python으로 이진트리 구현하기 알고리즘 끝장내기 | 이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다. 알고리즘 끝장내기 | 이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다. 맨 꼭 대기에 있는 1번 노드는 루트(Root)라고 한다. 루트 노드의 깊이를 1로 하고 한 단계 내려가면 깊이가 1만큼 증가한다. 트리 1과 트리 2는 노드와 에지를 가지고 있는 트리다. 1번부터 9번 노드를 가지고 있다.

Table of Contents:

python으로 이진트리 구현하기

Read More

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree)

Article author: iyk2h.tistory.com

Reviews from users: 43234 Ratings

Ratings Top rated: 3.6

Lowest rated: 1

Summary of article content: Articles about C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree) C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree). by IYK2h 2021. 3. 5. 320×100. 코드 … …

Most searched keywords: Whether you are looking for C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree) C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree). by IYK2h 2021. 3. 5. 320×100. 코드 … 코드 //binary search tree #include #include typedef struct node { int data; struct node* left; struct node* right; }node; node* root; node* insert(node* root,int data) { if(root == NULL) { root = (n..

Table of Contents:

태그

관련글

댓글0

인기글

최근글

태그

전체 방문자

티스토리툴바

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree)

Read More

[자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해 | C언어 이진탐색트리 구현

Article author: code-lab1.tistory.com

Reviews from users: 15396 Ratings

Ratings Top rated: 4.0

Lowest rated: 1

Summary of article content: Articles about [자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해 | C언어 이진탐색트리 구현 ( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리) 1. … 이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다. …

Most searched keywords: Whether you are looking for [자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해 | C언어 이진탐색트리 구현 ( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리) 1. … 이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다. 이진탐색트리(Binary Search Tree)이란? 이진탐색트리란 다음과 같은 특징을 갖는 이진트리를 말한다. ( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리) 1. 각 노드에 중복되지 않는 키(key)가 있다. 2. 루..

Table of Contents:

Header Menu

Main Menu

[자료구조] 이진탐색트리(Binary Search Tree)의 개념 이해 C언어 이진탐색트리 구현

이진탐색트리(Binary Search Tree)이란

이진 탐색 트리의 특징

‘Computer Science[자료구조]’ 관련 글

Sidebar – Right

Copyright © 코드 연구소 All Rights Reserved

Designed by JB FACTORY

티스토리툴바

[자료구조] 이진탐색트리(Binary Search Tree)의 개념, 이해 | C언어 이진탐색트리 구현

Read More

자료구조-트리 (트리, 이진 트리, C로 구현)

Article author: foxtrotin.tistory.com

Reviews from users: 36203 Ratings

Ratings Top rated: 3.3

Lowest rated: 1

Summary of article content: Articles about 자료구조-트리 (트리, 이진 트리, C로 구현) 자료구조-트리 (트리, 이진 트리, C로 구현). proqk 2020. 6. 10. 23:58 … 노드의 왼쪽 자식 노드를 루트로 하는 왼쪽 서브트리도 이진 트리. …

Most searched keywords: Whether you are looking for 자료구조-트리 (트리, 이진 트리, C로 구현) 자료구조-트리 (트리, 이진 트리, C로 구현). proqk 2020. 6. 10. 23:58 … 노드의 왼쪽 자식 노드를 루트로 하는 왼쪽 서브트리도 이진 트리. 트리 원소들 간에 1:n 관계를 가지는 비선형 자료구조 원소들 간에 계층 관계를 가지는 계층형 자료구조 상위 원소에서 하위 원소로 내려가면서 확장되는 트리 모양 구조 노드: 트리의 원소 -트리 A의 노드: A,B,..

Table of Contents:

안 쓰던 블로그

자료구조-트리 (트리 이진 트리 C로 구현) 본문

티스토리툴바

자료구조-트리 (트리, 이진 트리, C로 구현)

Read More

[ 자료구조 강좌 ] 6. 이진 트리 구현하기 : 네이버 블로그

Article author: m.blog.naver.com

Reviews from users: 3415 Ratings

Ratings Top rated: 4.6

Lowest rated: 1

Summary of article content: Articles about [ 자료구조 강좌 ] 6. 이진 트리 구현하기 : 네이버 블로그 또한 이진 트리를 구현할 수 있다면 전위 순회, 중위. 순회, 후위 순회까지 다양한 응용이 가능합니다. 따라서 왠만하면 자신만의 이진 트리를 구현한 … …

Most searched keywords: Whether you are looking for [ 자료구조 강좌 ] 6. 이진 트리 구현하기 : 네이버 블로그 또한 이진 트리를 구현할 수 있다면 전위 순회, 중위. 순회, 후위 순회까지 다양한 응용이 가능합니다. 따라서 왠만하면 자신만의 이진 트리를 구현한 …

Table of Contents:

카테고리 이동

안경잡이개발자

이 블로그

자료구조 강좌

카테고리 글

카테고리

이 블로그

자료구조 강좌

카테고리 글

[ 자료구조 강좌 ] 6. 이진 트리 구현하기 : 네이버 블로그

Read More

See more articles in the same category here: Top 767 tips update new.

[자료구조] 이진 트리(Binary Tree) 개념과 구현

1. 트리 트리(Tree)란 비선형 자료구조 중에서 자료들 간에 계층관계를 가진 계층형 자료구조(Hierarchical Data Structure)를 말합니다. 트리 · 노드(Node): 트리를 구성하는 원소(자료) · 간선(Edge): 노드를 연결하는 선 · 차수(Dgree): 자식 노드의 수 · 높이(Height): 루트에서 해당 노드에 이르는 경로에 있는 간선의 수 · 루트 노드(Root Node): 트리의 시작 노드 · 형제 노드(Sibling Node): 같은 부모 노드의 자식노드들 · 조상 노드(Ancestor Node): 한 노드에서 간선을 따라 루트 노드까지 이르는 경로에 있는 노드들 · 자손 노드(Descendant Node): 한 노드의 서브 트리에 있는 노드들 · 단말 또는 리프 노드(Leaf Node): 자식이 없는 노드 2. 이진 트리 이진 트리(Binary Tree)란 모든 노드의 차수를 2 이하로 정하여 전체 트리의 차수가 2 이하가 되도록 만든 트리입니다. 이진 트리 · 이진 트리는 왼쪽 자식 노드와 오른쪽 자식 노드 2개만을 가질 수 있으며, 공백 노드도 이진 트리의 노드로 취급합니다. · 이진 트리에 있는 모든 노드는 왼쪽 자식 노드를 루트로 하는 왼쪽 서브 트리와 오른쪽 자식 노드를 루트로 하는 오른쪽 서브 트리를 가집니다. 그리고 이진 트리의 서브 트리들 모두 이진 트리여야 합니다. 3. 이진 트리의 특징 ① n개의 노드를 가진 이진 트리는 항상 (n-1)개의 간선을 갖습니다. 루트 노드 이외의 모든 노드는 한 개의 부모 노드를 가지고 있기 때문에 부모 노드와 연결하는 한 개의 간선을 갖습니다. 따라서 n개의 노드로 구성된 이진 트리에서 루트 노드를 제외한 나머지 노드의 개수가 (n-1)개이므로 (n-1)개의 간선을 갖습니다. ② 높이가 h인 이진 트리가 가질 수 있는 노드의 최소 개수는 (h+1)개, 최대 개수는 (2^(h+1) -1)개입니다. 이진 트리의 높이가 h가 되려면 한 레벨에 최소한 한 개의 노드가 있어야 하므로 높이가 h인 이진 트리의 최소 노드의 개수는 (h+1)개가 됩니다. 하나의 노드는 최대 2개의 자식 노드를 가질 수 있기 때문에 레벨 i에서 노드의 최대 개수는 2^i가 됩니다. 따라서 높이가 h인 이진 트리에서 최대 노드의 개수는 (2^(h+1) -1)개가 됩니다. 4. 이진 트리의 종류 ① 포화 이진 트리 모든 레벨에 노드가 꽉 차있는 포화 상태의 이진 트리입니다. 즉 이진 트리의 높이가 h일 때 (2^(h+1) -1)개의 노드를 갖는 이진 트리를 말합니다. 포화 이진 트리 ② 완전 이진 트리 높이가 h, 노드의 개수가 n개일 때(단, n < 2^(h+1) -1), 노드의 위치가 포화 이진 트리의 노드 1번 부터 n번까지의 위치와 완전히 일치하는 이진 트리입니다. 따라서 (n+1)번 부터 (2^(h+1) -1)번까지는 공백 노드가 됩니다. 완전 이진 트리 ③ 편향 이진 트리 이진 트리 중에서 최소 개수의 노드를 가지면서 왼쪽이나 오른쪽 서브 트리만 가지고 있는 트리입니다. 즉 이진 트리의 높이가 h일 때 (h+1)개의 노드를 가지면서 한 쪽으로 치우친 이진 트리를 말합니다. 왼쪽 편향 이진 트리와 오른쪽 편향 이진 트리 5. 이진 트리의 구현 · 순차 자료구조 방식 1차원 배열에서 인덱스 계산을 간단히 하기 위해서 인덱스 0번은 사용하지 않고 비워두고, 인덱스 1번에 루트를 저장합니다. 완전 이진 트리의 배열 표현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다. 노드 인덱스 조건 노드 i의 부모 노드 i / 2 i > 1 노드 i의 왼쪽 자식 노드 i * 2 (i * 2) <= n 노드 i의 오른쪽 자식 노드 (i * 2) + 1 (i * 2) + 1 <= n · 연결 자료구조 방식 배열을 이용한 이진 트리의 구현은 인덱스 규칙에 따라 부모 노드와 자식 노드를 찾기 쉽다는 장점이 있습니다. 하지만 메모리 공간의 사용에 있어 완전 이진 트리의 경우에는 최적의 공간 사용이 되지만, 편향 이진 트리의 경우 많은 공간이 낭비됩니다. 따라서 메모리 낭비 문제와 삽입 · 삭제 연산이 비효율적인 순차 자료구조 방식 보다는 연결 자료구조 방식을 많이 사용합니다. 이진 트리의 노드는 왼쪽 자식 노드와 오른쪽 자식 노드를 연결해야 하므로 데이터를 저장하는 데이터 필드, 왼쪽 자식 노드를 연결하는 왼쪽 링크 필드와 오른쪽 자식 노드를 연결하는 오른쪽 링크 필드로 구성된 참조 변수를 사용해야 합니다. public class TreeNode { private Object data; TreeNode left; TreeNode right; public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } 6. 이진 트리의 순회 이진 트리에 있는 모든 노드를 한번씩 모두 방문하여 노드가 가지고 있는 데이터를 처리하는 것을 순회라고 합니다. 선형 자료구조는 순회하는 방법이 한 가지였지만, 트리는 계층적인 구조를 가지고 있기 때문에 여러 가지 순회 방법이 있습니다. 하나의 노드에서 순회를 위해 수행할 수 있는 작업은 (1) 현재 노드를 방문하여 데이터를 읽는 작업, (2) 현재 노드의 왼쪽 서브 트리로 이동하는 작업, (3) 현재 노드의 오른쪽 서브 트리로 이동하는 작업이 있습니다. 그리고 서브 트리를 순회하는 순서는 항상 왼쪽 서브 트리를 먼저 방문하고, 그 후에 오른쪽 서브 트리를 방문하는 것으로 합니다. 따라서 현재 노드를 방문하는 순서에 따라 전위 순회, 중위 순회, 후위 순회로 나눌 수 있습니다. · 전위 순회(Preorder Traversal) 현재 노드를 방문 → 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 preorder(T) if(T != null) then{ visit T.data; preorder(T.left); preorder(T.right); } end preorder() · 중위 순회(Inorder Traversal) 왼쪽 서브 트리 방문 → 현재 노드를 방문 → 오른쪽 서브 트리 방문 inorder(T) if(T != null) then { inorder(T.left); visit T.data; inorder(T.right); } end inorder() · 후위 순회(Postorder Traversal) 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 → 현재 노드를 방문 postorder(T) if(T != null) then { postorder(T.left); postorder(T.right); visit T.data; } end postorder(T) 7. 이진 트리 소스 코드 · TreeNode public class TreeNode { private Object data; // 데이터 필드 TreeNode left; // 왼쪽 링크 필드 TreeNode right; // 오른쪽 링크 필드 public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } · LinkedTree public class LinkedTree { // 이진 트리 노드 생성 public TreeNode makeBT(TreeNode left, Object data, TreeNode right) { TreeNode newNode = new TreeNode(data); newNode.left = left; newNode.right = right; return newNode; } // 전위 순회 public void preorder(TreeNode node) { if (node != null) { System.out.printf("%c", node.getData()); preorder(node.left); preorder(node.right); } } // 중위 순회 public void inorder(TreeNode node) { if (node != null) { inorder(node.left); System.out.printf("%c", node.getData()); inorder(node.right); } } // 후위 순회 public void postorder(TreeNode node) { if (node != null) { postorder(node.left); postorder(node.right); System.out.printf("%c", node.getData()); } } } · MainForLinkedTree public class MainForLinkedTree { public static void main(String[] args) { LinkedTree t = new LinkedTree(); TreeNode n7 = t.makeBT(null, 'D', null); TreeNode n6 = t.makeBT(null, 'C', null); TreeNode n5 = t.makeBT(null, 'B', null); TreeNode n4 = t.makeBT(null, 'A', null); TreeNode n3 = t.makeBT(n6, '-', n7); TreeNode n2 = t.makeBT(n4, '+', n5); TreeNode n1 = t.makeBT(n2, '*', n3); // 전위 순회 System.out.printf("preorder: "); t.preorder(n1); // 중위 순회 System.out.printf(" inorder: "); t.inorder(n1); // 후위 순회 System.out.printf(" postorder: "); t.postorder(n1); } } · 실행 결과 [C] 이진 트리 구현 코드 728×90 1. 이진 트리 노드 구현 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능하다. 노드 구조체는 다음과 같다. #include #include typedef struct Node { int data; struct Node *leftChild; struct Node *rightChild; } Node; 하나의 노드는 내부적으로 하나의 data를 가지고 있다. 여기 예시 코드에서는 정수형 데이터 하나만 들어가는 걸로 설정했지만, 실제로는 다양한 데이터가 data에 들어갈 수 있다. 특정 노드를 초기화하는 함수는 다음과 같다. Node* initNode(int data, Node* leftChild, Node* rightChild) { Node* node = (Node*) malloc(sizeof(Node)); node -> data = data; node -> leftChild = leftChild; node -> rightChild = rightChild; return node; } 이진트리 같은 경우에는 함수의 반환형에서 특정 노드의 포인터가 들어가는 경우가 많다. data, leftNode, rightNode 모두 초기화시켜준 다음, 그 노드의 포인터를 반환해 준다. 2. 이진 트리의 순회 알고리즘 이진 트리는 자료구조이기 때문에 컴퓨터의 메모리상에 올라가 있어 사람이 이진트리에 담긴 데이터를 시각화하기란 어렵다. 따라서 이진트리에 담긴 데이터를 조회해서 출력하는 방법으로는 주로 순회 기법을 사용한다. 크게 세 가지 순회 방법이 있다. (1) 전위 순회 – 자기 자신을 출력한다 -> 왼쪽 자식을 방문한다. -> 오른쪽 자식을 방문한다. 전위 순회 같은 경우에는 먼저 루트에서 시작하면 자기 자신을 출력하고, 그 다음에 왼쪽 자식노드로 들어가서 데이터를 출력하고, 다시 그 노드의 왼쪽 자식노드로 들어가서 데이터를 출력한다. 마지막에 다다르면 부모 노드로 거슬러 올라갔다가, 부모 노드의 오른쪽 자식 노드로 가서 데이터를 출력한다. 전위 순위법 void preorder(Node* root) { if (root) { printf(“%d “, root -> data); preorder(root -> leftChild); preorder(root -> rightChild); } } 특정한 노드가 주어졌을 때, 그 노드가 null값이 아니라면 재귀적으로 다음 노드를 탐색한다. 먼저 자기 자신을 출력한 후에 왼쪽으로 들어가고, 마지막에 왼쪽 노드가 null이면 이제 오른쪽 노드로 들어가는 것이다. (2) 중위 순회 – 왼쪽 자식 출력 -> 그 다음 자기 자신 출력 -> 오른쪽 자식 출력 맨 위 노드에서 계속 왼쪽 자식 노드로 내려간 다음, 1을 출력한다. 그 다음 2, 3을 출력한다. 돌아와서 4를 출력하고 같은 과정을 반복한다. 항상 왼쪽으로 쭉 내려갔다가 자신으로 돌아온 후 오른쪽으로 간다. 결과적으로 왼쪽에서부터 오른쪽으로 차례로 출력된다. 중위 순위법 void inorder(Node* root) { if (root) { inorder(root -> leftChild); printf(“%d “, root -> data); inorder(root -> rightChild); } } 전위순위랑 비슷하고 코드의 순서만 바꿔주면 된다. 왼쪽 노드를 먼저 방문 후, 자기 자신을 출력하고 오른쪽을 방문한다. (3) 후위 순위 – 왼쪽 자식 방문 -> 오른쪽 자식 방문 -> 자기 자신 출력 먼저 왼쪽 최하단 노드 1을 방문한 다음, 그 형제 노드 2를 방문한 후 부모 노드 3을 출력한다. 그리고 루트의 오른쪽 4, 5, 6 노드들에 대해서도 같은 연산을 반복한 다음 루트로 돌아와서 출력한다. 이 알고리즘은 루트가 가장 마지막에 출력된다는 특징이 있다. 후위 순위법 void postorder(Node* root) { if (root) { postorder(root -> leftChild); postorder(root -> rightChild); printf(“%d “, root -> data); } } 마찬가지로 코드의 순서만 바꿔주면 된다. 왼쪽 노드를 먼저 방문 후, 오른쪽을 방문한 다음 자기 자신을 출력한다. 3. 순회 알고리즘 코드로 표현해보기 int main(void) { Node* n7 = initNode(50, NULL, NULL); Node* n6 = initNode(37, NULL, NULL); Node* n5 = initNode(23, NULL, NULL); Node* n4 = initNode(5, NULL, NULL); Node* n3 = initNode(48, n6, n7); Node* n2 = initNode(17, n4, n5); Node* n1 = initNode(30, n2, n3); preorder(n1); printf(” “); inorder(n1); printf(” “); postorder(n1); printf(” “); } 루트 노드를 n1이라고 하고 그 자식을 각각 n2, n3라 한다. 또 각 자식도 자식노드를 가진다. 이 하위 자식노드는 더 이상 자식 노드를 갖지 않기 때문에 왼쪽 노드, 오른쪽 노드 부분에 NULL을 넣어 준다. 차례대로 전위, 중위, 후위순회를 실행해 보면 다음과 같이 출력된다. 30 17 5 23 48 37 50 5 17 23 30 37 48 50 5 23 17 37 50 48 30 728×90 반응형

python으로 이진트리 구현하기

이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다. 맨 꼭 대기에 있는 1번 노드는 루트(Root)라고 한다. 루트 노드의 깊이를 1로 하고 한 단계 내려가면 깊이가 1만큼 증가한다. 트리의 종류 트리 1과 트리 2는 노드와 에지를 가지고 있는 트리다. 1번부터 9번 노드를 가지고 있다. 둘 다 1번 노드가 루트이고 깊이는 4이다. 2번 노드를 보면 두 트리의 차이점을 알 수 있다. 트리 1의 2번 노드는 자식 노드가 3개이지만 트리 2는 2번 노드의 자식 노드는 2개이다. 트리 2처럼 모든 노드가 최대 두 개의 자식을 갖는 트리를 이진트리라고 한다. 이진트리는 깊이 h에 최대 2^{h-1}만큼 노드를 가질 수 있다. 자 이제, 다음과 같은 이진트리를 python으로 생성해보자. 이진트리 만들기 Node는 자기 자신의 값인 item과 자식의 위치인 left와 right를 가진다. class Node: def __init__(self, item): self.item = item self.left = None self.right = None 각 노드를 생성한다. n1 = Node(10) n2 = Node(20) n3 = Node(30) n4 = Node(40) n5 = Node(50) n6 = Node(60) n7 = Node(70) n8 = Node(80) 각 노드를 엮어주기 위하여 BinaryTree를 만든다. class BinaryTree(): def __init__(self): #트리 생성 self.root = None 순서에 맞게 노드를 엮는다. tree = BinaryTree() tree.root = n1 n1.left = n2 n1.right = n3 n2.left = n4 n2.right = n5 n3.left = n6 n3.right = n7 n4.left = n8 트리 순회란 트리 순회란 트리의 노드를 지정한 순서대로 방문하는 것을 말한다. 이진트리를 순회하는 방법은 대표적으로 3개이다. 여기에 1가지를 더해 총 4가지를 python으로 구현해보자. 전위 순회 (Preorder) 후위 순회 (Postorder) 중위 순회 (Inorder) 레벨 순회 (Levelorder) 트리를 읽을 때에 대전제는 왼쪽부터 오른쪽으로 읽는다는 것이다. 오른쪽에서부터 왼쪽으로는 읽지 않는다. “방문”은 자신의 번호를 출력하는 print() 함수로 표현한다. 이 출력 함수의 위치에 따라서 트리를 순회하는 방법을 구분하는 것이다. 트리 순회 전위 순회 ( Pre order) 자기 자신을 먼저 출력하고 자식 노드를 호출한다. 순서는 다음과 같다. 자기 자신 출력 왼쪽 서브 트리 호출 오른쪽 서브 트리 호출 그렇다면 출력은 어떤 순서로 될까? 우선 맨 위 루트부터 방문하므로 자기 자신인 10을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다. 왼쪽에 있는 20번 노드를 방문했으므로 20을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다. 왼쪽에 있는 40번 노드를 방문했으므로 40을 출력한다. 그 후에 왼쪽에 있는 트리를 호출한다. 왼쪽에 있는 80번 노드를 방문했으므로 80을 출력한다. 80번 노드는 자식 노드가 없으므로 더 호출하지 않는다. 40번 노드로 올라간다. 40번 노드의 오른쪽 노드가 없으므로 더 호출하지 않는다. 20번 노드로 올라간다. 20번 노드의 오른쪽 노드인 50번 노드를 방문한다. 50번 노드 출력. 50번 노드가 자식 노드가 없으므로 호출 끝. 20번 노드로 올라간다. 호출할 자식 노드 없으므로 10번 노드로 올라간다. 오른쪽의 30번 노드를 방문한다. 30을 출력한다. 왼쪽 노드인 60번 노드 방문. 60을 호출. 자식 노드 없으므로 호출 끝. 30번 노드로 올라간다. 오른쪽 노드인 70번 노드를 방문한다. 70을 출력한다. 자식 노드 없으므로 호출 끝. 정답 : 10 20 40 80 50 30 60 70 # 전위 순회 def preorder(self, n): if n != None: print(n.item, ”, end=”) # 노드 방문 if n.left: self.preorder(n.left) # 왼쪽 서브 트리 순회 if n.right: self.preorder(n.right) # 오른쪽 서브 트리 순회 후위 순회 (Postorder) 자기 자신 출력을 가장 나중에 한다. 왼쪽 서브 트리 호출 오른쪽 서브 트리 호출 자기 자신 출력 # 후위 순회 def postorder(self, n): if n != None: if n.left: self.postorder(n.left) if n.right: self.postorder(n.right) print(n.item, ”, end=”) # 노드 방문 호출을 먼저 하고 끝이 보이면 자기 자신을 출력하므로 가장 왼쪽 노드인 80부터 출력된다. 정답 : 80 40 50 20 60 70 30 10 중위 순회 (Inorder) 자기 자신 출력이 중간에 있다. 왼쪽 서브 트리 호출 자기 자신 출력 오른쪽 서브 트리 호출 # 중위 순회 def inorder(self, n): if n != None: if n.left: self.inorder(n.left) print(n.item, ”, end=”) # 노드 방문 if n.right: self.inorder(n.right) 정답 : 80 40 20 50 10 60 30 70 레벨 순회 (Levelorder) 레벨 순회는 깊이(레벨) 단위로 출력하는 것이다. 그 순서는 깊이가 낮은 순서이다. 우리가 흔히 생각하는 10 20 30 40 50 60 70 80 순으로 출력하고 싶다면 어떻게 해야 할까? 호출될 때마다 자식 노드를 따로 저장하는 것이다. 선입선출 구조인 큐로 구현한다. # 레벨 순회 def levelorder(self, n): q = [] q.append(n) while q: t = q.pop(0) print(t.item, ”, end=”) if t.left != None: q.append(t.left) if t.right != None: q.append(t.right) 정답 : 10 20 30 40 50 60 70 80 전체 코드 전체 코드는 블로그를 참조하라. 이제 이진 트리라는 자료구조를 구현하는 방법을 알았다. 다음에는 이 구조를 활용하여 결정 트리(Decision Tree)를 만들어 보자. qqplot의 기술 블로그 https://qqplot.github.io/

So you have finished reading the 이진 트리 구현 topic article, if you find this article useful, please share it. Thank you very much. See more: 이진트리 구현 파이썬, 이진트리 구현 c++, 이진트리 구현 자바, c언어 이진트리 구현, c언어 이진트리 연결리스트 구현, 이진트리 삽입 구현, 이진트리 구현 java, 이진트리 배열 구현

이진 트리 구현 | 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] 14271 좋은 평가 이 답변

당신은 주제를 찾고 있습니까 “이진 트리 구현 – 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]“? 다음 카테고리의 웹사이트 https://ppa.dianhac.com.vn 에서 귀하의 모든 질문에 답변해 드립니다: https://ppa.dianhac.com.vn/blog/. 바로 아래에서 답을 찾을 수 있습니다. 작성자 동빈나 이(가) 작성한 기사에는 조회수 28,411회 및 좋아요 196개 개의 좋아요가 있습니다.

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] 강의 동영상입니다. 이번 시간에는 이진 트리의 개념에 대해 이해하고 실제로 C언어의 포인터를 이용해 구현한 뒤에 그결과를 확인합니다.

트리는 배열이나 연결리스트로 구현하는 것이 보편적이다. 배열로 트리를 구현할 때는 노드 넘버링을 할 때 통상 인덱스 1부터 시작함에 …

+ 자세한 내용은 여기를 클릭하십시오

Source: chanhuiseok.github.io

Date Published: 9/22/2022

View: 7975

1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다.

+ 여기에 자세히 보기

Source: leejinseop.tistory.com

Date Published: 11/18/2022

View: 7358

이진 트리 노드 구현. 이진 트리는 부모가 왼쪽 자식, 오른쪽 자식을 가지고 있다는 점에서 포인터를 이용해서 구현하면 효과적인 데이터 관리가 가능 …

+ 여기를 클릭

Source: eunjinii.tistory.com

Date Published: 9/24/2021

View: 561

C언어 – 이진 트리, 이진 탐색 트리 구현 (binary tree, binary search tree). by IYK2h 2021. 3. 5. 320×100. 코드 …

+ 자세한 내용은 여기를 클릭하십시오

Source: iyk2h.tistory.com

Date Published: 3/23/2021

View: 1983

알고리즘 끝장내기 | 이진트리란 트리는 노드(Node)와 에지(Edge)로 구성된다. 노드는 동그라미이고 에지는 선이다. 노드는 자식을 가질 수 있다.

+ 여기에 표시

Source: brunch.co.kr

Date Published: 5/21/2022

View: 5954

( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리) 1. … 이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다.

+ 여기에 보기

Source: code-lab1.tistory.com

Date Published: 12/2/2022

View: 8997

포인터로 이진 트리 구현하고 순회하기. … 각 레벨에 노드가 꽉 찬 이진 트리; 각 레벨 단위로 왼쪽에서 오른쪽으로 번호를 붙일 수 있으며, …

+ 자세한 내용은 여기를 클릭하십시오

Source: velog.io

Date Published: 3/2/2021

View: 2314

또한 이진 트리를 구현할 수 있다면 전위 순회, 중위. 순회, 후위 순회까지 다양한 응용이 가능합니다. 따라서 왠만하면 자신만의 이진 트리를 구현한 …

+ 여기에 표시

Source: m.blog.naver.com

Date Published: 6/30/2022

View: 5853

자료구조-트리 (트리, 이진 트리, C로 구현). proqk 2020. 6. 10. 23:58 … 노드의 왼쪽 자식 노드를 루트로 하는 왼쪽 서브트리도 이진 트리.

+ 여기에 표시

Source: foxtrotin.tistory.com

Date Published: 2/1/2021

View: 1266

이 게시물은 스레드 이진 트리를 탐색하고 일반 이진 트리를 스레드 이진 트리로 변환합니다. 스레드된 이진 트리에서 노드의 오른쪽 자식 포인터는 해당 노드의 순서 …

+ 여기를 클릭

Source: www.techiedelight.com

Date Published: 11/19/2021

View: 9784

주제와 관련된 더 많은 사진을 참조하십시오 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

The blog posts on this site are licensed under the Creative Commons Attribution 4.0 International License.

높이가 h, 노드의 개수가 n개일 때(단, n < 2^(h+1) -1), 노드의 위치가 포화 이진 트리의 노드 1번 부터 n번까지의 위치와 완전히 일치하는 이진 트리입니다. 따라서 (n+1)번 부터 (2^(h+1) -1)번까지는 공백 노드가 됩니다. 완전 이진 트리 ③ 편향 이진 트리 이진 트리 중에서 최소 개수의 노드를 가지면서 왼쪽이나 오른쪽 서브 트리만 가지고 있는 트리입니다. 즉 이진 트리의 높이가 h일 때 (h+1)개의 노드를 가지면서 한 쪽으로 치우친 이진 트리를 말합니다. 왼쪽 편향 이진 트리와 오른쪽 편향 이진 트리 5. 이진 트리의 구현 · 순차 자료구조 방식 1차원 배열에서 인덱스 계산을 간단히 하기 위해서 인덱스 0번은 사용하지 않고 비워두고, 인덱스 1번에 루트를 저장합니다. 완전 이진 트리의 배열 표현 1차원 배열을 사용하여 이진 트리를 구현하면 각 노드의 부모 노드와 자식 노드가 저장된 배열 인덱스에 대하여 일정한 규칙을 찾을 수 있습니다. 노드 인덱스 조건 노드 i의 부모 노드 i / 2 i > 1 노드 i의 왼쪽 자식 노드 i * 2 (i * 2) <= n 노드 i의 오른쪽 자식 노드 (i * 2) + 1 (i * 2) + 1 <= n · 연결 자료구조 방식 배열을 이용한 이진 트리의 구현은 인덱스 규칙에 따라 부모 노드와 자식 노드를 찾기 쉽다는 장점이 있습니다. 하지만 메모리 공간의 사용에 있어 완전 이진 트리의 경우에는 최적의 공간 사용이 되지만, 편향 이진 트리의 경우 많은 공간이 낭비됩니다. 따라서 메모리 낭비 문제와 삽입 · 삭제 연산이 비효율적인 순차 자료구조 방식 보다는 연결 자료구조 방식을 많이 사용합니다. 이진 트리의 노드는 왼쪽 자식 노드와 오른쪽 자식 노드를 연결해야 하므로 데이터를 저장하는 데이터 필드, 왼쪽 자식 노드를 연결하는 왼쪽 링크 필드와 오른쪽 자식 노드를 연결하는 오른쪽 링크 필드로 구성된 참조 변수를 사용해야 합니다. public class TreeNode { private Object data; TreeNode left; TreeNode right; public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } 6. 이진 트리의 순회 이진 트리에 있는 모든 노드를 한번씩 모두 방문하여 노드가 가지고 있는 데이터를 처리하는 것을 순회라고 합니다. 선형 자료구조는 순회하는 방법이 한 가지였지만, 트리는 계층적인 구조를 가지고 있기 때문에 여러 가지 순회 방법이 있습니다. 하나의 노드에서 순회를 위해 수행할 수 있는 작업은 (1) 현재 노드를 방문하여 데이터를 읽는 작업, (2) 현재 노드의 왼쪽 서브 트리로 이동하는 작업, (3) 현재 노드의 오른쪽 서브 트리로 이동하는 작업이 있습니다. 그리고 서브 트리를 순회하는 순서는 항상 왼쪽 서브 트리를 먼저 방문하고, 그 후에 오른쪽 서브 트리를 방문하는 것으로 합니다. 따라서 현재 노드를 방문하는 순서에 따라 전위 순회, 중위 순회, 후위 순회로 나눌 수 있습니다. · 전위 순회(Preorder Traversal) 현재 노드를 방문 → 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 preorder(T) if(T != null) then{ visit T.data; preorder(T.left); preorder(T.right); } end preorder() · 중위 순회(Inorder Traversal) 왼쪽 서브 트리 방문 → 현재 노드를 방문 → 오른쪽 서브 트리 방문 inorder(T) if(T != null) then { inorder(T.left); visit T.data; inorder(T.right); } end inorder() · 후위 순회(Postorder Traversal) 왼쪽 서브 트리 방문 → 오른쪽 서브 트리 방문 → 현재 노드를 방문 postorder(T) if(T != null) then { postorder(T.left); postorder(T.right); visit T.data; } end postorder(T) 7. 이진 트리 소스 코드 · TreeNode public class TreeNode { private Object data; // 데이터 필드 TreeNode left; // 왼쪽 링크 필드 TreeNode right; // 오른쪽 링크 필드 public TreeNode(Object data) { this.data = data; this.left = null; this.right = null; } public Object getData() { return this.data; } } · LinkedTree public class LinkedTree { // 이진 트리 노드 생성 public TreeNode makeBT(TreeNode left, Object data, TreeNode right) { TreeNode newNode = new TreeNode(data); newNode.left = left; newNode.right = right; return newNode; } // 전위 순회 public void preorder(TreeNode node) { if (node != null) { System.out.printf("%c", node.getData()); preorder(node.left); preorder(node.right); } } // 중위 순회 public void inorder(TreeNode node) { if (node != null) { inorder(node.left); System.out.printf("%c", node.getData()); inorder(node.right); } } // 후위 순회 public void postorder(TreeNode node) { if (node != null) { postorder(node.left); postorder(node.right); System.out.printf("%c", node.getData()); } } } · MainForLinkedTree public class MainForLinkedTree { public static void main(String[] args) { LinkedTree t = new LinkedTree(); TreeNode n7 = t.makeBT(null, 'D', null); TreeNode n6 = t.makeBT(null, 'C', null); TreeNode n5 = t.makeBT(null, 'B', null); TreeNode n4 = t.makeBT(null, 'A', null); TreeNode n3 = t.makeBT(n6, '-', n7); TreeNode n2 = t.makeBT(n4, '+', n5); TreeNode n1 = t.makeBT(n2, '*', n3); // 전위 순회 System.out.printf("preorder: "); t.preorder(n1); // 중위 순회 System.out.printf(" inorder: "); t.inorder(n1); // 후위 순회 System.out.printf(" postorder: "); t.postorder(n1); } } · 실행 결과 //binary search tree #include #include typedef struct node { int data; struct node* left; struct node* right; }node; node* root; node* insert(node* root,int data) { if(root == NULL) { root = (node*)malloc(sizeof(node)); root->right = root->left = NULL; root->data = data; return root; } else { if(data < root->data) root->left = insert(root->left,data); else root->right = insert(root->right,data); } return root; } node* fMin(node* root) { node* min = root; while(min->left!=NULL) min = min->left; return min; } node* delete(node* root,int data) { node *tmproot = NULL; if(root==NULL) return NULL; if(data < root->data) root->left = delete(root->left,data); else if(data > root->data) root->right = delete(root->right,data); else { if(root -> left!=NULL && root->right != NULL) { tmproot = fMin(root->right); root->data = tmproot->data; root->right = delete(root->right,tmproot->data); } else { tmproot = (root->left == NULL) ? root->right : root->left; free(root); return tmproot; } } return root; } void print(node* root) { if(root==NULL) return; printf(“%d “,root->data); print(root->left); print(root->right); } //전위 순회 void preorderPrint(node* root) { if(root==NULL) return; printf(“%d “,root->data); print(root->left); print(root->right); } //중위 순회 void inorderPrint(node* root) { if(root==NULL) return; print(root->left); printf(“%d “,root->data); print(root->right); } //후위 순회 void postorderPrint(node* root) { if(root==NULL) return; print(root->left); print(root->right); printf(“%d “,root->data); } int main() { root = insert(root,5); root = insert(root,1); root = insert(root,9); printf(“preorder : “); preorderPrint(root); printf(”

이진탐색트리(Binary Search Tree)이란?

이진탐색트리란 다음과 같은 특징을 갖는 이진트리를 말한다. ( #이진트리 – 각 노드의 자식 노드가 최대 2개인 트리)

1. 각 노드에 중복되지 않는 키(key)가 있다.

2. 루트노드의 왼쪽 서브 트리는 해당 노드의 키보다 작은 키를 갖는 노드들로 이루어져 있다.

3. 루트노드의 오른쪽 서브 트리는 해당 노드의 키보다 큰 키를 갖는 노드들로 이루어져 있다.

4. 좌우 서브 트리도 모두 이진 탐색 트리여야 한다.

예를 들어 다음과 같은 트리가 이진탐색트리이다.

이진탐색트리

이진 탐색 트리의 특징

이진 탐색 트리는 기존 이진트리보다 탐색이 빠르다. 이진 탐색 트리의 탐색 연산은 트리의 높이(height)가 h라면 O(h)의 시간 복잡도를 갖는다. 이러한 효율적인 탐색이 가능한 이유는 탐색 과정에서 자세히 알아보자. 혹시라도 트리에 관한 용어가 헷갈린다면 다음 포스팅을 참고하자.

이진 탐색 트리 탐색(Search)

이진 탐색 트리의 탐색은 다음과 같은 과정을 거친다.

1. 루트 노드의 키와 찾고자 하는 값을 비교한다. 찾고자 하는 값이라면 탐색을 종료한다.

2. 찾고자 하는 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리로 탐색을 진행한다.

3. 찾고자 하는 값이 루트노드의 키보다 크다면 오른쪽 서브트리로 탐색을 진행한다.

위 과정을 찾고자 하는 값을 찾을 때까지 반복해서 진행한다. 만약 값을 찾지 못한다면 그대로 종료한다.

이러한 탐색 과정을 거치면 최대 트리의 높이(h)만큼의 탐색이 진행되게 된다. 예를 들어보자.

탐색과정

위와 같은 트리에서 키가 5인 노드를 찾고자 한다면, 가장 먼저 루트 노드와의 비교가 이루어진다.

5가 7보다 작으므로 왼쪽 서브 트리로의 탐색이 이루어지고, 이후 5가 3보다 크므로 오른쪽 서브트리로 탐색이 이루어진다. 마지막으로 키가 5인 노드를 찾았으므로 탐색이 종료된다. 즉 트리의 높이인 3번 만큼의 탐색이 이루어졌다. 만약 8을 찾는다면 2번의 연산이 진행되었을 것이다. 즉, 트리 안의 값을 찾는다면 무조건 트리의 높이(h) 이하의 탐색이 이루어지게 된다.

트리 안에 찾고자 하는 값이 없더라도 최대 h 번 만큼만의 탐색이 진행된다. 예를 들어 위 트리에서 6이라는 값을 찾는다고 하면 위 그림과 같은 과정을 거치고 탐색이 종료된다. (직접 위 그림에서 과정을 생각해보자) 마지막으로 탐색하게 되는 5를 키로 갖는 노드에서 6은 5보다 크므로 오른쪽 서브트리로 탐색을 진행해야 하는데 오른쪽 서브 트리가 없으므로 탐색이 종료되는 것이다.

이진 탐색 트리 탐색 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TreeNode * search(TreeNode * root, int key){ if (root = = NULL ){ // 값을 찾지 못한 경우 return NULL ; } if (key = = root – > key){ // 값을 찾음 return root; } else if (key < root - > key){ // 왼쪽 서브트리 탐색 search(root – > left, key); } else if (key > root – > key){ // 오른쪽 서브트리 탐색 search(root – > right, key); } } Colored by Color Scripter cs

이진 탐색 트리의 탐색을 C언어로 구현하면 재귀를 이용할 수 있다. 재귀가 아닌 for문을 통해서도 구현이 가능하지만 직관적으로 이해가 쉽게 재귀로 구현하였다. 이진 탐색 트리 삽입(insert) 이진 탐색트리의 삽입은 다음과 같은 과정을 거친다. 탐색과 과정이 비슷하다.

1. 삽입할 값을 루트 노드와 비교해 같다면 오류를 발생한다( 중복 값 허용 X )

2. 삽입할 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리를 탐색해서 비어있다면 추가하고, 비어있지 않다면 다시 값을 비교한다.

3. 삽입할 값이 루트노드의 키보다 크다면 오른쪽 서브트리를 탐색해서 비어있다면 추가하고, 비어있지 않다면 다시 값을 비교한다.

예를 들어 아래와 같은 트리에 6을 키로 가진 노드를 추가한다고 하자.

삽입과정

탐색과 비슷하게 삽입하고자 하는 값을 계속해서 비교해서 삽입할 위치를 찾는다.

삽입완료

삽입할 위치가 5의 오른쪽 서브 트리인 것을 찾았으므로, 5의 오른쪽 자식으로 6을 추가하면 된다.

이진 탐색 트리 삽입 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 void insert(TreeNode * * root, int key){ TreeNode * ptr; // 탐색을 진행할 포인터 TreeNode * newNode = (TreeNode * ) malloc ( sizeof (TreeNode)); // newNode 생성 newNode – > key = key; newNode – > left = newNode – > right = NULL ; if ( * root = = NULL ){ // 트리가 비어 있을 경우 * root = newNode; return ; } ptr = * root; // root 노드부터 탐색 진행 while (ptr){ if (key = = ptr – > key){ // 중복값 printf ( “Error : 중복값은 허용되지 않습니다!

” ); return ; } else if (key < ptr - > key){ // 왼쪽 서브트리 if (ptr – > left = = NULL ){ // 비어있다면 추가 ptr – > left = newNode; return ; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > left; } } else { // key > ptr->key 오른쪽 서브트리 if (ptr – > right = = NULL ){ // 비어있다면 추가 ptr – > right = newNode; return ; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > right; } } } } Colored by Color Scripter cs

이진 탐색 트리의 삭제(delete)

이진탐색트리의 삭제는 삽입보다 조금 더 복잡하다. 이진 탐색 트리에서 특정 노드를 삭제할 때 아래와 같은 3가지 상황을 나누어 구현해야 한다.

1. 삭제하려는 노드가 단말 노드(leaf node) 일 경우

2. 삭제하려는 노드의 서브 트리가 하나인 경우(왼쪽 혹은 오른쪽 서브 트리)

3. 삭제하려는 노드의 서브 트리가 두 개인 경우

1. 삭제하려는 노드가 단말 노드(leaf node) 일 경우

단말노드의 삭제

자식이 없는 단말 노드의 삭제는 간단하다. 삭제할 노드의 부모 노드가 있다면 부모 노드의 자식 노드를 NULL로 만들고, 삭제할 노드를 삭제(메모리 해제) 해주면 된다.

단말노드의 삭제 완료

2. 삭제하려는 노드의 서브 트리가 하나인 경우(왼쪽 혹은 오른쪽 서브 트리)

노드 삭제 과정

삭제하려는 노드의 서브 트리가 하나인 경우도 간단하다. 삭제할 노드의 자식노드를 삭제할 노드의 부모노드가 가리키게 하고 해당 노드를 삭제하면 된다.

3. 삭제하려는 노드의 서브트리가 두 개인 경우

노드 삭제 과정

삭제하려는 노드의 서브트리가 두 개인 경우는 가장 복잡하다. 이 경우 두 가지 방법을 사용할 수 있다.

1) 삭제할 노드 왼쪽 서브 트리의 가장 큰 자손을 해당 노드의 자리에 올린다.

노드 삭제 과정

위와 같이 삭제할 노드의 왼쪽 서브 트리에서 가장 큰 자손을 해당 노드의 자리에 올리면, 이진 탐색 트리의 조건을 만족하면서 트리가 유지되는 것을 확인할 수 있다. 또한 자리를 옮기면서 다른 노드들(4번노드)도 자리가 적절히 이동한 것을 확인 할 수 있다.

2) 삭제할 노드 오른쪽 서브 트리의 가장 작은 자손을 해당 노드의 자리에 올린다.

노드 삭제 과정

위와 같이 삭제할 노드의 오른쪽 서브 트리에서 가장 작은 자손을 해당 노드의 자리에 올리면, 이진 탐색 트리의 조건을 만족하면서 트리가 유지되는 것을 확인할 수 있다. 또한 자리를 옮기면서 다른 노드들(10번노드)도 자리가 적절히 이동한 것을 확인 할 수 있다.

이진 탐색 트리의 삭제 소스코드

그림으로 보면 이해가 쉬우나, 직접 구현하려면 헷갈리는 부분이 많을 것이다. 아래 코드를 보며 자세히 이해해 보자.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 TreeNode * delete_node(TreeNode * root, int key){ TreeNode * del = NULL ; // 삭제할 노드 TreeNode * parent = NULL ; // 삭제할 노드의 부모 노드 TreeNode * successor = NULL ; // 삭제할 노드의 왼쪽 서브트리에서 가장 큰 노드 TreeNode * predecessor = NULL ; // successor의 부모노드 TreeNode * child = NULL ; // 삭제할 노드의 자식 노드 del = root; while (del ! = NULL ){ // 삭제할 노드 탐색 if (key = = del – > key){ break ; } parent = del; if (key < del - > key){ del = del – > left; } else { del = del – > right; } } if (del = = NULL ){ printf ( “Error : 존재하지 않는 키

” ); return root; } if (del – > left = = NULL & & del – > right = = NULL ){ // 삭제할 노드의 자식노드가 없는 경우 if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽노드가 삭제할 노드일 때 parent – > left = NULL ; } else { // 오른쪽 일 때 parent – > right = NULL ; } } else { // 부모노드가 없는 경우 = root 노드 root = NULL ; } } else if (del – > left ! = NULL & & del – > right ! = NULL ){ // 삭제할 노드의 자식 노드가 2개인 경우 predecessor = del; successor = del – > left; while (successor – > right ! = NULL ){ // 왼쪽 서브트리에서 가장 큰 값 찾기 predecessor = successor; successor = successor – > right; } predecessor – > right = successor – > left; // successor의 자식 노드 위치 변경 successor – > left = del – > left; // successor를 삭제할 노드의 위치로 옮긴 것과 같음 successor – > right = del – > right; if (parent ! = NULL ){ // 삭제할 노드의 부모노드가 있을 때 if (parent – > left = = del){ parent – > left = successor; } else { parent – > right = successor; } } else { root = successor; } } else { // 삭제할 노드의 자식 노드가 1개인 경우 if (del – > left ! = NULL ){ // 왼쪽 노드 child = del – > left; } else { // 오른쪽 노드 child = del – > right; } if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽 노드로 삭제할 노드의 자식노드 연결 parent – > left = child; } else { // 부모노드의 오른쪽 노드로 삭제할 노드의 자식노드 연결 parent – > right = child; } } else { root = child; } } free (del); // 메모리해제 return root; } Colored by Color Scripter cs 전체 소스코드

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 #include < stdio.h > #include < stdlib.h > typedef struct _TreeNode{ int key; // key 값 _TreeNode * left; // left child _TreeNode * right; // right child }TreeNode; TreeNode * search(TreeNode * root, int key){ if (root = = NULL ){ // 값을 찾지 못한 경우 printf ( “Error : 값을 찾을 수 없습니다

” ); return root; } if (key = = root – > key){ // 값을 찾음 return root; } else if (key < root - > key){ // 왼쪽 서브트리 탐색 search(root – > left, key); } else if (key > root – > key){ // 오른쪽 서브트리 탐색 search(root – > right, key); } } TreeNode * insert(TreeNode * root, int key){ TreeNode * ptr; // 탐색을 진행할 포인터 TreeNode * newNode = (TreeNode * ) malloc ( sizeof (TreeNode)); // newNode 생성 newNode – > key = key; newNode – > left = newNode – > right = NULL ; if (root = = NULL ){ // 트리가 비어 있을 경우 root = newNode; return root; } ptr = root; // root 노드부터 탐색 진행 while (ptr){ if (key = = ptr – > key){ // 중복값 printf ( “Error : 중복값은 허용되지 않습니다!

” ); return root; } else if (key < ptr - > key){ // 왼쪽 서브트리 if (ptr – > left = = NULL ){ // 비어있다면 추가 ptr – > left = newNode; return root; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > left; } } else { // key > ptr->key 오른쪽 서브트리 if (ptr – > right = = NULL ){ // 비어있다면 추가 ptr – > right = newNode; return root; } else { // 비어있지 않다면 다시 탐색 진행 ptr = ptr – > right; } } } } TreeNode * delete_node(TreeNode * root, int key){ TreeNode * del = NULL ; // 삭제할 노드 TreeNode * parent = NULL ; // 삭제할 노드의 부모 노드 TreeNode * successor = NULL ; // 삭제할 노드의 왼쪽 서브트리에서 가장 큰 노드 TreeNode * predecessor = NULL ; // successor의 부모노드 TreeNode * child = NULL ; // 삭제할 노드의 자식 노드 del = root; while (del ! = NULL ){ // 삭제할 노드 탐색 if (key = = del – > key){ break ; } parent = del; if (key < del - > key){ del = del – > left; } else { del = del – > right; } } if (del = = NULL ){ printf ( “Error : 존재하지 않는 키

” ); return root; } if (del – > left = = NULL & & del – > right = = NULL ){ // 삭제할 노드의 자식노드가 없는 경우 if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽노드가 삭제할 노드일 때 parent – > left = NULL ; } else { // 오른쪽 일 때 parent – > right = NULL ; } } else { // 부모노드가 없는 경우 = root 노드 root = NULL ; } } else if (del – > left ! = NULL & & del – > right ! = NULL ){ // 삭제할 노드의 자식 노드가 2개인 경우 predecessor = del; successor = del – > left; while (successor – > right ! = NULL ){ // 왼쪽 서브트리에서 가장 큰 값 찾기 predecessor = successor; successor = successor – > right; } predecessor – > right = successor – > left; // successor의 자식 노드 위치 변경 successor – > left = del – > left; // successor를 삭제할 노드의 위치로 옮긴 것과 같음 successor – > right = del – > right; if (parent ! = NULL ){ // 삭제할 노드의 부모노드가 있을 때 if (parent – > left = = del){ parent – > left = successor; } else { parent – > right = successor; } } else { root = successor; } } else { // 삭제할 노드의 자식 노드가 1개인 경우 if (del – > left ! = NULL ){ // 왼쪽 노드 child = del – > left; } else { // 오른쪽 노드 child = del – > right; } if (parent ! = NULL ){ // 부모노드가 있는 경우 if (parent – > left = = del){ // 부모노드의 왼쪽 노드로 삭제할 노드의 자식노드 연결 parent – > left = child; } else { // 부모노드의 오른쪽 노드로 삭제할 노드의 자식노드 연결 parent – > right = child; } } else { root = child; } } free (del); // 메모리해제 return root; } void print_tree(TreeNode * root){ if (root = = NULL ){ return ; } printf ( “%d

” , root – > key); print_tree(root – > left); print_tree(root – > right); } int main(){ TreeNode * root = NULL ; TreeNode * ptr = NULL ; root = insert(root, 7 ); root = insert(root, 3 ); root = insert(root, 8 ); root = insert(root, 1 ); root = insert(root, 5 ); root = insert(root, 4 ); root = insert(root, 10 ); print_tree(root); printf ( ”

” ); ptr = search(root, 7 ); printf ( “%d

” , ptr – > key); root = delete_node(root, 7 ); ptr = search(root, 7 ); return 0; } Colored by Color Scripter cs

실행결과

반응형

스위프트로 구현하는 자료구조 7: 트리와 이진 트리(Binary Tree)

글 작성자: 개발하는 훈이

트리의 정의

먼저, 트리에 대해서 정의해보면, 트리는 몇가지 조건을 만족하는 그래프입니다.

1) 트리의 간선에는 방향이 없습니다. 즉, 트리는 무방향 그래프입니다.

2) 트리를 구성하는 모든 노드는 연결되어 있는 연결 그래프입니다. 연결된 간선 중 하나만 삭제해도 연결 그래프가 깨집니다.

-> 여기서 연결그래프란 그래프의 임의의 노드 사이에 항상 경로가 존재함을 의미합니다. 어떤 노드로 가는 경로가 없어지면 해당 노드는 트리에 포함될 수 없겠죠?

3) 트리를 구성하는 간선의 개수는 항상 노드의 개수보다 하나 적습니다. 따라서 사이클이 발생하지 않습니다.

이진 트리 (Binary Tree)

이진 트리는 트리를 구성하는 각 노드가 최대 두 개의 자식 노드를 가지는 트리를 의미합니다.

이진 트리의 종류

이진 트리는 형태에 따라서 몇 가지 종류로 나눌 수 있습니다.

포화 이진 트리

포화 이진 트리는 위 그림처럼 마지막 리프노드를 가진 레벨이 노드를 더 추가할 수 있는 공간없이 가득 차 있는 이진 트리를 말합니다. 따라서 포화 이진 트리의 노드 개수는 항상 트리의 높이 h에 대해 2^h – 1 개가 됩니다.

완전 이진 트리

완전 이진 트리는 모든 레벨이 왼쪽부터 채워져있는 트리를 의미합니다. 위 그림 처럼 한 레벨이 가득 채워지지 않아도 8번 노드가 가장 왼쪽에 채워져 있기 때문에 완전 이진 트리가 됩니다.

반면에 이런 경우는 왼쪽에 아직 채워지지 않은 공간이 있음에도 중간부터 노드가 들어가있기 때문에 완전 이진 트리가 될 수 없습니다.

가장 왼쪽부터 차례대로 채우는 완전 이진 트리 특성 때문에 완전 이진 트리는 배열로 쉽게 표현할 수 있습니다.

이렇게 배열의 0번째 요소를 비워둔 채로 1번 인덱스를 루트노드로 만들면 오른쪽 자식 노드는 현재 인덱스 i에 대해 i * 2 로 찾아갈 수 있고, 오른쪽 자식 노드는 i * 2 + 1 로 찾아갈 수 있습니다.

편향 이진 트리

편향 이진 트리는 트리의 노드가 한쪽 자식 노드로만 계속 연결되면서 노드의 개수는 적지만 트리의 높이는 커지는 모습의 트리를 의미합니다.

이진 트리 순회

이진 트리는 트리와 트리에 포함된 서브 트리들의 루트 노드를 언제 방문하는지에 따라 세 가지 방법으로 트리의 전체 노드를 순회할 수 있습니다.

전위 순회

전위 순회는 다른 노드들을 방문 하기 이전에 루트노드를 먼저 방문하는 순회방식입니다. 루트 -> 왼쪽 -> 오른쪽 순으로 트리의 노드들을 방문한다고 생각하면 됩니다.

이 트리를 전위 순회하면 A->B->D->E->C->F->G 의 순서대로 방문하게 됩니다. 보이듯이 어떤 노드의 서브트리를 순회할 때는 해당 노드의 왼쪽의 모든 서브트리가 완료되어야 오른쪽 서브트리를 순회하게 됩니다.

중위 순회

중위 순회는 루트 노드를 중간에 방문하는 순회 방법입니다. 따라서 왼쪽->루트->오른쪽의 순서대로 노드를 방문하게 됩니다.

위 예시와 동일한 트리를 중위 순회하게 되면 D->B->E->A->F->C->G의 순서대로 노드를 방문합니다.

후위 순회

후위 순회는 루트 노드를 가장 마지막으로 방문하는 순회 방법입니다. 왼쪽 서브트리의 탐색이 항상 오른쪽보다 선행되기 때문에 왼쪽->오른쪽->루트의 순서대로 노드를 방문하게 됩니다.

동일한 트리를 후위 순회하면 D->E->B->F->G->C->A의 순서대로 방문하게 됩니다. 서브트리를 구성하는 루트 노드는 자신의 왼쪽과 오른쪽 자식노드가 모두 방문 된 이후에 방문됩니다.

완전 이진 트리 구현하기

이전에 힙을 구현하면서 이미 완전 이진트리를 구현했지만, 이번에는 링크드 리스트로 구현해 전위, 중위, 후위 순회까지 구현해보도록 하겠습니다.

뼈대 만들기

TreeNode

먼저 트리의 노드가 될 자료구조부터 정의하겠습니다.

import Foundation final class TreeNode { let data: T var leftChild: TreeNode? var rightChild: TreeNode? init(data: T) { self.data = data } var asString:String { return treeString(self){(“\($0.data)”,$0.leftChild,$0.rightChild)} } }

이렇게 구성했는데요, data에는 트리에 담을 데이터를 넣어주고, 자신의 왼쪽 자식 노드와 오른쪽 자식 노드의 참조값을 저장할 수 있도록 했습니다.

asString 프로퍼티는 트리를 엄청 예쁘게 출력해주는 treeString 메서드를 호출하는데 이건 스택 오버플로우에서 진짜 잘 만들어주신 분이 계셔서 그대로 사용했어요!

이 질문에 대한 답변에 메서드가 정의되어 있구요,

적용하면 이렇게 예쁘게 콘솔에 트리가 출력됩니다!

노드 추가

이번 구현에서는 다른 연산은 구현하지 않고(이진 트리에 대해서는 정형화된 방법이 없기 때문에) 노드를 추가하는 연산만 구현한 뒤에 순회 함수를 구현하고 호출만 해보려고 합니다.

완전 이진트리이기 때문에 항상 가장 왼쪽 부터 차례대로 노드를 추가해주어야겠죠?

private func add(newNode: TreeNode, to node: TreeNode) { var queue = Queue> () queue.push(root!) while !queue.isEmpty { let now = queue.pop() if now?.leftChild == nil { now?.leftChild = newNode return } if now?.rightChild == nil { now?.rightChild = newNode return } queue.push(now!.leftChild!) queue.push(now!.rightChild!) } }

그래서 이렇게 BFS를 사용해서 트리를 순회해주고, 아직 자식 노드가 완전히 채워지지 않은 노드를 만나면 왼쪽 자식 노드부터 채워주는 방식으로 구현했습니다. 사실 그래프에 대한 포스트를 안써서 BFS를 여기서 소개하는게 맞을까 싶지만.. BFS에 대한 내용은 여기에 정리되어 있으니 어떻게 동작하는지 잘 모르시겠다면 참고하시면 좋을 것 같아요!

트리 순회

트리의 순회는 재귀적인 방식으로 이루어집니다. 그런데 생각해보면 사실 왼쪽 자식 노드는 항상 오른쪽 자식 노드보다 먼저 방문 되니, 루트노드를 언제 방문하는지만 다르게 구현해주면 될 것 같습니다.

먼저 전위 순회 결과를 출력하는 코드입니다!

private func printPreorder(node: TreeNode?) { guard let node = node else { return } print(node.data, terminator: ” “) self.printPreorder(node: node.leftChild) self.printPreorder(node: node.rightChild) }

재귀적으로 전위 순회를 진행하면서 출력을 해주는데요, 루트 노드를 먼저 출력해주고 왼쪽 자식 노드가 루트 노드인 서브트리로 이동해 순회를 모두 마친뒤, 오른쪽 자식 노드가 루트 노드인 서브트리로 이동해 순회를 마치고 돌아오는 코드입니다.

이런 트리가 있다면 먼저 A를 출력해주고, B를 루트로 가지는 서브트리로 이동할 테니 재귀적으로 호출된 새로운 함수는

이 서브트리를 가지고 다시 똑같은 로직을 수행합니다. 따라서 이제 B를 출력하고 왼쪽 자식노드를 루트로 가지는 서브트리로 재귀 호출을 하니

이번엔 자식 노드가 없는 리프노드를 가지고 로직을 수행합니다. 여기서 D를 출력 하고 재귀적으로 한 번 더 호출하지만 nil이 루트이기 때문에 함수가 리턴되면서 모든 왼쪽 서브트리의 순회를 마치게 됩니다.

이 작업이 전체 트리에 대해서 완료되면 전위 순회의 결과가 출력됩니다.

중위 순회

로직은 동일하니 그림은 이제 생략하겠습니다..

private func printInorder(node: TreeNode?) { guard let node = node else { return } self.printInorder(node: node.leftChild) print(node.data, terminator: ” “) self.printInorder(node: node.rightChild) }

중위 순회의 로직은 전위 순회와 거의 동일한데요, 단순히 루트 노드의 출력이 왼쪽 자식 노드를 루트로 가지는 서브트리의 순회가 모두 끝나야 이루어진다는 것만 다릅니다.

후위 순회

private func printPostorder(node: TreeNode?) { guard let node = node else { return } self.printPostorder(node: node.leftChild) self.printPostorder(node: node.rightChild) print(node.data, terminator: ” “) }

후위 순회도 마찬가지입니다. 후위 순회는 왼쪽와 오른쪽 자식 노드의 순회가 모두 끝난 뒤에 루트노드를 출력하기 때문에 루트노드를 출력하는 코드를 재귀 함수의 가장 뒤에 넣어주는 것만 변경되었습니다.

전체 코드

자료구조 시리즈의 코드들은 이 레포에서 모두 확인할 수 있어요!

키워드에 대한 정보 이진 트리 구현

다음은 Bing에서 이진 트리 구현 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ]

  • 이진트리
  • 순회알고리즘
  • 나동빈
  • 순회
  • 나동빈강좌
  • 알고리즘강좌
  • 알고리즘강의

20강 #- #이진 #트리의 #구현과 #순회 #알고리즘 #[ #실전 #알고리즘 #강좌(Algorithm #Programming #Tutorial) ##20 #]


YouTube에서 이진 트리 구현 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 20강 – 이진 트리의 구현과 순회 알고리즘 [ 실전 알고리즘 강좌(Algorithm Programming Tutorial) #20 ] | 이진 트리 구현, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  뿌린 대로 거둔다 사자 성어 | 속담이 야호 - 뿌린 대로 거둔다_#001 빠른 답변

Leave a Reply

Your email address will not be published. Required fields are marked *