データ構造:バイナリツリーの再帰実装(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には先行ノードがなく、ルート ノードと呼ばれます。
  • ルート ノードを除く他のノードは、2 つの非結合セット T1 (B、D、E、F...)、T2 (C、G、H、L...) に分割されます。各集合 T は、ツリーと同様の構造のサブツリーです。各サブツリーのルート ノードにはルート ノードが 1 つだけあり、0 個以上の後続ノードを持つことができます。
  • したがって、ツリーは再帰的に定義されます。
  • ツリーのサブツリーは交差を持つことができません。それ以外の場合、それはグラフになります。

  • ノードの次数: ノードに含まれる部分木の数をノードの次数と呼び、上図に示すように、ノード A の次数は 2 です。
  • リーフ ノードまたはターミナル ノード: 次数 0 のノードはリーフ ノードと呼ばれます。上の図に示すように、K、J、F、L、O、P はリーフ ノードです。
  • 非終端ノードまたは分岐ノード: 次数が 0 ではないノード; 上図に示すように: A、B、C、D、E などのノードが分岐ノードです。
  • 親ノードまたは親ノード: ノードに子ノードが含まれる場合、このノードはその子ノードの親ノードと呼ばれます。上に示すように、ノード A は B と C の親ノードです。
  • 子ノードまたは子ノード: ノードにサブツリーが含まれる場合、サブツリーのルート ノードがノードの子ノードになります。上図Bに示すように、CはAの子ノードです。
  • 兄弟ノード: 同じ親ノードを持つノードは兄弟ノードです。上に示すように、B と C は兄弟ノードです。
  • ツリーの次数: ツリーでは、最大のノードの次数が数値の次数になります。上図の数字の次数は 3 です
  • ノード階層: ルートの定義から始まり、ルートが最初の層、ルートの子ノードが 2 番目の層などとなります。上図に示すように、G ノードのレベルは 3 です。
  • ツリーの高さまたは深さ: ツリー内のノードの最大レベル。上に示すように、ツリーの深さは 5 です。
  • いとこノード: 親ノードが同じレイヤー上にあるノードはいとこノードです。上に示すように、D と G は互いにいとこノードです。
  • ノードの祖先: ルートからノードまでのブランチ上のすべてのノード。上に示すように、A はすべてのノードの祖先です。
  • 子孫ノード: ノードをルートとするサブツリー内のノードは、ノードの子孫と呼ばれます。上に示すように、ノードは A の子孫です。
  • : m 個の互いに素な木の集合を森と呼びます

二分木

二分木の概念

これは、ルート ノードと 2 つのサブツリーで構成されます。

ここに画像の説明を挿入

  • 二分木の最大次数は 2 です
  • 二分木は順序付き木であり、二分木の部分木は左右に分かれており、順序を逆にすることはできません。

二分木の性質

ルート ノードの層の数が 1 に指定されている場合、空ではないバイナリ ツリーの K 番目の層には最大 2^(k - 1) 個のノードがあります。

ルート ノードの層数が 1 に指定されている場合、深さ h のバイナリ ツリー内のノードの最大数は 2^h - 1 になります。

任意の二分木について、次数 0 のノードが N0、次数 2 のノードが N2 である場合、N0 = N2 + 1 (数学的帰納法)

ルート ノードの層数が 1 に指定されている場合、N 個のノードを持つ完全なバイナリ ツリーの深さは log(n + 1) [基数 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);
}

次の二分木について、第 3 層のノード数の再帰的展開グラフを求めます。
ここに画像の説明を挿入
ここに画像の説明を挿入

二分木のリーフノードの数 (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