Árvore binária de pistas
Nota: código fonte
- O conceito de árvore de pista binária A árvore de pista
binária é baseada na estrutura de árvore binária tradicional, mais sinalizadores para determinar se os filhos esquerdo e direito do nó são LTag, RTag vazios.
Quando o filho da esquerda está vazio, lchild aponta para o nó predecessor do nó, e quando o filho da direita está vazio, rchild aponta para o nó sucessor do nó. Para aumentar a densidade de armazenamento da lista vinculada. Abaixo, damos a estrutura da árvore de pistas binárias:
typedef struct BiTNode
{
char data;//数据域
int LTag = 0;//左标签
int RTag = 0;//右标签
struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准
struct BiTNode* rchild = nullptr;//左右孩子
}BiTNode, * BiTree;
-
Em comparação com a árvore binária geral, a vantagem da árvore de pistas binárias é a
lista vinculada binária como estrutura de armazenamento. Ela só pode encontrar as informações dos filhos esquerdo e direito do nó, mas não pode obter as informações do predecessor e do sucessor do nó em qualquer sequência. Essas informações só podem ser percorridas Ele só pode ser obtido no processo dinâmico, e a árvore de pistas binárias pode armazenar as informações do predecessor e do sucessor nesses processos dinâmicos. E porque a árvore binária geral tem n nós, deve haver um (n + 1) domínio de cadeia vazia (fácil de provar). Portanto, esses domínios de cadeia de ar podem ser totalmente utilizados para armazenar o precursor e informações subsequentes e a densidade de armazenamento pode ser aumentada. -
Criar uma árvore binária
Criamos uma árvore binária percorrendo primeiro, introduzimos primeiro o nó raiz, depois criamos a subárvore esquerda e, em seguida, criamos a subárvore direita (se os dados do nó forem #, significa uma árvore vazia). código mostrado abaixo:
void CreateBiTree(BiTree& T,BiTree P)//先序输入
{
char ch;
cin >> ch;
if (ch == '#') T = NULL;
else
{
T = new BiTNode;//分配空间
T->data = ch;//根节点赋值
T->parent = P;
CreateBiTree(T->lchild,T);//建立左子树
CreateBiTree(T->rchild,T);//建立右子树
}
}
- Árvore binária encadeada de primeira ordem A encadeamento de primeira ordem é
realizada na ordem da esquerda para a raiz. O processo específico é:
primeiro, criamos um BiTree Thrt vazio (por um lado, ele é usado como o nó precursor do primeiro nó e o último nó Nós sucessores. Por outro lado, a árvore binária também pode ser formada em uma lista duplamente vinculada. Ela pode ser percorrida do primeiro nó em sucessão ou do último nó ao predecessor, o que é muito conveniente - ^ - ^ - ), crie um BiTree antes que aponte sempre para o nó recém-visitado.
Em segundo lugar, primeiro encontramos o nó raiz.Se este nó não tiver um filho esquerdo, apontamos lchild para seu predecessor e atribuímos este nó a pre. Se pre não tem filho certo, apontamos o rchild de pre para o nó atual.
Finalmente, repita a subárvore esquerda e, em seguida, repita a subárvore direita.
A árvore que queremos atravessar é a seguinte:
A árvore binária após o encadeamento de pré-encomenda é assim (um pouco feia - ^ - ^ -):
O código está anexado abaixo (pre é uma variável global do tipo BiTree. Se você não quiser a árvore principal do nó, será a primeira mais à esquerda O lchild do nó está vazio e, em seguida, aponta para este nó):
//以结点T为根的子树先序线索化
void PreThreading(BiTree& T)
{
if (T)//T非空
{
if (!T->lchild)//左子树为空
{
T->LTag = 1;
T->lchild = pre;//指向前驱结点
}
else
{
T->LTag = 0;
}
if (!pre->rchild)
{
pre->RTag = 1;
pre->rchild = T;//指向后继结点
}
else
{
T->RTag = 0;
}
pre = T;//pre指向当前节点
if (T->LTag == 0)//这点很重要,只有结点有左孩子的时候才可以遍历左子树,否则会陷入死循环
{
PreThreading(T->lchild);//遍历左子树
}
if (T->RTag == 0)//同上
{
PreThreading(T->rchild);//遍历右子树
}
}
}
//以结点T为根的字树先序线索化
//带头节点的二叉树先序线索化
void PreOrderThreading(BiTree& Thrt, BiTree T)
{
Thrt = new BiTNode;//头节点
Thrt->LTag = 0;//左标签为零,表明有左子树
Thrt->RTag = 1;
Thrt->rchild = Thrt;//右子树指向自己
if (!T)//若为空树,右子树指向自己
{
Thrt->lchild = Thrt;
}
else
{
Thrt->lchild = T;//左指针指向T
pre = Thrt;
PreThreading(T);//进行线索化
pre->rchild = Thrt;//此时pre为最右面的那个节点,让它的右子树为Thrt
pre->RTag = 1;
Thrt->rchild = pre;//Thrt的右子树为pre,形成闭环
}
}
//带头节点的二叉树先序线索化
Nesse ponto, o encadeamento de pré-encomenda da árvore binária acabou.
Árvore binária encadeada de ordem média As etapas da árvore binária encadeada de ordem média são semelhantes à árvore binária de pré-ordem. As etapas específicas são:
1. Percorra a subárvore esquerda, encontre o nó mais à esquerda, deixe seu filho apontar para pré e apontar pré para o nó atual .
2. Repita as etapas acima para o nó raiz.
3. Atravessando a subárvore direita.
A seguir está um diagrama de uma árvore binária encadeada em ordem (o diagrama ainda é muito feio):
O código está anexado abaixo (o código ainda é esse código, mas a ordem foi alterada):
//以结点T为根的子树中序线索化
void InThreading(BiTree &T)
{
if (T)//T非空
{
InThreading(T->lchild);//遍历左子树
if (!T->lchild)//左子树为空
{
T->LTag = 1;
T->lchild = pre;
}
else
{
T->LTag = 0;
}
if (!pre->rchild)
{
pre->RTag = 1;
pre->rchild = T;
}
else
{
T->RTag = 0;
}
pre = T;
InThreading(T->rchild);//遍历右子树
}
}
//以结点T为根的字树中序线索化
//带头节点的二叉树中序线索化
void InOrderThreading(BiTree& Thrt, BiTree T)
{
Thrt = new BiTNode;
Thrt->LTag = 0;
Thrt->RTag = 1;
Thrt->rchild = Thrt;
if (!T)
{
Thrt->lchild = Thrt;
}
else
{
Thrt->lchild = T;
pre = Thrt;
InThreading(T);
pre->rchild = Thrt;
pre->RTag = 1;
Thrt->rchild = pre;
}
}
//带头节点的二叉树中序线索化
- Árvore binária de pista
pós-ordem A árvore binária de pista pós-ordem é a mesma que a ideia anterior:
1. Primeiro atravesse a subárvore esquerda, encontre o nó mais à esquerda, se seu lchild estiver vazio, este lchild aponta para pré, se o rchild de pre estiver vazio, então O rchild de pre aponta para o nó atual.
2. Atravesse a subárvore direita e prossiga com as etapas acima.
3. Finalmente, execute as operações acima no nó raiz.
A seguir está um diagrama da árvore binária de dicas pós-pedido (o diagrama ainda é muito feio):
Anexe o código:
//以结点T为根的子树后序线索化
void PosThreading(BiTree& T)
{
if (T)//T非空
{
PosThreading(T->lchild);//遍历左子树
PosThreading(T->rchild);//遍历右子树
if (!T->lchild)//左子树为空
{
T->LTag = 1;
T->lchild = pre;
}
else
{
T->LTag = 0;
}
if (!pre->rchild)
{
pre->RTag = 1;
pre->rchild = T;
}
else
{
T->RTag = 0;
}
pre = T;
}
}
//以结点T为根的字树后序线索化
//带头节点的二叉树后序线索化
void PosOrderThreading(BiTree& Thrt, BiTree T)
{
Thrt = new BiTNode;
Thrt->LTag = 0;
Thrt->RTag = 1;
Thrt->rchild = T;
if (!T)
{
Thrt->lchild = Thrt;
}
else
{
Thrt->lchild = T;
pre = Thrt;
PosThreading(T);
}
}
//带头节点的二叉树后序线索化
Vendo isso, a pista da árvore de pistas binárias acabou, quando nossa história ainda não acabou (a vida não é apenas sobre as pistas que estão diante de nós, mas também a travessia da árvore binária). Vamos falar sobre a travessia da árvore de dicas da árvore binária.
- Atravessando a árvore de pistas da pré-ordem Ao
cruzar a árvore de pistas da pré-ordem, primeiro defina uma BiTree p, apontando para a subárvore esquerda do nó principal p, ou seja, p = T-> filho.
Em seguida, queremos produzir as informações de p. Se o nó tiver uma subárvore à esquerda, então p aponta para a subárvore à esquerda e exibe as informações do nó. Se não houver nenhuma subárvore à esquerda, então p aponta para a subárvore à direita e exibe as informações.
Finalmente, quando p aponta para T, o laço termina.
A seguir está um exemplo de passagem de pré-encomenda (a animação não é bem feita):
O código está anexado abaixo (é tão simples):
//遍历先序线索二叉树
void PreTraverse_Thr(BiTree T)
{
BiTree p = T->lchild;
while (p != T)
{
cout << p->data;
if (p->LTag == 0)
{
p = p->lchild;
}
else
{
p = p->rchild;
}
}
}
//遍历先序线索二叉树
- Percorrendo a árvore de pistas de ordem média
A ideia de percorrer a árvore de pistas de ordem média é seguir a ideia raiz esquerda-direita :
primeiro, encontre o nó mais à esquerda p e produza o valor do nó.
Então, se rchild = 1, p = p-> rchild do nó à esquerda, produza o valor do nó e repita.
Se estiver passando para o nó raiz p, p = p-> rchild. No loop, até que p seja o fim de T.
A seguir está um exemplo de travessia de ordem intermediária (a animação ainda não está bem feita):
anexe o código (ainda tão simples quanto isso):
//遍历中序线索二叉树
void InTraverse_Thr(BiTree T)
{
BiTree p = T->lchild;//
while (p != T)
{
while (p->LTag == 0)
{
p = p->lchild;
}
cout << p->data;
while (p->RTag == 1 && p->rchild != T)
{
p = p->rchild;
cout << p->data;
}
p = p->rchild;
}
}
//遍历中序线索二叉树
- Percorrendo a árvore de pistas pós-pedido
Percorrer a árvore de pistas pós-pedido é um pouco difícil. A estrutura binária original da árvore precisa ser alterada. Precisamos adicionar um nó pai para cada nó para resolver o problema de não ser capaz de acessar o nó pai ao atravessar para a subárvore certa.
código mostrado abaixo:
typedef struct BiTNode
{
char data;//数据域
int LTag = 0;//左标签
int RTag = 0;//右标签
struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准
struct BiTNode* rchild = nullptr;//左右孩子
struct BiTNode* parent = nullptr;//双亲
}BiTNode, * BiTree;
Com a estrutura acima, é muito mais simples percorrer a árvore de pistas na ordem subsequente.
1. Em primeiro lugar, devemos encontrar o nó mais à esquerda p primeiro, como o percurso de ordem do meio, e emitir o valor do nó, se p-> rchild == 1; p = p-> rchild, o valor do nó de saída, repetindo, Até p-> lchild == 0 e p-> rchild == 0.
2. Neste momento p é o nó raiz (relativamente falando), precisamos continuar percorrendo pelo nó pai e emitir o valor do nó. Até encontrarmos o nó raiz real p, então p = p-> rchild.
3. Repita as etapas 1 e 2 até que o nó pai de p esteja vazio.
Diagrama de demonstração:
anexe o código (não é simples desta vez):
//后序遍历需要双亲节点
void PosTraverse_Thr(BiTree T)
{
BiTree root = T->lchild;//初始节点
BiTree prev = nullptr;//记录上一个节点
while (root)
{
if (root->lchild == root->rchild)//如果双亲没有左子树或者右子树
{
root = root->rchild;
}
while (root->LTag == 0 && root->lchild != prev)//找到最左边的节点
{
root = root->lchild;
}
while (root->RTag == 1)//输出并遍历节点的后继
{
cout << root->data;
prev = root;//记录上一个节点
root = root->rchild;
}
if (root == T->lchild)//判断是不是根节点
{
cout << root->data;
return;
}
while (root->rchild == prev)//不是根节点,访问当前节点的双亲节点
{
cout << root->data;
prev = root;
root = root->parent;
if (root == nullptr)//遍历到根节点,退出
{
return;
}
}
if (root->RTag == 0)//遍历右子树
{
root = root->rchild;
}
}
}
//遍历后序线索二叉树