排序二叉树及其Java实现[通俗易懂]

排序二叉树及其Java实现[通俗易懂]定义排序二叉树的定义也是递归定义的,需要满足:(1)若它的左子树不为空,则左子树上所有节点的值要均小于根节点的值;(2)若它的右子树不为空,则右子树上所有节点的值要均大于根节点的值;(3)左、右子树也分别是排序二叉树如下图,对于排序二叉树,若按中序遍历就可以得到由小到大的有序序列。创建创建排序二叉树的步骤就是不断像排序二叉树中添加新节点(p)的过程:(1)以根节

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

定义

排序二叉树的定义也是递归定义的,需要满足:

(1)若它的左子树不为空,则左子树上所有节点的值要均小于根节点的值;

(2)若它的右子树不为空,则右子树上所有节点的值要均大于根节点的值;

(3)左、右子树也分别是排序二叉树

如下图,对于排序二叉树,若按中序遍历就可以得到由小到大的有序序列。

排序二叉树及其Java实现[通俗易懂]

创建

创建排序二叉树的步骤就是不断像排序二叉树中添加新节点(p)的过程:

(1)以根节点(root)为当前节点(current)开始搜索;

(2)用新节点p的值和current的值进行比较;

(3)如果p.data>current.data,则current=current.right;若p.data<current.data,则current=current.left;

(4)重复(2)(3),直到找到合适的叶子节点位置;

(5)将p添加到上面找到的合适位置,若新节点更大,则添加为右子节点;否则,加为左子节点

删除节点

当从排序二叉树中删除节点后,要保持它依然是二叉树,必须对它进行维护:

待删除节点p,p的父节点q,p的左子树pL,p的右子树pR

(1·)p是叶子节点,直接将它从其父节点中删除;

(2)p只有左(右)子树,将pL(pR)添加成p的父节点q的左(右)子树即可;

(3)p左右子树均非空,有两种处理方法:

  • 将pL设为q的左或右子节点(取决于p是其父节点q的左、右子节点),将pR设为p的中序前驱结点s的右子节点(s是pL最右下的节点,也就是pL中最大的节点)
  • 以p的中序前驱或后继替代p所指节点,然后再从原排序二叉树中删去中序前驱或后继节点(也就是用大于p的最小节点或小于p的最大节点代替p节点)

imageimage

imageimage

Java实现代码:

package com.liuhao.DataStructures;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;


public class SortedBinTree <T extends Comparable>{

	static class Node{
		Object data;
		Node parent;
		Node left;
		Node right;
		
		public Node(Object data, Node parent, Node left, Node right) {
			this.data = data;
			this.parent = parent;
			this.left = left;
			this.right = right;
		}
		
		public String toString(){
			return "[data=" + data + "]";
		}
		
		public boolean equals(Object obj){
			if(this == obj){
				return true;
			}
			
			if(obj.getClass() == Node.class){
				Node target = (Node) obj;
				return data.equals(target.data) && left == target.left 
						&& right == target.right && parent == target.parent;
			}
			
			return false;
		}
		
	}
	
	private Node root;
	
	public SortedBinTree(){
		root = null;
	}	
	
	public SortedBinTree(T o){
		root = new Node(o, null, null, null);
	}
	
	/**
	 * 添加节点
	 * @param ele 新节点的元素
	 */
	public void add(T ele){
		if(root == null){
			root = new Node(ele, null, null, null);
		}
		else{
			Node current = root;
			Node parent = null;
			int cmp;
			
			//搜索合适的叶子节点,以该叶子节点为父节点添加新节点
			do{
				parent = current;
				cmp = ele.compareTo(current.data);
				
				//如果新节点的值大于当前节点的值
				if(cmp > 0){
					//以当前节点的右子节点作为当前节点
					current = current.right;
				}else{
					current = current.left;
				}
			}while(current != null);
			
			//创建新节点
			Node newNode = new Node(ele, parent, null, null);
			
			//如果新节点的值大于父节点的值
			if(cmp > 0){
				parent.right = newNode;
			}else{
				parent.left = newNode;
			}
		}
	}
	
	/**
	 * 删除节点
	 * @param ele
	 */
	public void remove(T ele){
		Node target = getNode(ele);
		
		if(target == null){
			return;
		}
		
		//左右子树都为空
		if(target.left == null && target.right == null){
			if(target == root){
				root = null;
			}
			else{
				//被删除节点是父节点的左子节点
				if(target == target.parent.left){
					//将target的父节点的left设为null
					target.parent.left = null;
				}else{
					target.parent.right = null;
				}
				
				target.parent = null;
			}
		}
		
		//左空右不空
		else if(target.left == null && target.right != null){
			if(target == root){
				root = target.right;
			}
			else{
				//被删除节点是父节点的左子节点
				if(target == target.parent.left){
					target.parent.left = target.right;
				}
				else{
					target.parent.right = target.right;
				}
				
				//让target的右子树的parent指向target的parent
				target.right.parent = target.parent;
			}
		}
		
		else if(target.left != null && target.right == null){
			if(target == root){
				root = target.left;
			}
			else{
				//被删除节点是父节点的左子节点
				if(target == target.parent.left){
					target.parent.left = target.left;
				}
				else{
					target.parent.right = target.left;
				}
				
				//让target的右子树的parent指向target的parent
				target.left.parent = target.parent;
			}
		}
		
		//左右都不为空
		else{
			//leftMaxNode:target的左子树中值最大的节点
			Node leftMaxNode = target.left;
			
			//搜索target的左子树中值最大的节点
			while(leftMaxNode.right != null){
				leftMaxNode = leftMaxNode.right;
			}
			
			//从原来的子树中删除leftMaxNode节点
			leftMaxNode.parent.right = null;
			
			leftMaxNode.parent = target.parent;
			
			if(target == target.parent.left){
				target.parent.left = leftMaxNode;
			}
			else{
				target.parent.right = leftMaxNode;
			}
			
			leftMaxNode.left = target.left;
			leftMaxNode.right = target.right;
			target.parent = target.left = target.right = null;
		}
	}
	
	/**
	 * 根据指定值搜索节点
	 * @param ele 指定值
	 * @return 节点
	 */
	public Node getNode(T ele){
		//从根节点开始搜索
		Node p = root;
		while(p != null){
			int cmp = ele.compareTo(p.data);
			
			if(cmp < 0){
				p = p.left;
			}
			else if(cmp > 0){
				p = p.right;
			}
			else{
				return p;
			}
		}
		
		return null;
	}
	
	/**
	 * 广度优先遍历
	 * @return
	 */
	public List<Node> breadthFirst(){
		Queue<Node> queue = new ArrayDeque<Node>();
		List<Node> list = new ArrayList<Node>();
		
		if(root != null){
			queue.offer(root);
		}
		
		while(!queue.isEmpty()){
			//将该队列的“队尾”元素添加到List中
			list.add(queue.peek());
			//弹出队尾节点
			Node p = queue.poll();
			
			//如果左子节点不为null,将它加入“队列”
			if(p.left != null){
				queue.offer(p.left);
			}
			
			if(p.right != null){
				queue.offer(p.right);
			}
		}
		
		return list;
	}
	
	/**
	 * 中序遍历
	 * @return
	 */
	public List<Node> inIterator(){
		return inIterator(root);
	}
	
	private List<Node> inIterator(Node node){
		List<Node> list = new ArrayList<Node>();
		
		//递归处理左子树
		if(node.left != null){
			list.addAll(inIterator(node.left));
		}
		
		//处理根节点
		list.add(node);
		
		//递归处理右子树
		if(node.right != null){
			list.addAll(inIterator(node.right));
		}
		
		return list;
	}
}


您的关注是我坚持写作的动力,如果觉得有用,欢迎关注我的微信,海量学习资源免费送!

你的关注是对我最大的鼓励!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160006.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Springboot面试问题总结

    Springboot面试问题总结Q:什么是springboot?A:多年来,随着新功能的增加,spring变得越来越复杂。只需访问页面https://spring.io/projects,我们将看到所有在应用程序中使用的不同功能的spring项目。如果必须启动一个新的spring项目,我们必须添加构建路径或maven依赖项,配置applicationserver,添加spring配置。因此,启动一个新的spring项…

  • pycharm如何缩进多行代码_pycharm统计代码行数

    pycharm如何缩进多行代码_pycharm统计代码行数方法一:在代码界面,点击鼠标右键,然后按住鼠标左键下拉选择就行了方法二:直接按下快捷键,alt+shift+insert,然后长按鼠标左键下拉即可进入多行编辑模式。…

  • 编写测试用例的思路_用例测试方法

    编写测试用例的思路_用例测试方法前言用过pytest的小伙伴都知道,pytest的运行方式是非常丰富的,可以说是你想怎么运行怎么运行,想运行哪些运行哪些,那httprunner是否同样可以呢?运行用例的各种方式运行指定路径的用

  • 自动化测试框架: Delphi中”包”的妙用

    自动化测试框架: Delphi中”包”的妙用

  • 40个容易上瘾的HTML5网页游戏,总有一款适合你[通俗易懂]

    40个容易上瘾的HTML5网页游戏,总有一款适合你[通俗易懂]我记得姐姐家的孩子在刚刚才学会走路,说话还不能完整的时候就已经能自己用小手点出小游戏的网站来一个人自娱自乐。我一直在想这一代跟着计算机一起茁壮成长的孩子会不会也和美国那一代人一样,出现9岁的黑客和计算机天才。但是并不是信息的成长就能让教育同步。很多时候我们会发现教育在发展的大环境中并没有什么创新的思考。不管怎么说,我们还是需要小盆友们能有足够的想象力。不要被束缚!今天分享的是40个HTML5的网页

  • Python分析和实现基于用户和Item的协同过滤算法

    Python分析和实现基于用户和Item的协同过滤算法打开微信扫一扫,关注《搜索与推荐Wiki》1:协同过滤算法简介2:协同过滤算法的核心3:协同过滤算法的应用方式4:基于用户的协同过滤算法实现5:基于物品的协同过滤算法实现一:协同过滤算法简介关于协同过滤的…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号