Estructura de datos: implementación recursiva del árbol binario (implementación C)

inserte la descripción de la imagen aquí

Página de inicio personal: Página de inicio personal
Columna personal: "Estructura de datos" "Lenguaje C"


prefacio

Este blog explica principalmente las operaciones relacionadas del árbol binario de la siguiente manera:

//通过前序遍历的数组"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. El concepto de árbol

Un árbol es una estructura no lineal, que es una colección de relaciones jerárquicas compuestas por n nodos finitos.

inserte la descripción de la imagen aquí

  • El nodo A en la figura no tiene un nodo predecesor y se llama nodo raíz.
  • Excepto el nodo raíz, los demás nodos se dividen en dos conjuntos no disjuntos T1 (B, D, E, F...), T2 (C, G, H, L...). Cada conjunto T es un subárbol similar en estructura a un árbol. El nodo raíz de cada subárbol tiene uno y solo un nodo raíz y puede tener 0 o más nodos sucesores.
  • Por tanto, el árbol se define de forma recursiva.
  • Los subárboles del árbol no pueden tener intersección, de lo contrario es un gráfico.

  • Grado del nodo : el número de subárboles contenidos en un nodo se llama grado del nodo; como se muestra en la figura anterior, el grado del nodo A es 2
  • Nodo hoja o nodo terminal : un nodo con un grado de 0 se llama nodo hoja; como se muestra en la figura anterior: K, J, F, L, O, P son nodos hoja
  • Nodo no terminal o nodo de rama : un nodo cuyo grado no es 0, como se muestra en la figura anterior: nodos como A, B, C, D, E, etc. son nodos de rama
  • Nodo principal o nodo principal : si un nodo contiene nodos secundarios, este nodo se denomina nodo principal de sus nodos secundarios. Como se muestra arriba, el nodo A es el nodo padre de B y C.
  • Nodo hijo o nodo hijo : si un nodo contiene un subárbol, el nodo raíz del subárbol es el nodo hijo del nodo. Como se muestra en la figura B anterior, C es un nodo hijo de A
  • Nodos hermanos : los nodos con el mismo nodo padre son nodos hermanos. Como se muestra arriba, B y C son nodos hermanos.
  • Grado del árbol : En un árbol, el grado del nodo más grande es el grado del número. El grado del número en la figura anterior es 3.
  • Jerarquía de nodos : a partir de la definición de raíz, la raíz es la primera capa, los nodos secundarios de la raíz son la segunda capa, y así sucesivamente. Como se muestra en la figura anterior, el nivel del nodo G es 3
  • Altura o profundidad del árbol : el nivel máximo de nodos en el árbol. Como se muestra arriba, la profundidad del árbol es 5
  • Nodos primos : los nodos cuyos nodos principales están en la misma capa son nodos primos. Como se muestra arriba, D y G son nodos primos entre sí.
  • Ancestros de un nodo : todos los nodos de la rama desde la raíz hasta el nodo. Como se muestra arriba, A es el antepasado de todos los nodos.
  • Nodo descendiente : cualquier nodo en el subárbol con raíz en un nodo se denomina descendiente del nodo. Como se muestra arriba, el nodo es descendiente de A.
  • Bosque : una colección de m árboles separados se llama bosque.

Segundo, el árbol binario.

El concepto de árbol binario.

Consta de un nodo raíz más dos subárboles.

inserte la descripción de la imagen aquí

  • El grado máximo de un árbol binario es 2.
  • Un árbol binario es un árbol ordenado. Los subárboles del árbol binario se dividen en izquierda y derecha y el orden no se puede invertir.

Propiedades de los árboles binarios

Si se especifica que el número de capas del nodo raíz es 1, entonces la capa K de un árbol binario no vacío tiene como máximo 2 ^ (k - 1) nodos.

Si se especifica que el número de capas del nodo raíz es 1, entonces el número máximo de nodos en un árbol binario con una profundidad de h es 2^h - 1

Para cualquier árbol binario, si el nodo de grado 0 es N0 y el nodo de grado 2 es N2, entonces N0 = N2 + 1 (inducción matemática)

Si se especifica que el número de capas del nodo raíz es 1, la profundidad de un árbol binario completo con N nodos es log(n + 1) [base 2]

Para un árbol binario completo con n nodos, si todos los nodos están numerados desde 0 de acuerdo con el orden de la matriz de arriba a abajo y de izquierda a derecha (es decir, la estructura del montón), entonces para el nodo con la serie número K: si k>
0, el número de serie del nodo padre del nodo k: (k - 1) / 2;
si k es 0 (nodo raíz), entonces no hay nodo padre
Si 2 k+1<n, el número de serie del hijo izquierdo es 2 k+1, y el número de serie del hijo derecho es 2 k+2 Si 2 k+1>n entonces no hay hijo izquierdo 2*k+2>n entonces no hay hijo derecho

3. Implementación de la estructura de cadena de árbol binario.

Definición de nodo de árbol binario

Un nodo requiere un campo de datos, un puntero al nodo secundario izquierdo y un puntero al nodo secundario derecho.
inserte la descripción de la imagen aquí

typedef char BTDataType;

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

Crear un nodo de árbol binario

Solo necesitamos pasar los datos de los nodos del árbol binario y el valor de retorno acepta el espacio de nodos creado dinámicamente.
malloc un espacio de nodo, proporcione parámetros de función a los datos, haga que la izquierda y la derecha apunten a NULL y devuelva la dirección del espacio

inserte la descripción de la imagen aquí

//创建二叉树的节点
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;
}

Para facilitar nuestra comprensión, aquí primero creamos manualmente un árbol binario para explicar las operaciones relacionadas y, finalmente, explicamos la creación de un árbol binario en orden.

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;
}

El árbol binario creado se muestra en la siguiente figura:
inserte la descripción de la imagen aquí

atravesar árbol binario

Hay varias formas de recorrer un árbol binario:

  • Recorrido de pedido anticipado: nodo raíz -> subárbol izquierdo -> subárbol derecho
  • Recorrido en orden: subárbol izquierdo -> nodo raíz -> subárbol derecho
  • Recorrido posterior al pedido: subárbol izquierdo -> subárbol derecho -> nodo raíz
  • Recorrido del orden de las capas: de izquierda a derecha y de arriba a abajo, recorra los nodos del árbol binario uno por uno

Recorrido previo al pedido del árbol binario (BinaryTreePrevOrder)

Para el árbol binario en la figura siguiente, el resultado del recorrido de preorden es: ABD##E#H##CF##G## ('#' significa NULL), entonces, ¿cómo se
inserte la descripción de la imagen aquí
recorre? Necesitamos recurrir al árbol binario en el orden de raíz, izquierda y derecha.
inserte la descripción de la imagen aquí

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

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

¿Cómo se desarrolla este código?
inserte la descripción de la imagen aquí

Recorrido en orden de un árbol binario (BinaryTreeInOrder)

El recorrido en orden es similar al recorrido en orden previo, solo el acceso del nodo raíz y el subárbol izquierdo intercambian recursivamente el orden de ejecución. Para el árbol binario en la figura siguiente, el resultado del recorrido en orden es
: #D#B#E#H#A#F #C#G# ( ' # ' significa NULL )
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

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

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

Recorrido posterior al pedido del árbol binario (BinaryTreePostOrder)

El recorrido posterior al orden consiste en ajustar nuevamente el orden de acceso del nodo raíz y ajustar el orden de acceso del nodo raíz a la recursividad del subárbol izquierdo y la recursividad del subárbol derecho.

Para el árbol binario en la figura siguiente, el resultado del recorrido de orden es: ##D###HEB##F##GCA ('#' significa NULL)
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

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

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

Recorrido de orden de nivel del árbol binario (BinaryTreeLevelOrder)

Para implementar el recorrido de orden de nivel de un árbol binario, necesitamos la ayuda de una cola.
Primero colocamos el nodo raíz en la cola y luego, cada vez que generamos los datos del encabezado de la cola, el nodo secundario izquierdo y el nodo secundario derecho señalados por los datos del encabezado de la cola se colocan respectivamente en la cola. el nodo secundario derecho es NULL, no se pondrá en cola. Repita el proceso anterior hasta que la cola esté vacía

inserte la descripción de la imagen aquí

//层序遍历  借助队列  出队头数据时,将其左子节点 与 右子节点依次入队列
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);
}

Número de nodos del árbol binario (BinaryTreeSize)

Usamos el pensamiento recursivo para observar la interfaz del número de nodos del árbol binario.
Subproblemas: el número de nodos en el subárbol izquierdo del nodo raíz y el número de nodos en el subárbol derecho del nodo raíz
Condición final: se devuelven nodos vacíos,
por lo que el problema de encontrar el número de nodos del árbol binario se puede convertir a el número de nodos en el subárbol izquierdo del nodo raíz + el número de nodos del subárbol derecho del nodo raíz + el número total de nodos del nodo raíz

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

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

Para el gráfico de expansión recursiva del siguiente árbol binario:
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

El número de nodos de nivel K en el árbol binario (BinaryTreeLevelKSize)

Declaración de función:

int BinaryTreeLevelKSize(BTNode* root, int k);

Subproblema: el número de nodos en el nivel K-1 del subárbol izquierdo del nodo raíz y el número de nodos en el nivel K-1 del subárbol derecho del nodo raíz Condición final: acceder a un nodo vacío o encontrar
el número de niveles buscados (k == 1)

Es decir, el problema de encontrar el número de nodos en el nivel K de un árbol binario se transforma en encontrar la suma del número de nodos en el nivel K-1 en el subárbol izquierdo del nodo raíz y el número de nodos en nivel K-1 en el subárbol derecho del nodo raíz.

//二叉树第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);
}

Para el siguiente árbol binario, encuentre el gráfico de expansión recursiva del número de nodos en la tercera capa.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

El número de nodos de hojas de árboles binarios (BinaryTreeLeafSize)

Declaración de función:

int BinaryTreeLeafSize(BTNode* root);

Subproblema: el nodo hoja del subárbol izquierdo del nodo raíz y el nodo hoja del subárbol derecho del nodo raíz
Condición final: visita a un nodo vacío o visita a un nodo hoja

El problema original se transforma en el número de nodos hoja en el subárbol izquierdo del nodo raíz + el número de nodos hoja en el subárbol derecho del nodo raíz.


//二叉树叶子节点个数   左子树的叶子节点 + 右子树的叶子结点
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);
}

Para el siguiente árbol binario, encuentre el gráfico de expansión recursiva del árbol de sus nodos hoja.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Encuentra el nodo con el valor X en el árbol binario (BinaryTreeFind)

Preordene el recorrido para encontrar el nodo; si es el nodo, devuelva la dirección del nodo directamente. Si no es el nodo, continúe buscando el subárbol izquierdo del nodo, si no se encuentra el subárbol izquierdo, busque el subárbol derecho.

//二叉树查找值为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;
}

Para el siguiente árbol binario, encuentre el gráfico de expansión recursiva de ' C '
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Determinar si un árbol binario es un árbol binario completo (BinaryTreeComplete)

Un árbol binario completo también es un montón, en el que los datos válidos (excluyendo NULL) son continuos cuando se recorre su orden de niveles.
Solo necesita usar la cola para atravesar el árbol binario en orden (si el hijo izquierdo o derecho de un nodo es NULL, también se pondrá en cola). Cuando los datos al principio de la cola son NULL, juzgue si los datos posteriores son todos NULL, si los datos posteriores son todos NULL, devuelva verdadero, si uno de los elementos posteriores no es NULL, devuelva falso.


//完全二叉树的节点是连续的,层序遍历二叉树,如果遇到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;
}

Construya un árbol binario a partir de una matriz recorrida en preorden

En la matriz recorrida en preorden, usamos '#' para representar NULL.
Declaración de función: donde a es la matriz atravesada por adelantado, n es el número de nodos y pi es el número de nodos actuales

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

Subproblema: construir el subárbol izquierdo y el subárbol derecho
Condición final: encontrar '#' en la matriz transversal del pedido anticipado o el número de nodos es mayor que n
Crear un nodo raíz, luego atravesar el subárbol izquierdo y el subárbol derecho, crear la raíz El nodo apunta al subárbol izquierdo con el subárbol derecho.

//通过前序遍历的数组"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. Visualización de código

Visualización de código de árbol binario

#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;
}

Visualización del código de cola

#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;
	}

}

Resumir

¡Lo anterior es mi comprensión de los árboles binarios! ! !
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/li209779/article/details/132343492
Recomendado
Clasificación