二叉搜索树的实现(JAVA)

树的基本概念

树:
在这里插入图片描述
在这里插入图片描述
ps:一棵树的深度和高度是一样的
在这里插入图片描述二叉树:
在这里插入图片描述ps:二叉树是有序树,至于顺序是右边大于左边还是右边小于左边可以由自己定义。
在这里插入图片描述真二叉树:
在这里插入图片描述满二叉树:
在这里插入图片描述完全二叉树:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述二叉搜索树:
之前实现过的动态数组和链表搜索元素的效率太低了:平均时间复杂度为O(n) 于是二叉搜素树应运而生。
在这里插入图片描述接下来就是用java实现二叉搜索树

add()方法实现 :
二叉搜索树的核心代码是add()方法的实现。有两个注意点
一:要有比较方法。
二:因为元素是泛型的,所以得给外界提供比较接口,否则无法添加元素。解决方法声明比较器接口(java内部提供的)

代码体现

// 声明比较器(java内部提供的):外界要是声明这个比较器就要实现compare方法
private Comparator<T> comparator;

// 比较方法
@SuppressWarnings("unchecked")
private int compare(T element, T element2) {
		// 判断是否有传入比较器
		if (comparator != null)
			// 具体比较要看传入的比较器
			return comparator.compare(element, element2);
		else
			// 没有传入比较器就用元素自己的默认比较方法比较 如果元素不具有比较性就会报错
			return ((Comparable<T>) element).compareTo(element2);
}

add()方法实现:

// 添加元素
	public T add(T element) {

		// 判断是否是根节点
		if (root == null) {
			root = new Node<T>(element, null);
			return null;
		} else {
			Node<T> node = root;
			Node<T> parent = null;

			int result = 0;
			// 一直遍历 直到最后一层
			while (node != null) {
				parent = node;
				//比较结果
				result = compare(element, node.element);
				if (result > 0) {

					node = node.right;
				} else if (result < 0) {
					node = node.left;
				} else {
					return node.element;
				}
			}
			// 根据结果判断是添加到右子树还是左子树
			if (result > 0) {

				parent.right = new Node<T>(element, parent);
				size++;
				return parent.element;
			} else {
				parent.left = new Node<T>(element, parent);
				size++;
				return parent.element;
			}
		}
	}

remove()方法实现 :
删除节点有三种可能:度为0,度为1,度为2。
删除度为2的节点:将它的前驱节点或后继节点的值覆盖该节点然后再去删除它的前驱或后继节点。(前驱或后继节点度不可能为2)
所以其实真正被删除的节点只有可能是度为0或1的节点。
找到前驱节点或后继节点


	// 获取某个节点的前驱节点
	private Node<T> getpredecessor(Node<T> node) {
		if (node == null)
			return null;
		if (node.left != null) {
			Node<T> tempNode = node.left;
			while (tempNode.right != null) {
				tempNode = tempNode.right;
			}

			return tempNode;
		} else {
			if (node.parent == null) {
				return null;
			} else {
				{
					Node<T> tempNode = node.parent;
					while (tempNode.parent != null) {
						if (tempNode == tempNode.parent.left) {
							return tempNode.parent;
						}
						tempNode = tempNode.parent;

					}

					return tempNode.parent;
				}
			}
		}

	}



	// 获取某个节点的后继节点
	private Node<T> getSuccessor(Node<T> node) {
		if (node == null)
			return null;
		if (node.right != null) {
			Node<T> tempNode = node.right;
			while (tempNode.left != null) {
				tempNode = tempNode.left;
			}

			return tempNode;
		} else {
			if (node.parent == null) {
				return null;
			} else {
				{
					Node<T> tempNode = node.parent;
					while (tempNode.parent != null) {
						if (tempNode == tempNode.parent.right) {
							return tempNode.parent;
						}
						tempNode = tempNode.parent;

					}

					return tempNode.parent;
				}
			}
		}

	}

remove()方法

// 移除元素
	public void remove(T element) {
		Node<T> node = getNode(element);
		remove(node);

	}

	// 根据元素找到节点
	private Node<T> getNode(T element) {
		Node<T> node = root;
		while (node != null) {
			int result = compare(node.element, element);
			if (result == 0) {
				return node;
			} else if (result < 0) {
				node = node.right;

			} else {
				node = node.left;
			}
		}
		return null;
	}

	// 移除节点
	private void remove(Node<T> node) {
		// 删除节点度为2的节点
		if (node.hasTwoChildren()) {
			// 直接将它的前驱节点的值赋给该节点 然后删除前驱节点
			node.element = getpredecessor(node).element;
			// 前驱节点 后继节点的度只能为1 或者0
			// 所以直接赋值给node 通过后续删除度为0或1节点来间接删除
			node = getpredecessor(node);
		}
		// 删除度为0或1的节点
		if (node.isLeaf()) {
			if (node.parent == null) {
				root = null;
			} else {
				if (node == node.parent.left) {
					node.parent.left = null;
					node.parent = null;

				} else {
					node.parent.right = null;
					node.parent = null;

				}
			}
		} else {

			if (node.parent == null) {
				if (node.left != null) {
					root = node.left;
					root.parent = null;
				} else {
					root = node.right;
					root.parent = null;
				}

			} else {

				if (node == node.parent.left) {
					if (node.left != null) {
						node.left.parent = node.parent;
						node.parent.left = node.left;
					} else {
						node.right.parent = node.parent;
						node.parent.left = node.right;
					}
				} else {
					if (node.left != null) {
						node.left.parent = node.parent;
						node.parent.right = node.left;
					} else {
						node.right.parent = node.parent;
						node.parent.right = node.right;
					}
				}

			}

		}

	}

二叉搜索树的几种遍历:
前序遍历:先遍历父节点再遍历左子节点最后遍历右子节点
中序遍历:先遍历左子节点再遍历父节点最后遍历右子节点
后序遍历:先遍历右子节点再遍历父节点最后遍历左子节点
层序遍历:一层一层的遍历,从左自右
代码

    // 前序遍历
	public void preorderTraversal(Visitor<T> visitor) {
		preorderTraversal(root, visitor);
	}

	// 前序遍历 递归实现
	private void preorderTraversal(Node<T> node, Visitor<T> visitor) {
		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;
		// 自定义怎么实现元素 并且可以随时停止遍历
		visitor.flag = visitor.vistor(node.element);
		preorderTraversal(node.left, visitor);
		preorderTraversal(node.right, visitor);

	}

	// 中序遍历
	public void inorderTraversal(Visitor<T> visitor) {
		inorderTraversal(root, visitor);
	}

	// 中序遍历 递归实现
	private void inorderTraversal(Node<T> node, Visitor<T> visitor) {
		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;

		inorderTraversal(node.left, visitor);
		// 这个判断是确保不会打印后面的元素
		if (visitor.flag)
			return;
		visitor.flag = visitor.vistor(node.element);
		inorderTraversal(node.right, visitor);
	}

	// 后序遍历
	public void postorderTraversal(Visitor<T> visitor) {

		postorderTraversal(root, visitor);
	}

	// 后序遍历 递归实现
	private void postorderTraversal(Node<T> node, Visitor<T> visitor) {

		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;

		postorderTraversal(node.left, visitor);
		postorderTraversal(node.right, visitor);
		// 这个判断是确保不会打印后面的元素
		if (visitor.flag)
			return;
		visitor.flag = visitor.vistor(node.element);

	}

	// 层序遍历 队列实现 注意一下官方的Linkedlist允许添加null元素
	public void levelorderTraversal(Visitor<T> visitor) {
		if (root == null | visitor == null)
			return;
		Queue<Node<T>> queue = new LinkedList<>();
		Node<T> node = root;
		// 首节点入队
		queue.offer(node);
		// 队首节点出队的同时 该节点的左右子节点依次入队
		while (!queue.isEmpty()) {
			node = queue.peek();
			if (visitor.vistor(queue.poll().element))
				return;

			// 如果有左子节点 让它入队
			if (node.left != null)
				queue.offer(node.left);
			// 如果有右子节点 让它入队
			if (node.right != null)
				queue.offer(node.right);

		}

	}

BinarySearchTree完整代码:

package com.ldg.binarysearchtree;

import java.util.Comparator;

import java.util.LinkedList;
import java.util.Queue;

import com.ldg.printer.BinaryTreeInfo;

//二叉搜索树   默认所添加的元素必须具有可比较性 (一:要么声明对象时传入相应比较器  二:要么实现Comparable接口)
public class BinarySearchTree<T> implements BinaryTreeInfo {
	// 元素数量
	private int size;
	// 根节点
	private Node<T> root;
	// 树的高度
	private int height = 0;

	// 比较器:元素是怎么比较的
	private Comparator<T> comparator;

	// 声明元素节点类
	@SuppressWarnings("hiding")
	private class Node<T> {
		T element;
		@SuppressWarnings("unused")
		Node<T> parent;
		Node<T> left;
		Node<T> right;

		// 判断该节点是否为叶子节点
		public boolean isLeaf() {
			return left == null && right == null;
		}

		public boolean hasTwoChildren() {
			return left != null && right != null;
		}

		public Node(T element, Node<T> parent) {
			this.element = element;
			this.parent = parent;
		}

		@Override
		public String toString() {
			return "" + element;
		}
	}

	// 元素数量
	public int size() {
		return size;
	}

	// 清空
	public void clear() {
		if (root == null)
			return;
		root = null;
	}

	// 判断是否为空
	public boolean isEmpty() {
		return size == 0;
	}

	// 添加元素
	public T add(T element) {

		// 判断是否是根节点
		if (root == null) {
			root = new Node<T>(element, null);
			return null;
		} else {
			Node<T> node = root;
			Node<T> parent = null;

			int result = 0;
			// 一直遍历 直到最后一层
			while (node != null) {
				parent = node;
				result = compare(element, node.element);
				if (result > 0) {

					node = node.right;
				} else if (result < 0) {
					node = node.left;
				} else {
					return node.element;
				}
			}
			// 根据结果判断是添加到右子树还是左子树
			if (result > 0) {

				parent.right = new Node<T>(element, parent);
				size++;
				return parent.element;
			} else {
				parent.left = new Node<T>(element, parent);
				size++;
				return parent.element;
			}
		}
	}

	// 移除元素
	public void remove(T element) {
		Node<T> node = getNode(element);
		remove(node);

	}

	// 根据元素找到节点
	private Node<T> getNode(T element) {
		Node<T> node = root;
		while (node != null) {
			int result = compare(node.element, element);
			if (result == 0) {
				return node;
			} else if (result < 0) {
				node = node.right;

			} else {
				node = node.left;
			}
		}
		return null;
	}

	// 移除节点
	private void remove(Node<T> node) {
		// 删除节点度为2的节点
		if (node.hasTwoChildren()) {
			// 直接将它的前驱节点的值赋给该节点 然后删除前驱节点
			node.element = getpredecessor(node).element;
			// 前驱节点 后继节点的度只能为1 或者0
			// 所以直接赋值给node 通过后续删除度为0或1节点来间接删除
			node = getpredecessor(node);
		}
		// 删除度为0或1的节点
		if (node.isLeaf()) {
			if (node.parent == null) {
				root = null;
			} else {
				if (node == node.parent.left) {
					node.parent.left = null;
					node.parent = null;

				} else {
					node.parent.right = null;
					node.parent = null;

				}
			}
		} else {

			if (node.parent == null) {
				if (node.left != null) {
					root = node.left;
					root.parent = null;
				} else {
					root = node.right;
					root.parent = null;
				}

			} else {

				if (node == node.parent.left) {
					if (node.left != null) {
						node.left.parent = node.parent;
						node.parent.left = node.left;
					} else {
						node.right.parent = node.parent;
						node.parent.left = node.right;
					}
				} else {
					if (node.left != null) {
						node.left.parent = node.parent;
						node.parent.right = node.left;
					} else {
						node.right.parent = node.parent;
						node.parent.right = node.right;
					}
				}

			}

		}

	}

	// 是否包含元素
	public boolean contains(T element) {

		if (root == null)
			return false;
		Node<T> node = root;
		while (node != null) {
			int reslut = compare(node.element, element);
			if(reslut==0)
			{
			   return  true;
			}else if(reslut>0)
			{
				node=node.left;
			}else {
				node=node.right;
			}
		}
		return false;
	}

	// 前序遍历
	public void preorderTraversal(Visitor<T> visitor) {
		preorderTraversal(root, visitor);
	}

	// 前序遍历 递归实现
	private void preorderTraversal(Node<T> node, Visitor<T> visitor) {
		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;
		// 自定义怎么实现元素 并且可以随时停止遍历
		visitor.flag = visitor.vistor(node.element);
		preorderTraversal(node.left, visitor);
		preorderTraversal(node.right, visitor);

	}

	// 中序遍历
	public void inorderTraversal(Visitor<T> visitor) {
		inorderTraversal(root, visitor);
	}

	// 中序遍历 递归实现
	private void inorderTraversal(Node<T> node, Visitor<T> visitor) {
		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;

		inorderTraversal(node.left, visitor);
		// 这个判断是确保不会打印后面的元素
		if (visitor.flag)
			return;
		visitor.flag = visitor.vistor(node.element);
		inorderTraversal(node.right, visitor);
	}

	// 后序遍历
	public void postorderTraversal(Visitor<T> visitor) {

		postorderTraversal(root, visitor);
	}

	// 后序遍历 递归实现
	private void postorderTraversal(Node<T> node, Visitor<T> visitor) {

		// 这个判断是确保递归彻底停下来 必须要加上visitor.flag
		if (node == null | visitor.flag)
			return;

		postorderTraversal(node.left, visitor);
		postorderTraversal(node.right, visitor);
		// 这个判断是确保不会打印后面的元素
		if (visitor.flag)
			return;
		visitor.flag = visitor.vistor(node.element);

	}

	// 层序遍历 队列实现 注意一下官方的Linkedlist允许添加null元素
	public void levelorderTraversal(Visitor<T> visitor) {
		if (root == null | visitor == null)
			return;
		Queue<Node<T>> queue = new LinkedList<>();
		Node<T> node = root;
		// 首节点入队
		queue.offer(node);
		// 队首节点出队的同时 该节点的左右子节点依次入队
		while (!queue.isEmpty()) {
			node = queue.peek();
			if (visitor.vistor(queue.poll().element))
				return;

			// 如果有左子节点 让它入队
			if (node.left != null)
				queue.offer(node.left);
			// 如果有右子节点 让它入队
			if (node.right != null)
				queue.offer(node.right);

		}

	}

	/**
	 * 获取二叉树的高度 递归实现
	 * 高度  :某条路径的最多节点个数
	 * @return 高度
	 */
	public int height() {
		height = height(root);
		return height;
	}

	/**
	 * 
	 * @param node
	 * @return 返回当前节点的高度
	 */
	private int height(Node<T> node) {
		if (node == null)
			return 0;
		// 某个节点的高度=其左右节点最大高度+1
		return Math.max(height(node.left), height(node.right)) + 1;
	}

	/**
	 * 迭代实现 层序遍历实现 当一层元素遍历完 高度+1
	 * 
	 * @return 返回树的高度
	 */
	public int heightTwo() {
		height = 0;
		if (root == null)
			return height;
		Queue<Node<T>> queue = new LinkedList<>();

		Node<T> node = root;
		// 首节点入队
		queue.offer(node);

		// 一层的元素数量
		int levelsize = 1;
		// 队首节点出队的同时 该节点的左右子节点依次入队
		while (!queue.isEmpty()) {
			// 队首元素出队
			node = queue.poll();
			levelsize--;
			// 如果有左子节点 让它入队
			if (node.left != null)
				queue.offer(node.left);
			// 如果有右子节点 让它入队
			if (node.right != null)
				queue.offer(node.right);
			// 判断这一层是否遍历完
			if (levelsize == 0) {
				// 记录下一层的元素个数
				levelsize = queue.size();
				height++;

			}

		}
		return height;
	}

	/**
	 * 判断是否为完全二叉树 层序遍历实现
	 * 
	 * @return
	 */
	public boolean iscomplete() {
		if (root == null)
			return false;
		Queue<Node<T>> queue = new LinkedList<Node<T>>();
		queue.offer(root);
		// 节点不是叶子节点
		boolean leaf = false;
		while (!queue.isEmpty()) {
			Node<T> node = queue.poll();
			// 当节点不是叶子节点 而leaf=true
			if (leaf && !node.isLeaf())
				return false;

			if (node.left != null)
				queue.offer(node.left);
			else {
				// node.left=null&&node.right!=null情况
				if (node.right != null)
					return false;
			}
			// node.left!=null&&node.right!=null情况
			if (node.right != null)
				queue.offer(node.right);
			else {
				// 包含 node.left=null&&node.right==null 情况
				// 包含 node.left!=null&&node.right==null 情况
				// 后面的所有节点都要是叶子节点
				leaf = true;
			}
		}
		return true;
	}

	// 提供外界自定义遍历结果如何显示接口
	public static abstract class Visitor<T> {
		// 是否停止遍历的标志
		private boolean flag = false;

		/**
		 * 怎么显示element数据及可以随时停止遍历(根据元素)
		 * 
		 * @param element 数据
		 */
		public abstract boolean vistor(T element);
	}

	// 重写tostring方法 将树树状结构显示出来
	@Override
	public String toString() {

		StringBuilder sb = new StringBuilder();
		toString(root, sb, "");
		return sb.toString();

	}

	// 递归遍历每个元素 并加上前缀
	private void toString(Node<T> node, StringBuilder sb, String prefix) {
		if (node == null)
			return;
		toString(node.left, sb, prefix + "[L]");
		sb.append(prefix).append(node.element).append("\n");
		toString(node.right, sb, prefix + "[R]");
	}

	public BinarySearchTree() {

	}

	public BinarySearchTree(Comparator<T> comparator) {

		this.comparator = comparator;
	}

	// 比较方法
	@SuppressWarnings("unchecked")
	private int compare(T element, T element2) {
		// 判断是否有传入比较器
		if (comparator != null)
			// 具体比较要看传入的比较器
			return comparator.compare(element, element2);
		else
			// 没有传入比较器就用元素自己的默认比较方法比较 如果元素不具有比较性就会报错
			return ((Comparable<T>) element).compareTo(element2);

	}

	// 测试根节点的前驱节点是否正确
	public Node<T> getPre() {

		return getpredecessor(root);
	}

	// 获取某个节点的前驱节点
	private Node<T> getpredecessor(Node<T> node) {
		if (node == null)
			return null;
		if (node.left != null) {
			Node<T> tempNode = node.left;
			while (tempNode.right != null) {
				tempNode = tempNode.right;
			}

			return tempNode;
		} else {
			if (node.parent == null) {
				return null;
			} else {
				{
					Node<T> tempNode = node.parent;
					while (tempNode.parent != null) {
						if (tempNode == tempNode.parent.left) {
							return tempNode.parent;
						}
						tempNode = tempNode.parent;

					}

					return tempNode.parent;
				}
			}
		}

	}

	// 测试根节点的后继节点是否正确
	public Node<T> getSuc() {

		return getSuccessor(root);
	}

	// 获取某个节点的后继节点
	private Node<T> getSuccessor(Node<T> node) {
		if (node == null)
			return null;
		if (node.right != null) {
			Node<T> tempNode = node.right;
			while (tempNode.left != null) {
				tempNode = tempNode.left;
			}

			return tempNode;
		} else {
			if (node.parent == null) {
				return null;
			} else {
				{
					Node<T> tempNode = node.parent;
					while (tempNode.parent != null) {
						if (tempNode == tempNode.parent.right) {
							return tempNode.parent;
						}
						tempNode = tempNode.parent;

					}

					return tempNode.parent;
				}
			}
		}

	}

//************************* BinaryTreeInfo
	@Override
	public Object root() {

		return root;
	}

	@Override
	public Object left(Object node) {
		// TODO Auto-generated method stub
		return ((Node) node).left;
	}

	@Override
	public Object right(Object node) {
		// TODO Auto-generated method stub
		return ((Node) node).right;
	}

	@Override
	public Object string(Object node) {
		// TODO Auto-generated method stub
		return ((Node) node) + "(" + ((Node) node).parent + ")";
	}

}

测试结果:
在这里插入图片描述

发布了23 篇原创文章 · 获赞 17 · 访问量 1272

猜你喜欢

转载自blog.csdn.net/qq_41587409/article/details/105724127