Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
el árbol es unno lineal Una estructura de datos, que es un conjunto de relaciones jerárquicas compuestas por n (n>=0) nodos limitados.ManojoSe llama árbol porque parece un árbol al revés, lo que significa que tiene las raíces hacia arriba y las hojas hacia abajo.
- Nodo raíz: el nodo raíz no tiene un nodo predecesor.
- A excepción del nodo raíz, los nodos restantes se dividen en subárboles con una estructura similar a la de un árbol. El nodo raíz de cada subárbol tiene un solo predecesor y puede tener 0 o más sucesores.
- Por lo tanto, el árbol esdefinición recursivade.
La estructura de árbol es más complicada que la tabla lineal y es más problemático almacenarla y representarla.Es necesario guardar tanto el rango de valores como la relación entre nodos y nodos.De hecho, existen muchas formas de representar árboles, como por ejemplo:Notación padre, notación hijo, notación padre hijo y notación hermano hijoesperar.
En el proceso de introducción de la siguiente estructura de almacenamiento, tomamos el siguiente árbol como ejemplo.
Suponemos que los nodos del árbol están almacenados en un conjunto de espacios continuos y al mismo tiempoEn cada nodo, se adjunta un indicador para indicar la posición de su nodo principal en la lista vinculada. . En otras palabras, además de saber quién es, cada nodo también sabe dónde están sus padres.
Entre ellos, los datos son el campo de datos, que almacena la información de datos del nodo. Y padre es un campo de puntero que almacena los subíndices de los padres del nodo en la matriz.
El siguiente es el código de definición de estructura de nodos para nuestra representación principal.
/*树的双亲表示法结点结构定义*/
#define MAX_TREE_SIZE 100
typedef int TElemType; //树结点的数据类型,目前暂定为整型
/*结点结构*/
typedef struct TreeNode
{
TElemType data; //结点数据
int parent; //双亲位置
}TreeNode;
/*树结构*/
typedef struct
{
TreeNode nodes[MAX_TREE_SIZE]; //结点数组
int r, n; //根的位置和结点数
}PTree;
Con dicha estructura de almacenamiento, podemos encontrar fácilmente sus nodos principales según el puntero principal del nodo utilizado.La complejidad del tiempo es 0(1) , hasta que el padre sea -1, lo que indica que se ha encontrado la raíz del nodo del árbol. Pero si queremos saber cuáles son los hijos del nodo, lo siento, recorra toda la estructura.
Hace un momento estudiamos la estructura de almacenamiento del árbol desde la perspectiva de los padres y la perspectiva del niño. ¿Qué pasa si miramos a los hermanos de los nodos del árbol? Por supuesto, para una estructura jerárquica como un árbol, solo estudiamos el. hermanos de los nodos No es posible Después de la observación, encontramos que para cualquier árbol, el primer hijo de su nodo es único si existe, y su hermano derecho también es único si existe. Por lo tanto, configuramos dos punteros, que apuntan al primer hijo del nodo y al hermano derecho del nodo.
/*树的孩子兄弟表示法结构定义*/
typedef struct TreeNode
{
TElemtype data;
struct TreeNode *firstchild, *rightsib;
} TreeNode,* pTreeNode;
Un árbol binario es un conjunto finito de nodos, que es:
- o vacío
- Consta de un nodo raíz más dos árboles binarios, también conocidos como subárbol izquierdo y subárbol derecho.
Como se puede ver en la imagen de arriba:
- No hay ningún nodo con grado mayor que 2 en un árbol binario
- Los subárboles de un árbol binario se pueden dividir en subárboles izquierdo y derecho, y el orden no se puede invertir, por lo que el árbol binario esárbol ordenado
Nota: Cualquier árbol binario se compone de las siguientes situaciones:
Los árboles binarios generalmente se pueden almacenar mediante dos estructuras:Una estructura secuencial, una estructura en cadena.
Los árboles binarios ordinarios no son adecuados para el almacenamiento en matrices porque puede haber mucho espacio desperdiciado.yLos árboles binarios completos son más adecuados para el almacenamiento de estructuras secuenciales. .En realidad, normalmenteUn montón (un árbol binario) utiliza una serie de estructuras secuenciales para almacenarCabe señalar que el montón aquí y el montón en el espacio de direcciones del proceso virtual del sistema operativo son dos cosas diferentes. Una es una estructura de datos y la otra es una segmentación de área que administra la memoria en el sistema operativo.
Para una implementación y aplicación específicas, consulte:[Estructura de datos] 08. Montón y aplicaciones de montón
La forma más sencilla de aprender la estructura de un árbol binario es recorrerla.así llamadoEl recorrido del árbol binario (Traversal) consiste en realizar las operaciones correspondientes en los nodos del árbol binario en secuencia de acuerdo con ciertas reglas, y cada nodo solo se opera una vez. . Las operaciones realizadas al acceder a los nodos dependen del problema específico de la aplicación. El recorrido es una de las operaciones más importantes en un árbol binario y también es la base para otras operaciones en un árbol binario.
//根 左子树 右子树
void PrevOrder(pTreeNode root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%d ", root->val);
PrevOrder(root->left);
PrevOrder(root->right);
}
La siguiente figura muestra el proceso recursivo:
//左子树 根 右子树
void InOrder(pTreeNode root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->left);
printf("%d ", root->val);
InOrder(root->right);
}
El siguiente es el proceso recursivo:
//左子树 右子树 根
void PostOrder(pTreeNode root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->left);
PostOrder(root->right);
printf("%d ", root->val);
}
El siguiente es el proceso recursivo:
Recorrido de orden de nivel: además del recorrido de orden previo, recorrido de orden y recorrido de orden posterior, el recorrido de orden de nivel también se puede realizar en árboles binarios. Supongamos que el número de nivel del nodo raíz del árbol binario es 1. El recorrido de orden de nivel comienza desde el nodo raíz del árbol binario. Primero, visita el nodo raíz del primer nivel y luego visita los nodos del segundo. nivel de izquierda a derecha, y luego el tercer nivel Los nodos de la capa, y así sucesivamente.El proceso de visitar los nodos del árbol capa por capa de arriba a abajo y de izquierda a derecha es un recorrido por orden de capas.。
Ilustración:
Aquí intervenimos en la cola para realizar un recorrido de preorden del árbol binario.
// 层序遍历
void LevelOrder(pTreeNode root)
{
Queue q;
QueueInit(&q);
if (root)
{
QueuePush(&q, root);
}
while (!QueueEmpty(&q))
{
pTreeNode front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
{
printf("NULL ");
}
else
{
printf("%d ", front->val);
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
}
QueueDestory(&q);
}
Para crear y destruir un árbol binario, usamosRecorrido de árbol binarioPor ejemplo.
//二叉树的创建
struct TreeNode* Creat(char* arr,int n,int* i)
{
if(*i<n&&arr[*i]=='#')
{
(*i)++;
return NULL;
}
TreeNode* newnode=(TreeNode*)malloc(sizeof(TreeNode));
newnode->left=NULL;
newnode->right=NULL;
newnode->val=arr[(*i)++];
newnode->left=Creat(arr,n,i);
newnode->right=Creat(arr,n,i);
return newnode;
}
//二叉树的销毁
void TreeDestroy(struct TreeNode* root)
{
if(root==NULL)
{
return;
}
TreeDestroy(root->left);
TreeDestroy(root->right);
free(root);
}
Todas las siguientes operaciones se llevan a cabo según la idea de recorrido.
// 二叉树节点个数
int TreeSize(pTreeNode root)
{
if (root == NULL)
{
return 0;
}
return TreeSize(root->left) + TreeSize(root->right) + 1;
}
// 二叉树叶子节点个数
int TreeLeafSize(pTreeNode root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
// 二叉树第k层节点个数
int TreeLevelKSize(pTreeNode root, int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return TreeLevelKSize(root->left, k - 1) + TreeLevelKSize(root->right, k - 1);
}
// 二叉树查找值为x的节点
pTreeNode TreeFind(pTreeNode root, TreeDataType x)
{
if (root == NULL)
{
return NULL;
}
//相等就返回
if (root->val == x)
return root;
//找左子树
pTreeNode left=TreeFind(root->left, x);
if (left)
{
return left;
}
//找右子树
pTreeNode right = TreeFind(root->right, x);
if (right)
{
return right;
}
//都没找到
return NULL;
}
//二叉树的高度
int TreeHeight(pTreeNode root)
{
if (root == NULL)
{
return 0;
}
int max_left = TreeHeight(root->left) ;
int max_right = TreeHeight(root->right);
return max_left > max_right ? max_left + 1 : max_right + 1;
}
//判断是否是完全二叉树
bool TreeComplete(pTreeNode root)
{
Queue q;
QueueInit(&q);
if (root)
{
QueuePush(&q, root);
}
while (!QueueEmpty(&q))
{
pTreeNode front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
{
break;
}
else
{
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
}
while (!QueueEmpty(&q))
{
pTreeNode front = QueueFront(&q);
QueuePop(&q);
if (front)
{
QueueDestory(&q);
return false;
}
}
QueueDestory(&q);
return true;
}