Diretório de artigos
Prefácio
A árvore binária é uma das estruturas de dados mais básicas e tem aplicações muito importantes na ciência da computação. A travessia da árvore binária refere-se à travessia de todos os nós em uma árvore binária em uma determinada ordem, que é uma das operações mais básicas de uma árvore binária.
Como percorrer uma árvore binária
Construa uma árvore binária
A função createNode
cria um novo nó da árvore binária e retorna um ponteiro para o nó. Esta função recebe um parâmetro do tipo inteiro val, que é utilizado para representar o valor do novo nó, ambos os ponteiros do nó NULL
.
// 创建新节点的函数
struct TreeNode *createNode(int val) {
struct TreeNode *node = (struct TreeNode*) malloc(sizeof(struct TreeNode));
node->val = val;
node->left = NULL;
node->right = NULL;
return node;
}
A buildTree
função é construir uma árvore binária com estrutura fixa e retornar o ponteiro do nó raiz. Dentro da função, primeiro crie um nó raiz com valor 1, depois createNode
crie todos os nós da árvore binária por meio da função e defina seus valores e ponteiros de subárvore correspondentes.
// 构建一棵二叉树
struct TreeNode *buildTree()
{
struct TreeNode *root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
root->right->right = createNode(7);
root->left->left->left = createNode(8);
root->left->left->right = createNode(9);
return root;
}
Depois de passar buildTree
a função, obtemos a árvore binária:
Percorrer recursivamente uma árvore binária
As etapas específicas da travessia recursiva são as seguintes:
- Primeiro determine se o nó atual está vazio e, se estiver vazio, retorne-o diretamente.
- Percorra recursivamente a subárvore esquerda do nó atual, ou seja, chame inOrder(node->left). 【1】
- Percorra o nó atual , ou seja, produza o valor node->val do nó node. 【2】
- Percorra recursivamente a subárvore direita do nó atual, ou seja, chame inOrder(node->right). 【3】
Então, o código detalhado de travessia em ordem é o seguinte:
// 递归中序遍历
void inOrder(struct TreeNode*node)
{
// 判断节点是否为空
if (node == NULL) return;
// 先访问左孩子
inOrder(node->left);
// 访问自己
printf(" %d ",node->val);
// 访问右孩子
inOrder(node->right);
}
Nota: Mover a etapa da ideia [2] para antes de [1] é uma passagem de pré-pedido. Depois de mover a etapa da ideia [2] para [3], é a travessia da pré-ordem.
Travessia não recursiva de uma árvore binária
A inOrder2
função é realizar a travessia em ordem não recursiva da árvore binária. Aqui, uma pilha é usada para simular a operação recursiva de travessia em ordem. A ideia da função é:
A função aceita dois parâmetros
root
(o nó raiz da árvore binária) enodeCount
(o número total de nós), ondenodeCount
é usado para inicializar o tamanho da pilha de travessia.Primeiro, use
malloc
a função para alocar umanodeCount
matriz de ponteiros de tamanhodata
para armazenar ponteiros de nós (simulando uma estrutura de pilha).Em segundo lugar, defina um ponteiro para o topo da pilha
dataLen
e inicialize-o com 0, e inicialize um ponteirop
para armazenar o ponteiro do nó atual.Depois disso, entre no loop de travessia. Determine se o nó atual
p
está vazio. Caso contrário, coloque-o na pilha ep
atualize seu nó filho esquerdo. Caso contrário, retire um nó da pilhap
, produza seu valor ep
atualize seu nó filho direito. Faça um loop até que a pilha esteja vazia e o nó atualp
seja NULL.Finalmente, o espaço de pilha alocado dinamicamente é liberado
data
.
// 非递归中序遍历
void inOrder2(struct TreeNode*root,int nodeCount)
{
// 初始化顺序栈
struct TreeNode* *data = (struct TreeNode**)malloc(sizeof(struct TreeNode*)*nodeCount);
// 栈顶指针
char dataLen = 0;
struct TreeNode*p = root;
// 遍历
while (p || dataLen)
{
// 节点不为空
if (p)
{
// 先入栈再访问下一个左孩子
data[dataLen++] = p;
p = p->left;
}
else
{
// 到达叶子节点后 应该先访问叶子节点再回溯到父节点最后访问兄弟
p = data[--dataLen];
printf(" %d ",p->val);
p = p->right;
}
}
// 注销栈空间
free(data);
}
Como a ideia desta função é usar a pilha para simular operações recursivas, ela economiza mais memória que o método recursivo e pode controlar melhor a ordem de execução da função.
Passagem de nível
A função levelOrder
é realizar o percurso hierárquico da árvore binária, ou seja, percorrer os nós na ordem da esquerda para a direita em cada camada e gerar o valor do nó. A função aceita dois parâmetros: o nó raiz da árvore binária root
e o número total de nós nodeCount
. Dentre eles, nodeCount
utilizado para inicializar o tamanho da fila sequencial.
Dentro da função, primeiro use
malloc
a função para alocar dinamicamente umanodeCount
matriz de ponteiros de tamanhoqueue
para armazenar ponteiros de nós (simulando uma estrutura de fila). A função também define um ponteiro inicialfront
e um ponteiro final da filarear
ep
inicializa os ponteiros para o nó raizroot
.Primeiro, adicione o nó raiz à fila, que é o ponteiro
p
.Em seguida, determine se o ponteiro final da fila está na frente do ponteiro principal (a fila está vazia). Se a condição for verdadeira, ele entra no loop de travessia, retira um nó do topo da fila
p
e determina se o nó atualp
está vazio.Dentro do loop, o valor do nó é a primeira saída
p
, ou seja, o nó acessado. Posteriormente, sep
o filho esquerdo do nó existir, seu filho esquerdo será enfileirado. Sep
o nó filho certo do nó existir, seu nó filho certo será enfileirado.Finalmente, prossiga para o próximo ciclo e repita as etapas acima.
// 层次遍历二叉树
void levelOrder(struct TreeNode*root,int nodeCount)
{
// 定义一个顺序队列用于辅助层序遍历
struct TreeNode* *queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*)*nodeCount);
// 队头 队尾
int front = 0,rear = 0;
struct TreeNode*p = root;
// 将根节点加入队列
queue[rear++] = p;
// 遍历
while ((rear != 0 && rear > front))
{
// [1] 出队列
p = queue[front++];
// [2] 访问节点
if (p)
printf(" %d ",p->val);
// [3] 将左节点入队列
if (p->left)
queue[rear++] = p->left;
// [4] 将右节点入队列
if (p->right)
queue[rear++] = p->right;
}
}
Nota: O design do algoritmo fornecido aqui é um percurso hierárquico de cima para baixo, da esquerda para a direita. Se você precisar alterá-lo para um percurso hierárquico de cima para baixo, da direita para a esquerda, então você só precisa alterar o loop while
. trocar as etapas [3] e [4].
Esta função usa o recurso primeiro a entrar, primeiro a sair da fila para percorrer a árvore binária em ordem hierárquica. É relativamente simples e fácil de entender e é aplicável a qualquer tipo de árvore binária.
Exemplo de resultados de árvore binária
Resultados teóricos:
Resultados da execução do código:
Resumir
Este artigo apresenta quatro métodos de travessia de árvores binárias: travessia de pré-ordem, travessia em ordem, travessia de pós-ordem e travessia hierárquica. Entre eles, a travessia pré-ordem, a travessia em ordem e a travessia pós-ordem são coletivamente chamadas de travessia em profundidade, enquanto a travessia hierárquica é a travessia em largura.
Tanto a travessia em profundidade quanto a travessia em largura têm suas próprias características e são frequentemente usadas para resolver problemas diferentes. O percurso em profundidade é mais adequado para situações em que toda a árvore precisa ser percorrida para obter informações globais, como resolver a profundidade da árvore, problemas de caminho e o maior diâmetro dos nós. A travessia em largura é mais adequada para encontrar nós alvo entre nós na mesma camada da árvore, como percorrer uma árvore binária por camada, resolver a profundidade mínima de uma árvore binária, etc.