排序二叉树及其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;
	}
}


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

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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python定时器

    python定时器

    2021年11月19日
    52
  • python 菜鸟教程 正则_华为mate30好用不

    python 菜鸟教程 正则_华为mate30好用不正则表达式简介正则表达式,是一个特殊的字符序列,又称规则表达式(英语:RegularExpression,在代码中常简写为regex、regexp或RE),本质而言是一种小型的,高度专业化的编程语言。Python自1.5版本起增加了re模块,re模块使Python语言拥有全部的正则表达式功能。正则语法表关于正则语法表,别想其他的都背过就行了。不管你是python还是其他…

    2022年9月25日
    4
  • Squid 代理服务器之 ACL 访问控制

    Squid 代理服务器之 ACL 访问控制文章目录1.ACL访问控制方式2.ACL规则优先级3.ACL的定义步骤4.定义访问控制列表4.1方法一4.2方法二1.ACL访问控制方式根据源地址、目标URL、文件类型等定义列表格式为:acl列表名称列表类型列表内容…针对已定义的acl列表进行限制格式为:http_accessallow或deny列表名称…2.ACL规则优先级一个用户访问代理服务器时,Squid会以从上至下的顺序匹配Squid中定义的所有规则列表,

    2022年6月21日
    25
  • Html动态点击按钮实现“+”和“-”功能

    Html动态点击按钮实现“+”和“-”功能  Html动态点击按钮实现“+”和“-”功能&lt;!DOCTYPE html&gt;&lt;html lang="en"&gt; &lt;head&gt; &lt;meta http-equiv="Content-Type" content="text/html;"&gt; &lt;title&gt;html动态实现加减&lt;

    2022年6月13日
    65
  • 手把手教你制作一款iOS越狱App,伪装微信位置

    手把手教你制作一款iOS越狱App,伪装微信位置说明缘由声明概念越狱的原理iOS目录层级结构iOS程序类型准备工作硬件设备辅助软件Mac需要的工具iOS需要使用的辅助开发工具逆向过程静态分析给App砸壳使用IDA静态分析动态调试iOS工程目录制作TweakTweak是什么了解Theos安装iOSOpenDev制作AppApp和Tweak通信交换数据App如何加载TweakApp如何

    2022年5月29日
    98
  • linux添加用户及用户权限管理命令_docker用户权限

    linux添加用户及用户权限管理命令_docker用户权限Linux添加用户及用户权限管理1.新建用户(组)①用户新建用户需要通过指令useradd来实现。useradd的一些基本用法如下:useraddusername 新建一个用户useradd-uuidusername 指定用户的uiduseradd-ggidusername 指定用户的gid(一定要存在)useradd-Ggiduseradd指定用户的附加组(…

    2025年8月2日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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