Árbol binario (1): descripción general (con implementación de árbol de búsqueda binaria)

Los árboles y los gráficos son estructuras de datos no lineales típicas

Definición de
árbol : Un árbol es un conjunto finito de n (n> = 0) nodos. Cuando n = 0, se convierte en un árbol vacío. En cualquier árbol no vacío, tiene las siguientes características:

  1. Solo un nodo específico se convierte en el nodo raíz
  2. Cuando n> 1, los nodos restantes se pueden dividir en m (m> 0) conjuntos finitos irrelevantes Cada conjunto es también un árbol y se convierte en un subárbol de la raíz.
树的最大层级数,称为树的高度或者深度

La definición de un
árbol binario : un árbol binario se refiere a该树的每个节点最多有2个子节点,有可能时两个,也可能只有1个,或者是没有

Dos formas especiales de árboles binarios:

满二叉树:一个二叉树的所有非叶子节点都存在左孩子和右孩子,并且所有叶子节点都在同一层级上,这个树就是满二叉树
完全二叉树:一个二叉树的`最后一个节点之前`所有非叶子节点都存在左孩子和右孩子,并且所有叶子节点都在同一层级上

La estructura de almacenamiento físico del árbol binario

1. Estructura de almacenamiento en cadena

Usando la estructura de almacenamiento de la lista enlazada, cada nodo del árbol binario contiene 3 partes

  • Variable de datos para almacenar datos
  • Puntero izquierdo al niño izquierdo
  • Puntero derecho al niño correcto

2. Matriz

Cuando se utiliza el almacenamiento de matriz, los nodos del árbol binario se colocan en las posiciones correspondientes en la matriz de acuerdo con el orden jerárquico. Si el hijo izquierdo o derecho de un nodo está vacante, la posición correspondiente de la matriz también está vacante

¿Por qué está diseñado así? Porque esto puede ubicar fácilmente los nodos secundarios y los nodos principales del árbol binario en la matriz

Suponiendo que el subíndice de un nodo padre es padre, entonces el subíndice de su nodo hijo izquierdo es 2 padre + 1, y el subíndice del nodo hijo derecho es 2 padre + 2.

en turno. Supongamos que el subíndice de un nodo hijo izquierdo es leftchild, entonces su subíndice del nodo padre es (leftchild-1) / 2

显然,对于一个稀疏的二叉树来说,用数组表示法是非常浪费空间的。
然而因为完全二叉树的特殊性,用数组来存储是非常合适的,比如二叉堆,一种特殊的完全二叉树

Aplicación del árbol binario

Hay muchas formas de árboles binarios, además de los árboles binarios generales, de los árboles binarios completos mencionados anteriormente, árboles binarios completos y montones binarios, etc.

Entonces, ¿cuáles son las funciones de tantos tipos de árboles binarios?

  1. Utilizado para operaciones de búsqueda
  2. Mantener el orden relativo entre elementos

Árbol de búsqueda binaria

También conocido como árbol de ordenación binaria, árbol de búsqueda binaria, etc. Como su nombre lo indica, los elementos de este árbol binario tienen un cierto orden y son fáciles de encontrar

definición:

  1. Si el subárbol izquierdo no está vacío, entonces左子树上所有节点的值均小于根节点的值
  2. Si el subárbol derecho no está vacío, entonces右子树上所有节点的值均大于根节点的值
  3. El subárbol izquierdo y el subárbol derecho también son árboles de búsqueda binarios
  4. 没有键值相等的结点

Aquí usamos la definición 1. Hay tres definiciones ( árbol de búsqueda binario de la Enciclopedia Baidu ) que son correctas y deben seleccionarse de acuerdo con las diferentes necesidades durante el desarrollo.

Golang implementa un árbol de búsqueda binario:

package main

import "fmt"

// 二叉树
type BinaryTree struct {
    
    
	HeadNode *TreeNode
}

//二叉树节点
type TreeNode struct {
    
    
	Data   int32     // 链表上的数据
	Left   *TreeNode // 指针指向左孩子节点
	Right  *TreeNode // 指针指向右孩子节点
}

// 判断二叉树是否为空树,只需要判断第一个元素是否是 nil
func (self *BinaryTree) IsEmpty() bool {
    
    
	if self.HeadNode == nil {
    
    
		return true
	} else {
    
    
		return false
	}
}

// 在二叉查找树里添加数据
func (self *BinaryTree) Add(value int32) bool {
    
    
	neWNode := &TreeNode{
    
    Data: value,}
	node := self.HeadNode
	if node == nil {
    
    
		self.HeadNode = neWNode
		return true
	}
	for node.Data!=value {
    
    
		if value < node.Data {
    
    
			if node.Left!=nil{
    
    
				node = node.Left
			}else {
    
    
				node.Left=neWNode
				return true
			}
		}
		if value > node.Data {
    
    
			if  node.Right!=nil{
    
    
				node = node.Right
			}else {
    
    
				node.Right=neWNode
				return true
			}
		}
	}
	return false
}

// 查找元素所在的节点
func (self *BinaryTree) Get(value int32) *TreeNode {
    
    
	node := self.HeadNode
	for node != nil {
    
    
		if value < node.Data {
    
    
			node = node.Left
		} else if value > node.Data {
    
    
			node = node.Right
		} else {
    
    
			return node
		}
	}
	return nil
}

func NewBinaryTree() BinaryTree {
    
    
	BinaryTree := BinaryTree{
    
    HeadNode: nil}
	return BinaryTree
}

func main() {
    
    
	binaryTree := NewBinaryTree()
	fmt.Println(binaryTree.IsEmpty())
	fmt.Println(binaryTree.Add(3))
	fmt.Println(binaryTree.Add(3))
	fmt.Println(binaryTree.Add(2))
	fmt.Println(binaryTree.Add(4))
	fmt.Println(binaryTree.HeadNode.Data)
	fmt.Println(binaryTree.HeadNode.Right.Data)
	fmt.Println(binaryTree.HeadNode.Left.Data)
	fmt.Println(binaryTree.Get(4).Data)
	fmt.Println(binaryTree.IsEmpty())
}

Complejidad temporal del árbol de búsqueda binaria:

Para un árbol de búsqueda binario con una distribución de nodos relativamente equilibrada, si el número total de nodos es n, la complejidad temporal de la búsqueda de nodos es O (logn), que es lo mismo que la profundidad del árbol.
Este método de búsqueda paso a paso comparando el tamaño es muy similar al algoritmo de búsqueda binaria

Pero para casos extremos (el tamaño de los datos aumenta o disminuye cada vez que se insertan los datos), solo aparece la mitad del árbol y la complejidad del tiempo de búsqueda se reducirá a O (n)

Para resolver este problema, implica el autoequilibrio del árbol binario, que se presentará más adelante.

Supongo que te gusta

Origin blog.csdn.net/csdniter/article/details/109788469
Recomendado
Clasificación