java二叉搜索树_java 二叉搜索树

java二叉查找树实现:

二叉查找树,上图:比根节点小者在其左边,比根节点大者在其右边。

8190d3bbdae0e7e59b284cc7eb60981b.png

抽象数据结构,上代码:

/*** 二叉查找树数据结构(非线程安全):

* 范型类型须实现Comparable接口,用于比较操作*/

public class BinarySearchTree>{private Node root; //tree root

private int count; //tree element counts

/*** 内部节点类*/

private static class Node{

E value;//元素对象

Node parent; //父节点

Node left; //左孩子节点

Node right; //右孩子节点

public Node(E value, Node parent, Node left, Noderight) {this.value =value;this.parent =parent;this.left =left;this.right =right;

}

}

}

一些基本操作实现:

插入(insert): 依次比较根元素,小者放左边,大者放右边:

/*** 插入元素

*@paramt 待插入元素

*@return插入成功返回true, 反之返回false*/

public booleaninsert(T t){if (root == null){ //若为空树

root = new Node(t, null, null, null);return true;

}

Node newNode = new Node(t, null, null, null);

Node pointer =root;while(true){if (newNode.value.compareTo(pointer.value) > 0){if (pointer.right == null){ //插入右边

newNode.parent =pointer;

pointer.right=newNode;

count++;return true;

}else{

pointer=pointer.right;

}

}else if (newNode.value.compareTo(pointer.value) < 0){if (pointer.left == null){ //插入左边

newNode.parent =pointer;

pointer.left=newNode;

count++;return true;

}else{

pointer=pointer.left;

}

}else { //相等了

return false;

}

}

}

查找(get):

/*** 查找元素

*@paramt 待查找元素

*@return对应元素或null*/

publicT get(T t) {

Node n =getN(t);return n == null? null: n.value;

}/*** 查找节点

*@paramt 待查找元素

*@return元素对应节点或null*/

private NodegetN(T t) {

Node cur =root;while (cur != null){if (cur.value.compareTo(t) < 0){ //右边子树找

cur =cur.right;

}else if(cur.value.compareTo(t) > 0){ //左边子树找

cur =cur.left;

}else{ //找到该节点

break;

}

}returncur;

}

查找最大,最小元素:

/*** 获取某节点为根的树的最小元素*/

public T min(Noden){

Node min =minN(n);return min == null ? null: min.value;

}/*** 获取某节点为根的树的最小节点

*@paramn 树根节点

*@return该子树最小节点*/

private Node minN(Noden){

Node min =n;while (min != null && min.left != null){

min=min.left;

}returnmin;

}/*** 获取某节点为根的树的最大元素

*@return最大元素, 没有返回null*/

public T max(Noden){

Node max =maxN(n);return max == null ? null: max.value;

}/*** 获取某节点为根的树的最大节点*/

private Node maxN(Noden){

Node max =n;while (max != null && max.right != null){

max=max.right;

}returnmax;

}

遍历树(中序遍历):

/*** 中序遍历*/

public voidleftRootRight(){

printLRR(root);

}/*** 中序遍历打印元素*/

private void printLRR(Nodenode) {if (node != null){

printLRR(node.left);

System.out.println(node.value);

printLRR(node.right);

}

}

获取前驱(prev)元素:

主要有两种情况:

1.该节点左子树不为空:其前驱节点为其左子树的最大元素:

ec31347a2f381750f2952fdba7eb32a0.png

2.该节点左子树为空: 其前驱节点为其祖先节点(递归),且该祖先节点的右孩子也为其祖先节点(就是一直往其parent找,出现左拐后的那个祖先节点):

f80bdac34722dc3c2a601ced78687260.png

代码实现:

/*** 获取元素前驱(中序遍历)

*@paramt 指定元素

*@return元素前驱,没有返回null*/

publicT prev(T t){//先找到该元素

Node cur =getN(t);if (cur != null){returnlocatePrev(cur);

}return null;

}/*** 定位到前驱节点

*@paramcur 当前节点

*@return前驱节点,没有返回null*/

private T locatePrev(Nodecur) {

Node prev =locatePrevN(cur);return prev == null ? null: prev.value;

}/*** 定位到前驱节点

*@paramcur 当前节点

*@return当前节点的前驱节点*/

private Node locatePrevN(Nodecur){if (cur != null){//1.如果该节点左子树不会空,则其前驱为其左子树的最大元素

if (cur.left != null) returnmaxN(cur.left);//2.该节点左子树为空, 则其前驱为:其祖先节点(递归), 且该祖先节点的右孩子也是其祖先节点//通俗的说,一直忘上找找到左拐后那个节点;

Node p =cur.parent;while(p != null && cur ==p.left){

cur=p;

p=p.parent;

}return p == null ? null: p;

}return null;

}

获取后继节点,也分两种情况:

1.该节点右子树不为空,其后继节点为其右子树的最小元素:

3e6c009daec6b83253884e4962f0eb6c.png

2.该节点右子树为空,其后继节点为其祖先节点(递归),且此祖先节点的左孩子也是该节点的祖先节点,就是说一直往上找其祖先节点,直到出现右拐后的那个祖先节点:

c6aa3121bd51e330ff10fb11e2ada9f1.png

实现代码:

/*** 获取元素后继元素(中序遍历)

*@paramt 指定元素

*@return后继元素,没有返回null*/

publicT next(T t){//先找到该元素

Node cur =getN(t);if (cur != null){returnlocateNext(cur);

}return null;

}/*** 定位当前节点的后继元素

*@paramcur 当前节点

*@return其后继元素*/

private T locateNext(Nodecur) {

Node next =locateNextN(cur);return next == null ? null: next.value;

}/*** 定位到当前节点的后继节点

*@paramcur 当前节点

*@return当前节点的后继节点*/

private Node locateNextN(Nodecur) {if (cur == null) return null;//1.若其右子树不为空,那么其后继节点就是其右子树的最小元素

if (cur.right != null) returnminN(cur.right);//2.若为空,应该为其祖先节点(递归),且该祖先节点的左孩子也是其祖先节点//通俗的说,一直忘上找,找到右拐后那个节点;

Node p =cur.parent;while (p != null && cur ==p.right){

cur=p;

p=p.parent;

}returnp;

}

删除(remove), 可分为三种情况:

1.该节点为叶子节点,直接删除:

d87965b7b60f7daebbc977e3ac2a18b4.png

2.该节点有一个孩子,将其孩子接上其父节点:

1c4bcc03d91651232b47f41427536cce.png

3.该节点有2个孩子,先删除其右子树的最小元素(该元素最多只会有一个孩子),将这个最小元素去替换要删除的节点:

f1bad54edaaa27bda782f9a035089542.png

实现代码:

/*** 移除某元素

*@paramt 待删除元素

*@return删除成功返回true, 反之false*/

public booleanremove(T t){//找到该节点

Node cur =getN(t);if (cur != null){if(doRemove(cur)){

cur=null; count--;return true;

}

}return false;

}/*** 执行删除操作*/

private boolean doRemove(Nodecur) {//该节点是否为根

boolean isRoot = cur ==root;//1.该节点为叶子节点, 直接将其父节点对应(左或右)孩子置空

if (cur.left == null && cur.right == null){if (isRoot) return true; //若树只有一个根节点

if (cur == cur.parent.right) //该节点为父节点的右孩子

cur.parent.right = null;else //该节点为父节点的左孩子

cur.parent.left = null;return true;

}else if(cur.left != null && cur.right != null){//2.该节点有2个孩子, 我们先找出一个替换节点(该节点的后继节点,后继节点没有则前驱节点)//找到其后继节点

Node replaceNode =locateNextN(cur);if (replaceNode == null) //若没有后继节点则用前驱节点

replaceNode =locatePrevN(cur);

doRemove(replaceNode);

cur.value=replaceNode.value;return true;

}else{ //3.该节点有1个孩子, 直接将其父节点对应(左或右)孩子接到其非空孩子

Node needLinkedNode = null;if (cur.left == null && cur.right != null){ //该节点有右孩子

needLinkedNode =cur.right;

}else if(cur.left != null && cur.right == null){ //该节点有左孩子

needLinkedNode =cur.left;

}if(isRoot){ //若该节点为根

root =needLinkedNode;return true;

}if (cur == cur.parent.right) //该节点为父节点右孩子

cur.parent.right =needLinkedNode;elsecur.parent.left=needLinkedNode;return true;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值