二叉树--前序遍历、中序遍历、后序遍历、层次遍历、查找、删除、更新--JAVA实现

本文详细介绍了使用Java实现二叉树的各种操作,包括前序、中序、后序及层次遍历,查找、删除和更新节点的方法。通过具体代码示例,展示了如何构建二叉树并进行上述操作。

二叉树基础,请参考:https://blog.csdn.net/cinling123/article/details/103911110

本文重点,用JAVA实现--二叉树--前序遍历、中序遍历、后序遍历、层次遍历、查找、删除、更新。--经过测试

直接上代码:

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

class TreeNode{
	Integer value;
	TreeNode leftNode;
	TreeNode rightNode;
	
	public TreeNode(){}
	
	/**
	 * 初始化结点
	 */
	public TreeNode(int value){
		this.value=value;
		this.leftNode=null;
		this.rightNode=null;
	}
	
	/**
	 * 创建二叉树
	 */
	static TreeNode buildTree(int[] data){
		TreeNode node = new TreeNode();
		for (int i=0;i<data.length;i++) {
			insert(node, data[i]);
//			insert2(node, data[i]);
		}
		return node;
	}
	
	/**
	 * 以查找二叉树的规则插入,小的在左,大的在右--递归
	 */
	public static void insert(TreeNode node, int value){
		if (node.getValue() == null) {
			node.setValue(value);
		} else if (value < node.getValue()) {//建立左子树
			if (node.getLeftNode() == null) {//左子树节点为空
				node.setLeftNode(new TreeNode());
				insert(node.getLeftNode(), value);
			} else {
				insert(node.getLeftNode(), value);
			}
		} else if (value > node.getValue()) {//建立右子树
			if (node.getRightNode() == null) {//右子树节点为空
				node.setRightNode(new TreeNode());
				insert(node.getRightNode(), value);
			} else {
				insert(node.getRightNode(), value);
			}
		}
	}
	
	/**
	 * 以查找二叉树的规则插入,小的在左,大的在右
	 */
	private static void insert2(TreeNode node, int value){
		if (node.value == null) {//根节点
			node.value = value;
			return;
		}
		TreeNode currentNode = node;
		while(true){
			if (value < currentNode.value) {//建立左子树
				if (currentNode.leftNode == null) {//左子树节点为空
					currentNode.leftNode = new TreeNode(value);//建立左孩子节点
					return;
				} else {
					currentNode = currentNode.leftNode;
				}
			} else {//建立右子树
				if (currentNode.rightNode == null) {//右子树节点为空
					currentNode.rightNode = new TreeNode(value);//建立右孩子节点
					return;
				} else {
					currentNode = currentNode.rightNode;
				}
			}
		}
	}
	
	/**
	 * 前序遍历
	 * 前序遍历通俗的说就是从二叉树的根结点出发,当第一次到达结点时就输出结点数据,按照先向左再向右的方向访问
	 */
	static void preOrder(TreeNode node){
		if (node != null) {
			System.out.print(node.getValue() + " ");
			preOrder(node.getLeftNode());
			preOrder(node.getRightNode());
		}
	}
	
	/**
	 * 中序遍历
	 * 中序遍历就是从二叉树的根结点出发,当第二次到达结点时就输出结点数据,按照先向左再向右的方向访问
	 */
	static void inOrder(TreeNode node){
		if (node != null) {
			inOrder(node.getLeftNode());
			System.out.print(node.getValue() + " ");
			inOrder(node.getRightNode());
		}
	}
	
	/**
	 * 后序遍历
	 * 后序遍历就是从二叉树的根结点出发,当第三次到达结点时就输出结点数据,按照先向左再向右的方向访问
	 */
	static void afterOrder(TreeNode node){
		if (node != null) {
			afterOrder(node.getLeftNode());
			afterOrder(node.getRightNode());
			System.out.print(node.getValue() + " ");
		}
	}
	
	/**
	 * 层序遍历(队列实现):其实就是从上到下,从左到右依次将每个数放入到队列中,然后按顺序依次打印就是想要的结果
	 *  1、首先将二叉树的根节点add到队列中,判断队列不为空,就输出队头的元素, 
	 *  2、判断节点如果有孩子,就将孩子add到队列中, 
	 *  3、遍历过的节点出队列, 
	 *  4、循环以上操作,直到Tree == NULL。
	 */
	static void floorOrder_queue(TreeNode node){
		Queue<TreeNode> q = new ConcurrentLinkedQueue<TreeNode>();
		if (null != node) {
			q.add(node);//根节点先入队列
		}
		while(q.isEmpty() == false){
			TreeNode currentNode = q.poll();//头元素出队列
			System.out.print(currentNode.getValue() + " ");
			if (currentNode.getLeftNode() != null) {//有左子树,左子树入队列
				q.add(currentNode.getLeftNode());
			}
			if (currentNode.getRightNode() != null) {//有右子树,右子树入队列
				q.add(currentNode.getRightNode());
			}
		}
	}
	
	/**
	 * 层序遍历(数据实现):其实就是从上到下,从左到右依次将每个数放入到队列中,然后按顺序依次打印就是想要的结果
	 * 1、创建一个指针数组,保存二叉树结构体指针, 
	 * 2、保存二叉树根节点,再申请变量 in、out ,控制数组,在遍历过程中,始终能找到节点和该节点的前一个节点, 
	 * 3、循环以上过程。
	 */
	static void floorOrder_array(TreeNode node, int size){
		TreeNode[] array = new TreeNode[size];
		int in = 0;
		int out = 0;
		array[in++] = node;
		while (in > out) {
			TreeNode currentNode = array[out];
			if (currentNode != null) {
				System.out.print(currentNode.getValue() + " ");
				if (currentNode.getLeftNode() != null) {//有左子树,左子树入数组
					array[in++] = currentNode.getLeftNode();
				}
				if (currentNode.getRightNode() != null) {//有右子树,右子树加入数组
					array[in++] = currentNode.getRightNode();
				}
				out++;
			}
		}
	}
	
	/**
	 * 查找
	 */
	static TreeNode findNode(TreeNode node, int value){
		if (value == node.getValue()) {//值相等,找到,返回
			return node;
		} else if (value < node.getValue()) {//值比当前节点小,左子树查找
			if (null != node.getLeftNode()) {
				return findNode(node.getLeftNode(), value);
			} else {
				return null;
			}
		} else if (value > node.getValue()) {//值比当前节点大,右子树查找
			if (null != node.getRightNode()) {
				return findNode(node.getRightNode(), value);
			} else {
				return null;
			}
		}
		return null;
	}
	
	/**
	 * 删除节点
	 * 要求:删除的要求相对复杂,因为,删除之后,还是必须要保持二叉查找树的特性。
       实现思路:先找到要删除的节点,这时会有三种情况:
	    1、删除节点为(左或者右)叶子--此时直接将节点的父亲节点的(左或者右)节点置为空;
		2、删除节点只包含一个(左或者右)子树--此时,判断删除节点是父节点的左子树,还是右子树,用删除节点的唯一那一个“儿子”去替换自己;
		3、删除节点既有左子树又有右子树--此时,可以找到右子树中最小的节点,替换删除节点,再递归地删除了它(做法不唯一,同样也可以用左子树中最大的节点去替换删除节点)
	 */
	static void delete(TreeNode tree, int value) {
		// 查询到的节点的父节点
		TreeNode parent = null;
		// 查询到的节点
		TreeNode searchTree = tree;
		// 当节点不为空的时候开始循环
		while (searchTree != null) {
			// 如果节点的值等于查询值,跳出循环,之后的逻辑就是一个树查找的逻辑
			if (searchTree.getValue() == value) {
				break;
			} else if (searchTree.getValue() > value) {
				parent = searchTree;
				searchTree = searchTree.getLeftNode();
			} else if (searchTree.getValue() < value) {
				parent = searchTree;
				searchTree = searchTree.getRightNode();
			}
		}

		// 查询到的节点是父节点的左节点与否
		boolean parentLeftFlag = false;
		// 查询到的节点的父节点是否存在
		boolean hasParent = true;
		// 查询到的节点的左子树存在与否
		boolean leftFlag = false;
		// 查询到的节点的右子树存在与否
		boolean rightFlag = false;

		if (parent == null) {
			hasParent = false;
		} else if (parent.getRightNode() == searchTree) {
			parentLeftFlag = false;
		} else {
			parentLeftFlag = true;
		}

		if (searchTree == null) {
			return;
		}
		if (searchTree.getLeftNode() != null) {
			leftFlag = true;
		}
		if (searchTree.getRightNode() != null) {
			rightFlag = true;
		}

		if (!leftFlag && !rightFlag) {
			if (hasParent) {
				if (parentLeftFlag) {
					parent.setLeftNode(null);
				} else {
					parent.setRightNode(null);
				}
			} else {
				searchTree.setValue(null);
			}
		} else if (!leftFlag || !rightFlag) {
			if (hasParent) {
				if (parentLeftFlag) {
					if (leftFlag) {
						parent.setLeftNode(searchTree.getLeftNode());
					} else {
						parent.setLeftNode(searchTree.getRightNode());
					}
				} else {
					if (leftFlag) {
						parent.setRightNode(searchTree.getLeftNode());
					} else {
						parent.setRightNode(searchTree.getRightNode());
					}
				}
			} else {
				if (leftFlag) {
					searchTree.setValue(searchTree.getLeftNode().getValue());
					searchTree.setRightNode(searchTree.getLeftNode().getRightNode());
					searchTree.setLeftNode(searchTree.getLeftNode().getLeftNode());
				} else {
					searchTree.setValue(searchTree.getRightNode().getValue());
					searchTree.setLeftNode(searchTree.getRightNode().getLeftNode());
					searchTree.setRightNode(searchTree.getRightNode().getRightNode());
				}
			}
		} else if (leftFlag && rightFlag) {
			TreeNode minTree = searchTree.getRightNode();
			while (minTree.getLeftNode() != null) {
				minTree = minTree.getLeftNode();
			}
			Integer minTreeValue = minTree.getValue();
			delete(searchTree, minTreeValue);
			searchTree.setValue(minTreeValue);
		}
	}
	
	/**
	 * 先删除旧节点,再插入新的值
	 */
	static void update(TreeNode tree, int oldValue, int newValue){
		delete(tree, oldValue);
		insert( tree, newValue);
	}

	public Integer getValue() {
		return value;
	}

	public void setValue(Integer value) {
		this.value = value;
	}

	public TreeNode getLeftNode() {
		return leftNode;
	}

	public void setLeftNode(TreeNode leftNode) {
		this.leftNode = leftNode;
	}

	public TreeNode getRightNode() {
		return rightNode;
	}

	public void setRightNode(TreeNode rightNode) {
		this.rightNode = rightNode;
	}
}

/**
 * 二叉树
 */
public class TestTreeNode {
	public static void main(String[] args) {
		int[] data = {6,3,9,7,4,8,2,1,5};
		System.out.println("原始数组:");
		for (int i=0;i<data.length;i++) 
		System.out.print(data[i] + " ");
		TreeNode rootNode = TreeNode.buildTree(data);
		System.out.print("\n前序遍历:");
		TreeNode.preOrder(rootNode);
		System.out.print("\n中序遍历:");
		TreeNode.inOrder(rootNode);
		System.out.print("\n后序遍历:");
		TreeNode.afterOrder(rootNode);
		System.out.print("\n层序遍历--队列:");
		TreeNode.floorOrder_queue(rootNode);
		System.out.print("\n层序遍历--数组:");
		TreeNode.floorOrder_array(rootNode, data.length);
		System.out.print("\n二叉树查找--值为8的节点:");
		TreeNode node = TreeNode.findNode(rootNode, 8);
		System.out.print(node == null?"未找到":node.getValue());
		TreeNode.delete(rootNode, 3);//删除值为3的节点
		System.out.print("\n删除节点值为3后--中序遍历:");
		TreeNode.update(rootNode, 7, 10);//更新值为7的节点
		System.out.print("\n更新值为7的节点后---层序遍历:");
		TreeNode.floorOrder_queue(rootNode);
	}
}

创建树后的结构:

运行结果:

 

代码实现参考资料:

(二叉树的层序遍历(两种方法实现)):https://blog.csdn.net/m0_37925202/article/details/80796010
二叉树的建立:https://blog.csdn.net/zd454909951/article/details/78794263

Java实现二叉树(一):二叉查找树的实现:https://blog.csdn.net/that_is_cool/article/details/80948929

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值