Estructura de datos elemental: tema del árbol binario


1. Árbol binario de un solo valor

árbol binario de valor único

Un árbol binario es un árbol binario de un solo valor si cada nodo del árbol tiene el mismo valor. Devuelve verdadero sólo si el árbol dado es un árbol binario de un solo valor; en caso contrario, devuelve falso.

inserte la descripción de la imagen aquí
Es necesario asegurarse de que todos sean iguales, por lo que, naturalmente, los subárboles izquierdo y derecho deben estar bien. Primero piense en un pequeño problema. Al atravesar un subárbol, eventualmente encontrará un espacio vacío. Si encuentra un espacio vacío, debe devolver verdadero para permitir que regrese de manera segura sin afectar el juicio. Esto significa que debemos atravesar de forma recursiva. Entonces, comenzando desde la raíz, primero hay un juicio, y si está vacío, devuelve verdadero. Después de omitir este juicio, ¿si pasa al siguiente paso? Queremos que la raíz sea igual a todos los demás números. Lo más fácil de juzgar es si los subárboles izquierdo y derecho de la raíz son iguales, por lo que podemos escribir esta declaración de juicio.

if(root->val != root->right->val)

Esta frase sigue siendo una falta de consideración. Ya sabes, ahora nuestra idea es usar un nodo raíz para comparar si es igual a sus dos subárboles, siempre que ambos subárboles existan. El juicio anterior es juzgar la raíz, es decir, juzgar el nodo raíz, pero no juzgar sus subárboles, por lo que debe escribirse así: if(root->right && root->right->val). Si se cumplen las condiciones, entonces este no es un árbol binario de un solo valor y debe devolver falso. El falso devuelto también debe hacer que todas las recursiones anteriores sean falsas y finalmente falsas.

No pensemos en esto por ahora. Volviendo al código de ahora, solo escribimos el lado derecho y también necesitamos escribir el lado izquierdo. Lo mismo es cierto, es decir, ambos si deben ser juzgados. Después de escribir estos tres juicios, hay que recurrir. Como se mencionó anteriormente, falso debe formar el todo, toda recursividad es falsa y también sabemos por el título que los valores de los nodos del subárbol izquierdo y derecho deben ser iguales a la raíz, por lo que cuando continúe avanzando hacia abajo, necesitas usar && para conectarte

return isUnivalTree(root->left) && isUnivalTree(root->right);

código general

bool isUnivalTree(struct TreeNode* root) 
{
    
    
    if(!root) return true;
    if(root->left && root->val != root->left->val)
        return false;
    if(root->right && root->val != root->right->val)
        return false;
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

Esta pregunta se acabó. Hay otra forma de escribir en la solución del problema, que es ingresar recursividad al juzgar si la izquierda y la derecha son iguales, pero esto no es apropiado. Si comienza desde la raíz, el valor de su nodo del subárbol derecho no es igual. y el programa juzga el subárbol izquierdo antes. Si son iguales, comenzará la recursividad para continuar buscando el subárbol izquierdo, entonces se desperdiciará espacio y tiempo, por lo que es mejor recurrir después de que se juzguen los subárboles izquierdo y derecho existentes. .

En segundo lugar, compruebe si los dos árboles son iguales.

mismo arbol

Dados los nodos raíz p y q de dos árboles binarios, escriba una función para verificar si los dos árboles son iguales. Dos árboles se consideran idénticos si son estructuralmente idénticos y los nodos tienen el mismo valor.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Al comparar dos árboles, los valores deben ser iguales y la estructura debe ser la misma. Comenzando desde la raíz, si los dos valores son iguales, esto debe cumplir con los requisitos, pero no puede devolver verdadero en este momento, tenemos que continuar juzgando, dejar que la recursividad continúe, mirar el subárbol y juzgar si la estructura es la misma, pero no igual Ciertamente no, no es el mismo árbol, entonces puedes escribir que si los valores no son iguales, devuelve falso. Para permitir que el programa continúe al nivel más bajo y juzgue si la estructura general es la misma, otras condiciones de juicio no deben obstaculizar el progreso de la recursividad hasta que lleguemos al vacío, como el subárbol izquierdo de 2 en el ejemplo anterior. 1, esta vez está vacío, si el otro árbol también está vacío en este momento, entonces no hay problema, devuelve verdadero y luego regresa para juzgar el subárbol derecho de su nodo padre; si uno está vacío y el otro no vacío, entonces debe estarlo. Si no, simplemente devuelve falso directamente. Y aquí hay una forma inteligente de escribir: primero escriba el juicio de que ambos están vacíos, si no, entonces uno está vacío y el otro no, o ambos no están vacíos, luego puede escribir que si uno está vacío, significa que la estructura es if(p == NULL || q == NULL)diferente Sí, porque está vacía y no vacía.

Se han escrito tres juicios en el párrafo anterior, y estos tres juicios son suficientes para completar los requisitos del tema, y ​​​​al final se puede agregar una recursión de los subárboles izquierdo y derecho.

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    
    
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if (p->val != q->val) return false;
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

3. Un subárbol de otro árbol.

subárbol de otro árbol

Se le proporcionan dos árboles binarios, raíz y subraíz. Prueba que root contiene un subárbol con la misma estructura y valores de nodo que subRoot. Devuelve verdadero si está presente; en caso contrario, devuelve falso. Un subárbol del árbol binario incluye un determinado nodo del árbol y todos los nodos descendientes de este nodo. Un árbol también puede verse como un subárbol de sí mismo.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Como queremos encontrar un subárbol, es decir, necesitamos encontrar la misma parte de subRoot en la raíz, podemos usar isSameTree que acabamos de escribir aquí. root tiene muchos subárboles, solo podemos compararlos uno por uno para ver si son iguales que subroot, comenzando desde la raíz, todo el árbol también es un subárbol de root, así que comience a comparar desde root, si root y subroot son los mismo árbol, luego devuelve verdadero. Si una comparación encuentra que no son iguales, el programa debe continuar buscando. Como en el ejemplo 2, hay un 0 debajo de 2, luego comienza desde 4. Las siguientes partes son diferentes, no iguales, no se devuelve nada y Continuar buscando Se comparan los subárboles izquierdo y derecho de 4. Aquí pensarás que tenemos que escribir dos fórmulas, un parámetro es raíz->izquierda, el otro es raíz->derecha, siempre que uno de estos dos sea verdadero, significa que es un subárbol, entonces el programa puede final, todo uso o. Sigue comparando, ¿cuándo parará? Si una ruta está vacía, significa que el árbol debajo del nodo en esta carretera no es lo mismo que subRoot, lo que significa que esta carretera no cumple con las condiciones, luego devuelve falso, no importa si devuelve falso, porque ha sido escrito o antes, por lo que el programa también juzgará si otra ruta es factible antes de dar el resultado final.

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    
    
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot) {
    
    
    if(!root) return false;
    if(isSameTree(root, subRoot)) return true;
    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}

4. Recorrido previo al pedido del árbol binario

recorrido de preorden

Dada la raíz del nodo raíz de su árbol binario, devuelva el recorrido de preorden de sus valores de nodo.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Resuelve usando un algoritmo recursivo. El recorrido del pedido anticipado es relativamente simple, pero aquí es necesario colocar el resultado del recorrido en una matriz, * returnSize es el tamaño de la matriz y finalmente devolver la matriz. Aunque el rango del número de nodos se proporciona en la sugerencia, es más adecuado para todos los árboles usar una función para calcular el número de nodos del árbol binario dado.

int TreeSize(struct TreeNode* root)
{
    
    
    if root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

void preorder(struct TreeNode* root, int* array, int* i)
{
    
    
    if(root == NULL)
    {
    
    
        return;
    }
    array[(*i)++] = root->val;
    preorder(root->left, array, i);
    preorder(root->right, array, i);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    
    
    *returnSize = TreeSize(root);
    int* array = (int*)malloc(sizeof(int) * (*returnSize));
    int i  = 0;
    preorder(root, array, &i);
    return array;
}

Cinco, árbol binario simétrico

Árbol binario simétrico

Dada la raíz del nodo raíz de un árbol binario, verifique si es simétrica en el eje.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Para un árbol binario simétrico, los subárboles izquierdo y derecho de la raíz deben compararse para ver si son simétricos. Aquí puede pensar en el mismo juicio, pero hay ciertas diferencias. El valor del nodo raíz también debe ser igual El subárbol izquierdo se compara con el subárbol derecho del otro, y se compara el subárbol derecho y el subárbol izquierdo del otro.

Otra idea es voltear el árbol binario, voltear los subárboles izquierdo y derecho, luego puede comparar directamente lo mismo, voltear no es difícil, los eventos principales se reducen, atravesar los subárboles en el nivel más bajo, luego voltear uno por uno, subir y finalmente completa el giro. Pero, de hecho, esta idea no funciona. Si se voltea el árbol binario, el árbol binario original no existirá después del volteo. Solo podemos hacer una copia y luego voltearlo nuevamente, pero la copia tiene que pasar por recursividad nuevamente. , entonces la idea es más complicada.

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    
    
    if(!p && !q)
    {
    
    
        return true;
    }
    if((p == NULL || q == NULL) || (p->val != q->val))
    {
    
    
        return false;
    }
    return isSameTree(p->left, q->right) && isSameTree(p->right, q->left);
}

bool isSymmetric(struct TreeNode* root){
    
    
    if(root == NULL)
    {
    
    
        return true;
    }
    return isSameTree(root->left, root->right);
}

Aquí las dos declaraciones falsas devueltas se fusionan.

Finalizar.

Supongo que te gusta

Origin blog.csdn.net/kongqizyd146/article/details/131999337
Recomendado
Clasificación