C 언어 데이터 구조 - 트리 구조의 트리 및 이진 트리

머리말

이진 트리의 용도는 무엇입니까?
이진 트리가 널리 사용됩니다.

운영 체제 소스 프로그램에서 트리와 포리스트는 파일 시스템을 구성하는 데 사용됩니다. 윈도우나 리눅스와 같이 우리가 보는 파일 관리 시스템은 모두 트리 구조입니다. C 컴파일러의 소스 코드와 같은 컴파일 시스템에서는 이진 트리의 중위 순회 형식을 사용하여 표현식을 C 언어로 저장합니다. 둘째, 이진 트리 자체의 응용이 많은데, 예를 들어 JPEG 인코딩 및 디코딩 시스템(압축 및 압축 해제 프로세스)의 소스 코드에 Huffman 이진 트리가 사용되며 프로세서를 작성하기 위한 명령도 사용할 수 있습니다. 이진 트리는 가변 길이 명령 시스템을 형성합니다.또한 이진 정렬 트리는 데이터 정렬 및 빠른 조회에 사용됩니다.

목차

1. 트리 개념 및 구조
2. 이진 트리 개념 및 구조
3. 이진 트리 체인 구조 구현

1. 트리 구조 및 개념(이해)

1.1 트리의 개념

트리는 n(n>=0) 유한 노드로 구성된 계층적 관계 집합인 비선형 데이터 구조입니다. 뿌리가 위를 향하고 잎이 아래를 향하는 거꾸로 된 나무처럼 보인다고 하여 나무라고 합니다.
루트 노드라는 특수 노드가 있는데 루트 노드에는 선행 노드가 없습니다
. 루트 노드를 제외하고 다른 노드는 M(M>0) 분리 집합 T1, T2, ..., Tm으로 나뉩니다. 여기서 각 집합은 Ti(1<= i <= m)는 트리와 구조가 유사한 하위 트리입니다. 각 하위 트리의 루트 노드에는 하나의 선행 노드만 있고 0개 이상의 후속 노드가 있을 수 있으므로
트리는 재귀적으로 정의됩니다.

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
노드의 차수 : 노드에 포함된 하위 트리의 수를 노드의 차수라고 함 위 그림과 같이 A는 6-
리프 노드 또는 터미널 노드 : 차수가 0인 노드를 리프라고 함 위 그림과 같이 B, C, H, I... 등의 노드는 잎 노드,
비말단 노드 또는 가지 노드 : 차수가 0이 아닌 노드, 위 그림과 같이 노드는 다음과 같습니다. D, E, F, G...가 분기 노드이므로
부모 노드 또는 부모 노드 : 노드에 자식 노드가 포함되어 있으면 이 노드를 자식 노드의 부모 노드라고 합니다. B의 부모 노드 자식 노드
또는 자식 노드 : 노드에 포함된 하위 트리의 루트 노드를 해당 노드의 자식 노드라고 하며 위 그림과 같이 B A의 자식 노드입니다. 형제 노드
: 노드 같은 부모 노드를 형제 노드라고 하며, 위 그림과 같이 B와 C는
형제 노드 트리의 차수 입니다 . 트리에서 가장 큰 노드의 차수를 트리 차수라고 합니다. : 트리의 레벨은 6개
노드 : 루트 정의부터 시작하여 루트가 첫 번째 레벨, 루트의 자식 노드가 두 번째 레벨 등
트리의 높이 또는 깊이 : 최대 트리의 노드 레벨, 위와 같이 그림: 트리의 높이는 4
노드 조상 입니다: 루트에서 노드의 가지에 있는 모든 노드까지, 위 그림과 같이: A는 모든 노드의 조상 후손입니다
. 노드를 루트로 하는 하위 트리의 모든 노드를 노드의 자손이라고 합니다. 위의 그림과 같이 모든 노드는 A
Forest 의 후손 임 : m(m>0) 개의 분리된 트리의 집합을 포리스트라고 함 (데이터 구조에서 학습 및 검색의 본질은
포리스트임)

1.2 트리 표현

트리 구조는 선형 테이블보다 복잡하고 저장 및 표현이 더 번거롭습니다.실제로 트리를 표현하는 방법에는 부모 표현, 자식 표현, 자식 형제 표현 등이 있습니다. 여기서 우리는 가장 일반적으로 사용되는 남동생 표기법을 이해합니다 .

typedef int DataType;
struct Node
{
    
    
  struct Node* _firstChild1;   // 第一个孩子结点
  struct Node* _pNextBrother;  // 指向其下一个兄弟结点
  DataType _data;        // 结点中的数据域
};

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

1.3 실제 트리 적용(파일 시스템의 디렉토리 트리 구조를 나타냄)

여기에 이미지 설명 삽입

2. 이진 트리의 개념과 구조

2.1 개념

이진 트리는 비어 있거나 루트 노드와 왼쪽 및 오른쪽 하위 트리라고 하는 두 개의 이진 트리로 구성된 유한한 노드 집합입니다.
이진 트리의 특징:

  1. 각 노드에는 최대 두 개의 하위 트리가 있습니다. 즉, 이진 트리에는 차수가 2보다 큰 노드가 없습니다.
  2. 이진 트리의 하위 트리는 좌우로 나뉘며 하위 트리의 순서는 뒤바뀔 수 없습니다.

2.2 실제 이진 트리:

여기에 이미지 설명 삽입

2.3 데이터 구조의 이진 트리:

여기에 이미지 설명 삽입

2.4 특수 이진 트리:

  1. 완전 이진 트리: 이진 트리, 각 계층의 노드 수가 최대값에 도달하면 이 이진 트리는 완전 이진 트리입니다. 즉, 이진 트리에 K개의 레이어가 있고 총 노드 수가 (2^k) -1이면 완전 이진 트리입니다.
  2. 완전한 이진 트리: 완전한 이진 트리는 매우 효율적인 데이터 구조이며 완전한 이진 트리는 완전한 이진 트리에서 파생됩니다. K와 n 노드의 깊이를 가진 이진 트리의 경우 각 노드가 깊이가 있는 전체 이진 트리에서 1부터 n까지 번호가 매겨진 노드와 일대일 대응을 갖는 경우에만 완전한 이진 트리라고 합니다. K의 완전 이진 트리는 특수한 종류의 완전 이진 트리입니다.

여기에 이미지 설명 삽입

2.5 이진 트리의 저장 구조

이진 트리는 일반적으로 순차 구조와 체인 구조의 두 가지 구조를 사용하여 저장할 수 있습니다.
이진 트리의 속성

  1. 루트 노드의 레이어 수가 1로 지정된 경우 비어 있지 않은 이진 트리의 i번째 레이어에는 최대 2^(i-1)개의 노드가 있습니다 .
  2. 루트 노드의 레이어 수를 1로 지정하면 깊이가 h인 이진 트리의 최대 노드 수는 2^h-1입니다.
  3. 임의의 이진 트리에서 차수가 0이고 잎 노드의 수가 n0이고 차수가 2인 가지 노드의 수가 n2이면 n0=n2+1
  4. 루트 노드의 계층 수를 1로 지정하면 n개의 노드가 있는 전체 이진 트리의 깊이, h=LogN

2.5.1 순차 저장:

순차 구조 저장은 저장을 위해 배열을 사용하는 것입니다 . 일반적으로 배열은 완전한 이진 트리가 아닌 경우 공간을 낭비하기 때문에 완전한 이진 트리를 나타내는 데만 적합합니다. 실제로는 힙만 스토리지에 어레이를 사용합니다. 이진 트리 순차 저장소는 물리적으로 배열이고 논리적으로 이진 트리입니다 .

여기에 이미지 설명 삽입

2.5.2 체인 스토리지

이진 트리의 연결 저장 구조는 이진 트리를 나타내기 위해 연결 목록, 즉 요소들의 논리적 관계를 나타내기 위해 연결을 사용함을 의미한다. 일반적인 방법은 연결 리스트의 각 노드가 데이터 필드와 좌우 포인터 필드의 3개 필드로 구성되고 왼쪽 및 오른쪽 포인터를 사용하여 왼쪽 자식
및 노드의 오른쪽 자식이 있습니다. 사슬 구조는 다시 이진 사슬과 삼중 사슬로 나뉩니다.현재 우리는 일반적으로 우리 연구에서 이진 사슬을 사용합니다.나중에 과정은 삼중 사슬을 사용할 레드-블랙 트리와 같은 고급 데이터 구조를 배울 것입니다.

여기에 이미지 설명 삽입
아래에서는 이진 트리를 구현하기 위해 이진 연결 목록을 사용합니다.

//二叉树结构的定义
typedef char BTDataType;

typedef struct BinaryTreeNode
{
    
    		
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;

머리말

//先序
void PrevOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("NULL ");
		return;
	}
	printf("%c ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

순서대로

//中序
void InOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}

후속

//后序
void PostOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);
}

노드 수 찾기

//节点个数
int BTNodeSize(BTNode* root)
{
    
    
	return root == NULL ? 0 : BTNodeSize(root->left) + BTNodeSize(root->right) + 1;
}

잎의 수

//叶子数
int LeafNodeSize(BTNode* root)
{
    
    
	//空节点
	if (root == NULL)
	{
    
    
		return 0;
	}
	//叶子节点
	if (root->left == NULL && root->right==NULL)
	{
    
    
		return 1;
	}
	//既不是叶子节点也不是空节点

	return LeafNodeSize(root->left) + LeafNodeSize(root->right);
}

대기열을 사용하여 이진 트리를 트래버스하기 위한 너비 우선 검색 구현

void LevelOrder(BTNode* root)
{
    
    
	Queue q;
	QueueInit(&q);
	if(root)
	QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
    
    
		BTNode* Front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", Front -> data);
		if (Front->left)
		{
    
    
			QueuePush(&q, Front->left);
		}
		if (Front->right)
		{
    
    
			QueuePush(&q, Front->right);
		}

	}
	printf("\n");
	QueueDestroy(&q);

}

Queue.h

#pragma once

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
struct BinaryTreeNode;
typedef struct BinaryTreeNode* QDataType;

typedef struct QueueNode
{
    
    
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
    
    
	QNode* head;
	QNode* tail;
}Queue;

//初始化
void QueueInit(Queue* pq);

//销毁队列
void QueueDestroy(Queue* pq);

//入队列
void QueuePush(Queue* pq, QDataType x);

//出队列
void QueuePop(Queue* pq);

//取队列的队头元素
QDataType QueueFront(Queue* pq);

//取队列的队尾元素
QDataType QueueBack(Queue* pq);

//返回队列长度
int QueueSize(Queue* pq);

//判空
bool QueueEmpty(Queue* pq);

Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
//初始化
void QueueInit(Queue* pq)
{
    
    
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
    
    
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
    
    
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;

}

//队尾入
void QueuePush(Queue* pq, QDataType x)
{
    
    
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
    
    
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->tail == NULL)
	{
    
    
		pq->tail = newnode;
		pq->head = newnode;
	}
	else
	{
    
    
		pq->tail->next = newnode;
		pq->tail = newnode;


	}

}

//队头出
void QueuePop(Queue* pq)
{
    
    
	//1.一个
	//2.多个
	assert(pq);
	assert(pq->head);
	if (pq->head->next == NULL)
	{
    
    
		free(pq->head);
		pq->head = pq->tail = NULL;

	}
	else
	{
    
    
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

//取队列的队头元素
QDataType QueueFront(Queue* pq)
{
    
    
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}

//取队列的队尾元素
QDataType QueueBack(Queue* pq)
{
    
    
	assert(pq);
	assert(pq->head);
	return pq->tail->data;
}

//返回队列长度
int QueueSize(Queue* pq)
{
    
    
	assert(pq);
	int size = 0;
	QNode* cur = pq->head;
	while (!cur)
	{
    
    
		size++;
		cur = cur->next;
	}
	return size;
}

//判空
bool QueueEmpty(Queue* pq)
{
    
    
	assert(pq);
	return pq->head == NULL;
}

테스트.c

//测试
int main()
{
    
    
	BTNode* A =(BTNode*)malloc(sizeof(BTNode));
	A->data = 'A';
	A->left = NULL;
	A->right = NULL;

	BTNode* B=(BTNode*)malloc(sizeof(BTNode));
	B->data = 'B';
	B->left = NULL;
	B->right = NULL;

	

	BTNode* C = (BTNode*)malloc(sizeof(BTNode));
	C->data = 'C';
	C->left = NULL;
	C->right = NULL;


	BTNode* D = (BTNode*)malloc(sizeof(BTNode));
	D->data = 'D';
	D->left = NULL;
	D->right = NULL;
	

	BTNode* E = (BTNode*)malloc(sizeof(BTNode));
	E->data = 'E';
	E->left = NULL;
	E->right = NULL;
	
	A->left = B;
	A->right = C;
	B->right = E;
	B->left = D;


	PrevOrder(A);
	printf("\n");
	InOrder(A);
	printf("\n");
	PostOrder(A);
	printf("\n");
	printf("BTNodeSize: %d\n", BTNodeSize(A));
	printf("BTNodeSize: %d\n", BTNodeSize(B));
	printf("BTNodeSize: %d\n", BTNodeSize(C));
	printf("叶子节点数:%d\n", LeafNodeSize(A));

	LevelOrder(A);
	return 0;
}

코드 실행 결과:
여기에 이미지 설명 삽입

Supongo que te gusta

Origin blog.csdn.net/weixin_63181097/article/details/130050123
Recomendado
Clasificación