Estructura de datos ------ Árbol de ordenación binario

Árbol de clasificación binaria

Primer vistazo a una demanda

Darle una secuencia numérica (7,3, 10, 12,5,1,9), que requiere la capacidad de consultar y agregar datos de manera eficiente.

Generalmente pensamos primero en matrices

La matriz no está ordenada Ventajas : agregue directamente al final de la matriz, lo cual es rápido. Desventajas : velocidad de búsqueda lenta.
Clasificación de matrices. Ventajas : se puede utilizar la búsqueda binaria. La velocidad de búsqueda es rápida. Desventajas : Para asegurar el orden de la matriz, al agregar nuevos datos, después de encontrar la posición de inserción, se necesitan los siguientes datos moverse en su conjunto, lo cual es lento.

¿Qué pasa con el almacenamiento encadenado?

Independientemente de si la lista vinculada está en orden, la velocidad de búsqueda es lenta y la velocidad de agregar datos es más rápida que la de las matrices, y no es necesario
mover los datos en su totalidad .

Mencionamos anteriormente que el almacenamiento de árboles se puede resolver de manera efectiva.

Árbol de clasificación binaria

Introducción

Árbol de ordenación binaria: BST: (Árbol de ordenación binaria (búsqueda )), para cualquier árbol de ordenación binaria de nodo no hoja,
requiere que el valor del nodo secundario izquierdo sea menor que el valor del nodo actual , el valor del elemento secundario derecho que el nodo actual Gran valor .
Nota especial: si hay los mismos valores, el nodo se puede colocar en el nodo hijo izquierdo o en el nodo hijo derecho

La creación y recorrido del árbol de ordenación binaria.

package 二叉排序树;

public class BinarySortTree {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		int[] arr= {
    
    7,3,10,12,5,1,9};
		BinarySortTreeDemo binarySortTree = new BinarySortTreeDemo();
		//循环添加节点到二叉树
		for (int i = 0; i < arr.length; i++) {
    
    
			binarySortTree.addNode(new Node(arr[i]));
		}
//		System.out.println("中序遍历二叉树");
		binarySortTree.infixOrder();
	}

}
//创建二叉排序树
class BinarySortTreeDemo{
    
    
	private Node root;
	//添加节点的方法
	public void addNode(Node node){
    
    
		if(root == null){
    
    
			root = node;
		}else{
    
    
			root.addNode(node);
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		if(root != null){
    
    
			root.infixOrder();
		}else{
    
    
			System.out.println("空树");
		}
	}
}
class Node{
    
    
	int value;
	Node left;
	Node right;
	public Node(int value) {
    
    
		super();
		this.value = value;
	}
	
	@Override
	public String toString() {
    
    
		return "Node [value=" + value + "]";
	}

	//添加节点的方法
	//递归的形式添加节点,需要满足二叉排序树
	public void addNode(Node node){
    
    
		if(node == null){
    
    
			return;
		}
		//判断传入的节点值,跟当前子树根节点值的关系
		if(node.value < this.value){
    
    
			//如果当前节点的左子节点为空
			if(this.left == null){
    
    
				this.left = node;
			}else
			{
    
    
				this.left.addNode(node);//递归添加
			}
		}else{
    
    
			if(this.right == null){
    
    
				this.right = node;
			}else{
    
    
				this.right.addNode(node);
			}
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		if(this.left != null){
    
    
			this.left.infixOrder();
		}
		System.out.println(this);
		if(this.right != null){
    
    
			this.right.infixOrder();
		}
	}
}

Eliminación del árbol de ordenación binaria

Hay muchas situaciones en esto:

1. Eliminar el nodo hoja

2. Elimina el nodo con un solo subárbol.

3. Elimina el nodo con dos subárboles.

Ideas

Caso 1: eliminar el nodo hoja

1. Primero debe encontrar el targetNode que se va a eliminar.

2. Busque el nodo principal del nodo que se va a eliminar (considere si hay un nodo principal)

3. Determine si targetNode es el nodo secundario izquierdo o el nodo secundario derecho del padre

4. Según lo anterior, elimine el correspondiente

Caso 2: eliminar un nodo con un solo subárbol

1. Primero debe encontrar el targetNode que se va a eliminar.

2. Busque el nodo principal del nodo que se va a eliminar (considere si hay un nodo principal)

3. Determine si el nodo hijo de targetNode es el nodo hijo izquierdo o el nodo hijo derecho

4. Determine si targetNode es el nodo secundario izquierdo o el nodo secundario derecho del padre

5. Si targetNode tiene un nodo secundario izquierdo

1) targetNode es el nodo hijo izquierdo del padre

parent.left = targetNode = left;

2) targetNode es el nodo secundario correcto del padre

parent.left = targetNode .right;

6. Lo mismo ocurre si targetNode tiene un nodo secundario correcto

Caso 3: eliminar un nodo con dos subárboles

1. Primero debe encontrar el targetNode que se va a eliminar.

2. Busque el nodo principal del nodo que se va a eliminar (considere si hay un nodo principal)

3. Encuentre el nodo más pequeño del subárbol derecho de targetNode

4. Utilice variables temporales para guardar el valor de la temperatura del nodo más pequeña

5. Elimina el nodo más pequeño.

6.targetNode.value = temp

Eliminar código de nodo

package 二叉排序树;

public class BinarySortTree {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		int[] arr= {
    
    7,3,10,12,5,1,9,2};
		BinarySortTreeDemo binarySortTree = new BinarySortTreeDemo();
		//循环添加节点到二叉树
		for (int i = 0; i < arr.length; i++) {
    
    
			binarySortTree.addNode(new Node(arr[i]));
		}
//		System.out.println("中序遍历二叉树");
		binarySortTree.infixOrder();
		
		//测试删除叶子节点
//		binarySortTree.delNode(2);
//		System.out.println("删除2节点后");
//		binarySortTree.infixOrder();
		binarySortTree.delNode(10);
		binarySortTree.infixOrder();

	}

}
//创建二叉排序树
class BinarySortTreeDemo{
    
    
	private Node root;
	//添加节点的方法
	public void addNode(Node node){
    
    
		if(root == null){
    
    
			root = node;
		}else{
    
    
			root.addNode(node);
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		if(root != null){
    
    
			root.infixOrder();
		}else{
    
    
			System.out.println("空树");
		}
	}
	//查找要删除的节点
	public Node search(int value){
    
    
		if(root == null){
    
    
			return null;
		}else{
    
    
			return root.search(value);
		}
	}
	//查找待删除节点的父节点
	public Node searchParent(int value){
    
    
		if(root == null){
    
    
			return null;
		}else{
    
    
			return root.searchParent(value);
		}
	}
	//编写方法
	/**
	 * 返回最小节点值,并且删除以node为根节点的二叉排序树的最小节点
	 * @param node	当做一颗二叉排序树的根节点
	 * @return		返回的以node为根节点的二叉排序树的最小节点的值
	 */
	public int delRightTreeMin(Node node){
    
    
		Node target = node;
		//循环查找左子节点,就会找到最小值
		while(target.left != null){
    
    
			target = target.left;
		}
		//这是target就指向了最小节点
		//删除最小节点
		delNode(target.value);
		return target.value;
	}
	
	//删除叶子结点的方法
	public void delNode(int value){
    
    
		if(root == null){
    
    
			return;
		}else{
    
    
			//1.需要先去找到待删除节点
			Node targetNode = search(value);
			//如果没有找到
			if(targetNode == null){
    
    
				return;
			}
			//如果当前这课二叉排序树只有一个节点
			if(root.left == null&& root.right == null){
    
    
				root = null;
				return;
			}
			//去查找targetNode的父节点
			Node parent = searchParent(value);
			//如果待删除的节点是叶子结点
			if(targetNode.left == null && targetNode.right == null){
    
    
				//如果targetNode是parent的左子节点
				if(parent.left != null && parent.left.value == targetNode.value){
    
    
					parent.left = null;
				}else if(parent.right != null && parent.right.value == targetNode.value){
    
    
					parent.right = null;
				}
			}else if(targetNode.left!=null && targetNode.right != null){
    
    
				int minValue = delRightTreeMin(targetNode.right);
				targetNode.value = minValue;
			}else{
    
    
				//删除只有一个子树的节点
				//如果删除的节点有左子节点
				if(targetNode.left != null){
    
    
					if(parent.left.value == targetNode.value){
    
    
						parent.left = targetNode.left;
					}else{
    
    
						parent.right = targetNode.left;
					}
				}else{
    
    
					//要删除的节点有右子节点
					if(parent.left.value == targetNode.value){
    
    
						parent.left = targetNode.right;
					}else{
    
    
						parent.right = targetNode.right;
					}
				}
			}
		}
	}
}
class Node{
    
    
	int value;
	Node left;
	Node right;
	public Node(int value) {
    
    
		super();
		this.value = value;
	}
	
	@Override
	public String toString() {
    
    
		return "Node [value=" + value + "]";
	}

	/**
	 * 查找待删除的节点
	 * @param value	待删除节点的值
	 * @return
	 */
	public Node search(int value){
    
    
		if(value == this.value){
    
    
			return this;
		}else if(value < this.value){
    
    //应该向左子树递归查找
			if(this.left != null){
    
    
				return this.left.search(value);
			}else{
    
    
				return null;
			}
		}else{
    
    
			if(this.right == null){
    
    
				return null;
			}else{
    
    
				return this.right.search(value);
			}
		}
	}
	/**
	 * 查找待删除节点的父节点
	 * @param value		待删除节点的值
	 * @return     返回待删除节点的父节点
	 */
	public Node searchParent(int value){
    
    
		if((this.left !=null && this.left.value == value) || (this.right != null && this.right.value == value)){
    
    
			//当前节点就是待删除节点的父节点
			return this;
		}else{
    
    
			//如果查找的值,小于当前节点的值,且当前节点的左子节点不为空
			if(value < this.value && this.left != null){
    
    
				return this.left.searchParent(value);
			}else if(value >= this.value && this.right != null){
    
    
				return this.right.searchParent(value);
			}else{
    
    
				return null;//没有找到父节点
			}
		}
	}
	
	
	//添加节点的方法
	//递归的形式添加节点,需要满足二叉排序树
	public void addNode(Node node){
    
    
		if(node == null){
    
    
			return;
		}
		//判断传入的节点值,跟当前子树根节点值的关系
		if(node.value < this.value){
    
    
			//如果当前节点的左子节点为空
			if(this.left == null){
    
    
				this.left = node;
			}else
			{
    
    
				this.left.addNode(node);//递归添加
			}
		}else{
    
    
			if(this.right == null){
    
    
				this.right = node;
			}else{
    
    
				this.right.addNode(node);
			}
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		if(this.left != null){
    
    
			this.left.infixOrder();
		}
		System.out.println(this);
		if(this.right != null){
    
    
			this.right.infixOrder();
		}
	}
}

Precauciones

Al eliminar varios nodos, debe prestar atención al pedido. Algunos pedidos se pueden eliminar normalmente, pero algunos pedidos informarán un error de puntero nulo. La razón es que hay un problema con el orden de eliminación, lo que lleva a un problema con el juicio en nuestro método de eliminación, que es el nodo raíz. En este lugar, no tiene un nodo principal, pero lo juzgamos, por lo que hay un error aquí

Supongo que te gusta

Origin blog.csdn.net/qq_22155255/article/details/113825468
Recomendado
Clasificación