데이터 구조: 이진 트리의 재귀적 구현(C 구현)

여기에 이미지 설명 삽입

개인 홈페이지 : 개인 홈페이지
개인 컬럼 : "데이터 구조" "C 언어"


머리말

이 블로그에서는 이진 트리의 관련 작업을 주로 다음과 같이 설명합니다.

//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

//二叉树的销毁
void BinaryTreeDestroy(BTNode* root);

//二叉树节点个数
int BinaryTreeSize(BTNode* root);

//二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

//二叉树第K层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

//二叉树查找值为X的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);

//二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

//二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

//层序遍历
void BinaryTreeLevelOrder(BTNode* root);

//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x);

1. 트리의 개념

트리는 n개의 유한 노드로 구성된 계층적 관계의 집합인 비선형 구조입니다.

여기에 이미지 설명 삽입

  • 그림의 노드 A 에는 선행 노드가 없으며 루트 노드라고 합니다.
  • 루트 노드를 제외한 다른 노드는 서로소가 아닌 두 개의 집합 T1(B, D, E, F...), T2(C, G, H, L...)로 나뉩니다. 각 집합 T는 트리와 구조가 유사한 하위 트리입니다. 각 하위 트리의 루트 노드에는 단 하나의 루트 노드가 있으며 0개 이상의 후속 노드를 가질 수 있습니다.
  • 따라서 트리는 재귀적으로 정의됩니다.
  • 트리의 하위 트리는 교차점을 가질 수 없습니다. 그렇지 않으면 그래프입니다.

  • 노드 차수 : 노드에 포함된 하위 트리의 수를 노드 차수라고 하며, 위 그림과 같이 노드 A의 차수는 2입니다.
  • 리프 노드 또는 터미널 노드 : 차수가 0인 노드를 리프 노드라고 하며 위 그림과 같이 K, J, F, L, O, P는 리프 노드입니다.
  • 비종단 노드 또는 분기 노드 : 차수가 0이 아닌 노드, 위 그림과 같이 A, B, C, D, E 등의 노드가 분기 노드입니다.
  • 상위 노드 또는 상위 노드 : 노드에 하위 노드가 포함된 경우 이 노드를 하위 노드의 상위 노드라고 합니다. 위에 표시된 것처럼 노드 A는 B와 C의 상위 노드입니다.
  • 하위 노드 또는 하위 노드 : 노드에 하위 트리가 포함된 경우 하위 트리의 루트 노드는 해당 노드의 하위 노드입니다. 위 그림 B에서 볼 수 있듯이 C는 A의 자식 노드입니다.
  • 형제 노드(Brother node) : 동일한 부모 노드를 가진 노드는 형제 노드입니다. 위에 표시된 대로 B와 C는 형제 노드입니다.
  • 트리의 차수 : 트리에서 가장 큰 노드의 차수는 숫자의 차수입니다. 위 그림의 숫자의 차수는 3입니다.
  • 노드 계층 구조 : 루트 정의부터 시작하여 루트는 첫 번째 레이어이고, 루트의 하위 노드는 두 번째 레이어입니다. 위 그림과 같이 G 노드의 레벨은 3 입니다.
  • 트리 높이 또는 깊이 : 트리에 있는 노드의 최대 수준입니다. 위에서 보듯이 트리의 깊이는 5이다.
  • 사촌 노드 : 부모 노드가 같은 레이어에 있는 노드는 사촌 노드입니다. 위에 표시된 것처럼 D와 G는 서로 사촌 노드입니다.
  • 노드의 조상 : 루트에서 노드까지 분기에 있는 모든 노드입니다. 위에 표시된 것처럼 A는 모든 노드의 조상입니다.
  • 하위 노드 : 노드를 루트로 하는 하위 트리의 모든 노드를 해당 노드의 하위 노드라고 합니다. 위에 표시된 대로 노드는 A의 자손입니다.
  • 숲(Forest) : m개의 분리된 나무들의 집합체를 숲이라 부른다.

둘째, 이진 트리

이진 트리의 개념

이는 루트 노드와 두 개의 하위 트리로 구성됩니다.

여기에 이미지 설명 삽입

  • 이진 트리의 최대 차수는 2입니다.
  • 이진 트리는 순서가 있는 트리입니다. 이진 트리의 하위 트리는 왼쪽과 오른쪽으로 나누어지며 순서는 바뀔 수 없습니다.

이진 트리의 속성

루트 노드의 레이어 수가 1로 지정된 경우 비어 있지 않은 이진 트리의 K번째 레이어는 최대 2^(k - 1)개의 노드를 갖습니다.

루트 노드의 레이어 수가 1로 지정되면 깊이가 h인 이진 트리의 최대 노드 수는 2^h - 1입니다.

임의의 이진 트리에 대해 차수가 0인 노드가 N0이고 차수가 2인 노드가 N2이면 N0 = N2 + 1(수학적 귀납법)

루트 노드의 레이어 수를 1로 지정하면 N 노드가 있는 전체 이진 트리의 깊이는 log(n + 1) [base 2]입니다.

n개의 노드가 있는 완전한 이진 트리의 경우 위에서 아래로, 왼쪽에서 오른쪽으로(즉, 힙의 구조) 배열 순서에 따라 모든 노드의 번호가 0부터 지정되면 직렬 노드가 있는 노드의 경우 숫자 K: k>
0이면 k 노드의 상위 노드 일련 번호: (k - 1) / 2,
k가 0(루트 노드)이면 상위 노드가 없습니다
. 2 k+1<n이면, 왼쪽 자식의 일련 번호는 2 k+1이고 오른쪽 자식의 일련 번호는 2 k+2입니다. 2 k+1>n이면 왼쪽 자식이 없습니다. 2*k+2>n 그러면 오른쪽 자식이 없습니다.

3. 바이너리 트리 체인 구조 구현

이진 트리 노드 정의

노드에는 데이터 필드, 왼쪽 자식 노드에 대한 포인터, 오른쪽 자식 노드에 대한 포인터가 필요합니다.
여기에 이미지 설명 삽입

typedef char BTDataType;

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

이진 트리 노드 생성

이진 트리 노드의 데이터만 전달하면 되며 동적으로 생성된 노드 공간이 반환 값에 의해 허용됩니다.
노드 공간을 malloc하고, 데이터에 함수 매개변수를 주고, 왼쪽과 오른쪽 포인트를 NULL로 만들고, 공간의 주소를 반환한다.

여기에 이미지 설명 삽입

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x)
{
    
    
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
    
    
		perror("malloc:");
		exit(-1);
	}
	root->data = x;
	root->left = root->right = NULL;

	return root;
}

이해를 돕기 위해 먼저 수동으로 이진 트리를 생성하여 관련 연산을 설명하고, 마지막으로 이진 트리 생성 과정을 순서대로 설명합니다.

void test()
{
    
    
	BTNode* a = BuyBinaryTreeNode('A');
	BTNode* b = BuyBinaryTreeNode('B');
	BTNode* c = BuyBinaryTreeNode('C');
	BTNode* d = BuyBinaryTreeNode('D');
	BTNode* e = BuyBinaryTreeNode('E');
	BTNode* f = BuyBinaryTreeNode('F');
	BTNode* g = BuyBinaryTreeNode('G');
	BTNode* h = BuyBinaryTreeNode('H');

	a->left = b;
	b->left = d;
	b->right = e;
	e->right = h;
	a->right = c;
	c->left = f;
	c->right = g;
}

생성된 이진 트리는 아래 그림과 같습니다.
여기에 이미지 설명 삽입

이진 트리 탐색

이진 트리를 순회하는 방법에는 여러 가지가 있습니다.

  • 선주문 순회: 루트 노드 -> 왼쪽 하위 트리 -> 오른쪽 하위 트리
  • 중위 순회: 왼쪽 하위 트리 -> 루트 노드 -> 오른쪽 하위 트리
  • 후위 순회: 왼쪽 하위 트리 -> 오른쪽 하위 트리 -> 루트 노드
  • 레이어 순서 탐색: 왼쪽에서 오른쪽으로, 위에서 아래로 이진 트리 노드를 차례로 탐색합니다.

이진 트리의 선주문 순회(BinaryTreePrevOrder)

아래 그림의 이진 트리의 경우 선주문 순회 결과는 ABD##E#H##CF##G##('#'은 NULL을 의미)이므로 어떻게 순회합니까
여기에 이미지 설명 삽입
? 루트, 왼쪽, 오른쪽 순서로 이진 트리를 반복해야 합니다.
여기에 이미지 설명 삽입

//二叉树前序遍历   根节点 左子树  右子树
void BinaryTreePrevOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//根节点
	printf("%c ", root->data);
	//左子树
	BinaryTreePrevOrder(root->left);
	//右子树
	BinaryTreePrevOrder(root->right);
}

이 코드는 어떻게 전개되나요?
여기에 이미지 설명 삽입

이진 트리의 중위순회(BinaryTreeInOrder)

순차 순회는 선순 순회와 유사하며 루트 노드와 왼쪽 하위 트리의 액세스만 재귀적으로 실행 순서를 교환합니다. 아래 그림의 이진 트리의 경우 순차 순회 결과는 다음과 같습니다
. #D#B#E#H#A#F #C#G#( ' # '는 NULL 을 의미함)
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

//二叉树中序遍历		左子树  根  右子树
void BinaryTreeInOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//左子树
	BinaryTreeInOrder(root->left);
	//根
	printf("%c ", root->data);
	//右子树
	BinaryTreeInOrder(root->right);
}

이진 트리의 후순 순회(BinaryTreePostOrder)

후위 순회는 루트 노드의 접근 순서를 다시 조정하고, 루트 노드의 접근 순서를 왼쪽 하위 트리의 재귀와 오른쪽 하위 트리의 재귀로 조정하는 것입니다.

아래 그림의 이진 트리의 경우 순서 탐색 결과는 다음과 같습니다. ##D###HEB##F##GCA('#'은 NULL을 의미)
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

//二叉树后序遍历  左子树 右子树 根
void BinaryTreePostOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//左子树
	BinaryTreePostOrder(root->left);
	//右子树
	BinaryTreePostOrder(root->right);
	//根
	printf("%c ", root->data);
}

이진 트리의 레벨 순서 탐색(BinaryTreeLevelOrder)

이진 트리의 레벨 순서 순회를 구현하려면 대기열의 도움이 필요합니다.
루트 노드를 먼저 큐에 넣은 후, 큐 헤드 데이터를 출력할 때마다 큐 헤드 데이터가 가리키는 왼쪽 자식 노드와 오른쪽 자식 노드가 각각 큐에 들어갑니다. 오른쪽 자식 노드가 NULL이면 대기열에 추가되지 않습니다. 대기열이 빌 때까지 위 과정을 반복합니다.

여기에 이미지 설명 삽입

//层序遍历  借助队列  出队头数据时,将其左子节点 与 右子节点依次入队列
void BinaryTreeLevelOrder(BTNode* root)
{
    
    
	Quene q;
	QueneInit(&q);

	//入根节点
	QuenePush(&q, root);

	//队列为空,代表二叉树中元素也遍历完成
	while (!QueneEmpty(&q))
	{
    
    
		QDataType val = QueneFront(&q);
			printf("%c ", val->data);

		//入数据  该节点的左节点 与 右节点
		if (val->left != NULL)
			QuenePush(&q, val->left);

		if (val->right != NULL)
			QuenePush(&q, val->right);

		//出队头数据
		QuenePop(&q);
	}
		QueneDestrory(&q);
}

이진 트리 노드 수(BinaryTreeSize)

우리는 이진 트리 노드 수의 인터페이스를 살펴보기 위해 재귀적 사고를 사용합니다.
하위 문제: 루트 노드의 왼쪽 하위 트리에 있는 노드 수와 루트 노드의 오른쪽 하위 트리에 있는 노드 수 종료
조건: 빈 노드가 반환되므로
이진 트리 노드 수를 찾는 문제는 다음과 같이 변환될 수 있습니다. 루트 노드의 왼쪽 하위 트리에 있는 노드 수 + 루트 노드의 오른쪽 하위 트리 노드 수 + 루트 노드의 총 노드 수

//二叉树节点个数   根节点的左子树与右子树的节点个数和  
int BinaryTreeSize(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		return 0;
	}

	//        左子树节点数                 右子树节点数               根节点
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

다음 이진 트리의 재귀 확장 그래프의 경우:
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

이진 트리의 K 수준 노드 수(BinaryTreeLevelKSize)

함수 선언:

int BinaryTreeLevelKSize(BTNode* root, int k);

하위 문제: 루트 노드의 왼쪽 하위 트리 K-1 수준에 있는 노드 수와 루트 노드의 오른쪽 하위 트리 K-1 수준에 있는 노드 수 끝 조건: 빈 노드에 접근
하거나 추구하는 수준 수 (k == 1)

즉, 이진 트리의 레벨 K에 있는 노드 수를 구하는 문제는 루트 노드의 왼쪽 하위 트리에 있는 레벨 K-1에 있는 노드 수와 레벨 K-1에 있는 노드 수의 합을 구하는 문제로 변환됩니다. 루트 노드의 오른쪽 하위 트리에 있는 레벨 K-1입니다.

//二叉树第K层节点个数       左子树的第k-1层节点数 + 右子树的第k-1层节点数     不同栈帧的k互不影响
int BinaryTreeLevelKSize(BTNode* root, int k)
{
    
    
	//如果 k 超过数的深度
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

다음 이진 트리의 경우 세 번째 계층의 노드 수에 대한 재귀 확장 그래프를 찾습니다.
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

이진 트리 리프 노드의 수(BinaryTreeLeafSize)

함수 선언:

int BinaryTreeLeafSize(BTNode* root);

하위 문제: 루트 노드의 왼쪽 하위 트리의 리프 노드와 루트 노드의 오른쪽 하위 트리의 리프 노드 종료
조건: 빈 노드를 방문하거나 리프 노드를 방문

원래 문제는 루트 노드의 왼쪽 하위 트리에 있는 리프 노드 수 + 루트 노드의 오른쪽 하위 트리에 있는 리프 노드 수로 변환됩니다.


//二叉树叶子节点个数   左子树的叶子节点 + 右子树的叶子结点
int BinaryTreeLeafSize(BTNode* root)
{
    
    
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

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

다음 이진 트리에 대해 리프 노드 트리의 재귀 확장 그래프를 찾으십시오.
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

이진 트리에서 X 값을 갖는 노드 찾기(BinaryTreeFind)

노드를 찾기 위해 순회를 선주문하고, 노드인 경우 노드의 주소를 직접 반환합니다. 노드가 아닌 경우 노드의 왼쪽 하위 트리를 계속 검색하고, 왼쪽 하위 트리를 찾을 수 없으면 오른쪽 하위 트리를 검색합니다.

//二叉树查找值为X的节点   前序遍历查找  
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    
    
	if (root == NULL)
		return NULL;

	//根
	if (root->data == x)
		return root;

	//左子树
	BTNode* leftNode = BinaryTreeFind(root->left, x);
	if (leftNode != NULL)
		return leftNode;

	//右子树
	BTNode* rightNode = BinaryTreeFind(root->right, x);
	if (rightNode != NULL)
		return rightNode;

	return NULL;
}

다음 이진 트리에 대해 'C'의 재귀 확장 그래프를 찾으십시오.
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

이진 트리가 완전한 이진 트리인지 확인(BinaryTreeComplete)

완전한 이진 트리는 레벨 순서를 순회할 때 유효한 데이터(NULL 제외)가 연속되는 힙이기도 합니다.
이진 트리를 순서대로 순회하려면 대기열을 사용해야 합니다(노드의 왼쪽 또는 오른쪽 자식이 NULL인 경우 노드도 대기열에 추가됩니다). 큐의 선두에 있는 데이터가 NULL이면 후속 데이터가 모두 NULL인지 판단하고, 후속 데이터가 모두 NULL이면 true를 반환하고, 후속 요소 중 하나가 NULL이 아니면 false를 반환합니다.


//完全二叉树的节点是连续的,层序遍历二叉树,如果遇到NULL,检查栈中后续元素是否都为NULL
bool BinaryTreeComplete(BTNode* root)
{
    
    
	Quene q;
	QueneInit(&q);

	QuenePush(&q, root);
	while (!QueneEmpty(&q))
	{
    
    
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
    
    
			QuenePush(&q, node->left);
			QuenePush(&q, node->right);
		}
		else
		{
    
    
			break;
		}
	}

	while (!QueneEmpty(&q))
	{
    
    
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
    
    
			QueneDestrory(&q);
			return false;
		}
	}

	QueneDestrory(&q);
	return true;
}

사전 순서로 탐색된 배열에서 이진 트리 구축

선순으로 순회하는 배열에서는 NULL을 나타내기 위해 '#'을 사용합니다.
함수 선언: a는 미리 탐색한 배열, n은 노드 수, pi는 현재 노드 수

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

하위 문제: 왼쪽 하위 트리와 오른쪽 하위 트리 구축 종료
조건: 선주문 순회 배열에서 '#'이 발생하거나 노드 수가 n보다 큽니다
. 루트 노드를 생성한 다음 왼쪽 하위 트리와 오른쪽 하위 트리를 순회하여 루트를 만듭니다. 노드는 오른쪽 하위 트리가 있는 왼쪽 하위 트리를 가리킵니다.

//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
    
    
	if (*pi >= n  || a[*pi] == '#')
	{
    
    
		(*pi)++;
		return NULL;
	}

	BTNode* newnode = BuyBinaryTreeNode(a[*pi]);
	(*pi)++;

	//左子节点
	BTNode* leftnode = BinaryTreeCreate(a, n, pi);
	newnode->left = leftnode;

	//右子节点
	BTNode* rightnode = BinaryTreeCreate(a, n, pi);
	newnode->right = rightnode;

	return newnode;
}

4. 코드 표시

바이너리 트리 코드 표시

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>

typedef char BTDataType;

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



//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

//二叉树的销毁
void BinaryTreeDestroy(BTNode* root);

//二叉树节点个数
int BinaryTreeSize(BTNode* root);

//二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

//二叉树第K层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

//二叉树查找值为X的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);

//二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

//二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

//层序遍历
void BinaryTreeLevelOrder(BTNode* root);

//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x);

#include "BinaryTree.h"
#include "quene.h"

//创建二叉树的节点
BTNode* BuyBinaryTreeNode(BTDataType x)
{
    
    
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
    
    
		perror("malloc:");
		exit(-1);
	}
	root->data = x;
	root->left = root->right = NULL;

	return root;
}

//二叉树前序遍历   根节点 左子树  右子树
void BinaryTreePrevOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//根节点
	printf("%c ", root->data);
	//左子树
	BinaryTreePrevOrder(root->left);
	//右子树
	BinaryTreePrevOrder(root->right);
}

//二叉树中序遍历		左子树  根  右子树
void BinaryTreeInOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//左子树
	BinaryTreeInOrder(root->left);
	//根
	printf("%c ", root->data);
	//右子树
	BinaryTreeInOrder(root->right);
}

//二叉树后序遍历  左子树 右子树 根
void BinaryTreePostOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("# ");
		return;
	}

	//左子树
	BinaryTreePostOrder(root->left);
	//右子树
	BinaryTreePostOrder(root->right);
	//根
	printf("%c ", root->data);
}



//二叉树的销毁  后序遍历二叉树 
void BinaryTreeDestroy(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		return;
	}

	//左子树
	BinaryTreeDestroy(root->left);
	//右子树
	BinaryTreeDestroy(root->right);
	//根
	free(root);
}



//二叉树节点个数   根节点的左子树与右子树的节点个数和  
int BinaryTreeSize(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		return 0;
	}

	//        左子树节点数                 右子树节点数               根节点
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}



//二叉树叶子节点个数   左子树的叶子节点 + 右子树的叶子结点
int BinaryTreeLeafSize(BTNode* root)
{
    
    
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

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



//二叉树第K层节点个数       左子树的第k层节点数 + 右子树的第k层节点数     不同栈帧的k互不影响
int BinaryTreeLevelKSize(BTNode* root, int k)
{
    
    
	//如果 k 超过数的深度
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}




//二叉树查找值为X的节点   前序遍历查找  
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    
    
	if (root == NULL)
		return NULL;

	//根
	if (root->data == x)
		return root;

	//左子树
	BTNode* leftNode = BinaryTreeFind(root->left, x);
	if (leftNode != NULL)
		return leftNode;

	//右子树
	BTNode* rightNode = BinaryTreeFind(root->right, x);
	if (rightNode != NULL)
		return rightNode;

	return NULL;
}



//层序遍历  借助队列  出队头数据时,将其左子节点 与 右子节点依次入队列
void BinaryTreeLevelOrder(BTNode* root)
{
    
    
	Quene q;
	QueneInit(&q);

	//入根节点
	QuenePush(&q, root);

	//队列为空,代表二叉树中元素也遍历完成
	while (!QueneEmpty(&q))
	{
    
    
		QDataType val = QueneFront(&q);
			printf("%c ", val->data);

		//入数据  该节点的左节点 与 右节点
		if (val->left != NULL)
			QuenePush(&q, val->left);

		if (val->right != NULL)
			QuenePush(&q, val->right);

		//出队头数据
		QuenePop(&q);
	}
		QueneDestrory(&q);
}



//判断二叉树是否是完全二叉树    层序遍历二叉树

//bool BinaryTreeComplete(BTNode* root)
//{
    
    
//	Quene q;
//	QueneInit(&q);
//
//	//如果某个节点的右节点为空,那么之后遍历的节点的左/右节点也应该为空
//	bool flag = false;
//
//	QuenePush(&q, root);
//	while (!QueneEmpty(&q))
//	{
    
    
//		QDataType val = QueneFront(&q);
//
//		if (val->left == NULL && val->right != NULL)
//			return false;
//
//		if (flag == true && (val->left != NULL || val->right != NULL))
//			return false;
//
//		if (val->left != NULL)
//			QuenePush(&q, val->left);
//
//		if (val->right != NULL)
//			QuenePush(&q, val->right);
//		else
//			flag = true;
//
//		QuenePop(&q);
//	}
//
//	return true;
//}

//完全二叉树的节点是连续的,层序遍历二叉树,如果遇到NULL,检查栈中后续元素是否都为NULL
bool BinaryTreeComplete(BTNode* root)
{
    
    
	Quene q;
	QueneInit(&q);

	QuenePush(&q, root);
	while (!QueneEmpty(&q))
	{
    
    
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
    
    
			QuenePush(&q, node->left);
			QuenePush(&q, node->right);
		}
		else
		{
    
    
			break;
		}
	}

	while (!QueneEmpty(&q))
	{
    
    
		BTNode* node = QueneFront(&q);
		QuenePop(&q);

		if (node != NULL)
		{
    
    
			QueneDestrory(&q);
			return false;
		}
	}

	QueneDestrory(&q);
	return true;
}



//通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
    
    
	if (*pi >= n  || a[*pi] == '#')
	{
    
    
		(*pi)++;
		return NULL;
	}

	BTNode* newnode = BuyBinaryTreeNode(a[*pi]);
	(*pi)++;

	//左子节点
	BTNode* leftnode = BinaryTreeCreate(a, n, pi);
	newnode->left = leftnode;

	//右子节点
	BTNode* rightnode = BinaryTreeCreate(a, n, pi);
	newnode->right = rightnode;

	return newnode;
}

대기열 코드 표시

#include "BinaryTree.h"
#include <assert.h>

//队列 节点结构--树节点
typedef struct QueneNode
{
    
    
	struct BinaryTreeNode* data;
	struct QueneNode* next;
}QueneNode;

typedef struct BinaryTreeNode* QDataType;

//队列 结构
typedef struct Quene
{
    
    
	QueneNode* head;
	QueneNode* tail;
	int size;
}Quene;


//初始化队列
void QueneInit(Quene* q);

//队尾入队列
void QuenePush(Quene* q, QDataType x);

//队头出数据
void QuenePop(Quene* q);

//获取队列头部元素
QDataType QueneFront(Quene* q);

//获取队列队尾元素
QDataType QueneBack(Quene* q);

//获取队列中有效元素个数
int QueneSize(Quene* q);

//检查队列是否为空,如果为空返回ture,如果非空返回false
bool QueneEmpty(Quene* q);

//销毁队列
void QueneDestrory(Quene* q);

#include "quene.h"

//初始化队列
void QueneInit(Quene* q)
{
    
    
	assert(q);

	q->head = q->tail = NULL;
	q->size = 0;
}

//队尾入队列
void QuenePush(Quene* q, QDataType x)
{
    
    
	assert(q);

	QueneNode* newnode = (QueneNode*)malloc(sizeof(QueneNode));
	if (newnode == NULL)
	{
    
    
		perror("malloc");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = x;

	//队列为空
	if (QueneEmpty(q) == true)
	{
    
    
		q->head = q->tail = newnode;
	}
	else//队列不为空
	{
    
    
		q->tail->next = newnode;
		q->tail = newnode;
	}

	q->size++;
}



//队头出数据
void QuenePop(Quene* q)
{
    
    
	assert(q);
	//队列为空
	assert(QueneEmpty(q) != true);

	//队列只有一个元素
	if (q->head->next == NULL)
	{
    
    
		free(q->head);
		q->head = q->tail = NULL;
	}
	else//队列中有多个元素
	{
    
    
		QueneNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}

	q->size--;
}


//获取队列头部元素
QDataType QueneFront(Quene* q)
{
    
    
	assert(q);

	return q->head->data;
}


//获取队列队尾元素
QDataType QueneBack(Quene* q)
{
    
    
	assert(q);

	return q->tail->data;
}


//获取队列中有效元素个数
int QueneSize(Quene* q)
{
    
    
	assert(q);

	return q->size;
}


//检查队列是否为空,如果为空返回ture,如果非空返回false
bool QueneEmpty(Quene* q)
{
    
    
	assert(q);

	return q->size == 0;
}


//销毁队列
void QueneDestrory(Quene* q)
{
    
    
	assert(q);

	QueneNode* cur = q->head;
	while (cur)
	{
    
    
		QueneNode* next = cur->next;
		free(cur);
		cur = next;
	}

}

요약하다

위의 내용은 이진 트리에 대한 나의 이해입니다! ! !
여기에 이미지 설명 삽입

추천

출처blog.csdn.net/li209779/article/details/132343492