详解Java二叉排序树

一、二叉排序树定义
1.二叉排序树的定义
  二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
③左、右子树本身又各是一棵二叉排序树。
上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。

2.二叉排序树的性质
按中序遍历二叉排序树,所得到的中序遍历序列是一个递增有序序列。

3.二叉排序树的插入
在二叉排序树中插入新结点,要保证插入后的二叉树仍符合二叉排序树的定义。   
插入过程:
若二叉排序树为空,则待插入结点*S作为根结点插入到空树中;   
当非空时,将待插结点关键字S->key和树根关键字t->key进行比较,若s->key = t->key,则无须插入,若s->key< t->key,则插入到根的左子树中,若s->key> t->key,则插入到根的右子树中。而子树中的插入过程和在树中的插入过程相同,如此进行下去,直到把结点*s作为一个新的树叶插入到二叉排序树中,或者直到发现树已有相同关键字的结点为止。

4.二叉排序树的查找
假定二叉排序树的根结点指针为 root ,给定的关键字值为 K ,则查找算法可描述为:
  ① 置初值: q = root ;
  ② 如果 K = q -> key ,则查找成功,算法结束;
  ③ 否则,如果 K < q -> key ,而且 q 的左子树非空,则将 q 的左子树根送 q ,转步骤②;否则,查找失败,结束算法;
  ④ 否则,如果 K > q -> key ,而且 q 的右子树非空,则将 q 的右子树根送 q ,转步骤②;否则,查找失败,算法结束。

5.二叉排序树的删除
假设被删结点是*p,其双亲是*f,不失一般性,设*p是*f的左孩子,下面分三种情况讨论:   
⑴ 若结点*p是叶子结点,则只需修改其双亲结点*f的指针即可。   
⑵ 若结点*p只有左子树PL或者只有右子树PR,则只要使PL或PR 成为其双亲结点的左子树即可。   
⑶ 若结点*p的左、右子树均非空,先找到*p的中序前趋(或后继)结点*s(注意*s是*p的左子树中的最右下的结点,它的右链域为空),然后有两种做法:① 令*p的左子树直接链到*p的双亲结点*f的左链上,而*p的右子树链到*p的中序前趋结点*s的右链上。② 以*p的中序前趋结点*s代替*p(即把*s的数据复制到*p中),将*s的左子树链到*s的双亲结点*q的左(或右)链上。
6、二叉树的遍历
二叉树的遍历有三种方式,如下:
(1)前序遍历(DLR),首先访问根结点,然后遍历左子树,最后遍历右子树。简记根-左-右。
(2)中序遍历(LDR),首先遍历左子树,然后访问根结点,最后遍历右子树。简记左-根-右。
(3)后序遍历(LRD),首先遍历左子树,然后遍历右子树,最后访问根结点。简记左-右-根。

二、代码编写
1、树节点类的定义0

package com.lin;
/**
 * 功能概要: 

 */
public class TreeNode { 

  public Integer data; 

  /*该节点的父节点*/
  public TreeNode parent; 

  /*该节点的左子节点*/
  public TreeNode left; 

  /*该节点的右子节点*/
  public TreeNode right; 

  public TreeNode(Integer data) {
    this.data = data; 

  } 

  @Override
  public String toString() {
    return "TreeNode [data=" + data + "]";
  } 

}

2、二叉排序树的定义

package com.lin; 

/**
 * 功能概要:排序/平衡二叉树 

 */
public class SearchTree { 

   public TreeNode root; 

   public long size; 

  /**
   * 往树中加节点
   * @param data
   * @return Boolean 插入成功返回true
   */
  public Boolean addTreeNode(Integer data) { 

    if (null == root) {
      root = new TreeNode(data);
      System.out.println("数据成功插入到平衡二叉树中");
      return true;
    } 

    TreeNode treeNode = new TreeNode(data);// 即将被插入的数据
    TreeNode currentNode = root;
    TreeNode parentNode; 

    while (true) {
      parentNode = currentNode;// 保存父节点
      // 插入的数据比父节点小
      if (currentNode.data > data) {
        currentNode = currentNode.left;
        // 当前父节点的左子节点为空
        if (null == currentNode) {
          parentNode.left = treeNode;
          treeNode.parent = parentNode;
          System.out.println("数据成功插入到二叉查找树中");
          size++;
          return true;
        }
        // 插入的数据比父节点大
      } else if (currentNode.data < data) {
        currentNode = currentNode.right;
        // 当前父节点的右子节点为空
        if (null == currentNode) {
          parentNode.right = treeNode;
          treeNode.parent = parentNode;
          System.out.println("数据成功插入到二叉查找树中");
          size++;
          return true;
        }
      } else {
        System.out.println("输入数据与节点的数据相同");
        return false;
      }
    }
  } 

  /**
   * @param data
   * @return TreeNode
   */
  public TreeNode findTreeNode(Integer data){
    if(null == root){
      return null;
    }
    TreeNode current = root;
    while(current != null){
      if(current.data > data){
        current = current.left;
      }else if(current.data < data){
        current = current.right;
      }else {
        return current;
      } 

    }
    return null;
  } 

}

这里暂时只放了一个增加和查找的方法
3、前、中、后遍历

package com.lin; 

import java.util.Stack; 

/**
 * 功能概要:
 */
public class TreeOrder { 

  /**
   * 递归实现前序遍历
   * @author linbingwen
   * @since 2015年8月29日
   * @param treeNode
   */
  public static void preOrderMethodOne(TreeNode treeNode) {
    if (null != treeNode) {
      System.out.print(treeNode.data + " ");
      if (null != treeNode.left) {
        preOrderMethodOne(treeNode.left);
      }
      if (null != treeNode.right) {
        preOrderMethodOne(treeNode.right); 

      }
    }
  } 

  /**
   * 循环实现前序遍历
   * @param treeNode
   */
  public static void preOrderMethodTwo(TreeNode treeNode) {
    if (null != treeNode) {
      Stack<TreeNode> stack = new Stack<TreeNode>();
      stack.push(treeNode);
      while (!stack.isEmpty()) {
        TreeNode tempNode = stack.pop();
        System.out.print(tempNode.data + " ");
        // 右子节点不为null,先把右子节点放进去
        if (null != tempNode.right) {
          stack.push(tempNode.right);
        }
        // 放完右子节点放左子节点,下次先取
        if (null != tempNode.left) {
          stack.push(tempNode.left);
        }
      }
    }
  } 

  /**
   * 递归实现中序遍历
   * @param treeNode
   */
  public static void medOrderMethodOne(TreeNode treeNode){
    if (null != treeNode) {
      if (null != treeNode.left) {
        medOrderMethodOne(treeNode.left);
      }
      System.out.print(treeNode.data + " ");
      if (null != treeNode.right) {
        medOrderMethodOne(treeNode.right);
      }
    } 

  } 

  /**
   * 循环实现中序遍历
   * @param treeNode
   */
  public static void medOrderMethodTwo(TreeNode treeNode){
    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode current = treeNode;
    while (current != null || !stack.isEmpty()) {
      while(current != null) {
        stack.push(current);
        current = current.left;
      }
      if (!stack.isEmpty()) {
        current = stack.pop();
        System.out.print(current.data+" ");
        current = current.right;
      }
    }
  } 

  /**
   * 递归实现后序遍历
   * @param treeNode
   */
  public static void postOrderMethodOne(TreeNode treeNode){
    if (null != treeNode) {
      if (null != treeNode.left) {
        postOrderMethodOne(treeNode.left);
      }
      if (null != treeNode.right) {
        postOrderMethodOne(treeNode.right);
      }
      System.out.print(treeNode.data + " ");
    } 

  } 

  /**
   * 循环实现后序遍历
   * @param treeNode
   */
  public static void postOrderMethodTwo(TreeNode treeNode){
    if (null != treeNode) {
      Stack<TreeNode> stack = new Stack<TreeNode>();
      TreeNode current = treeNode;
      TreeNode rightNode = null;
      while(current != null || !stack.isEmpty()) {
        while(current != null) {
          stack.push(current);
          current = current.left;
        }
        current = stack.pop();
        while (current != null && (current.right == null ||current.right == rightNode)) {
          System.out.print(current.data + " ");
          rightNode = current;
          if (stack.isEmpty()){
            System.out.println();
            return;
          }
          current = stack.pop();
        }
        stack.push(current);
        current = current.right;
      }  

    }
  } 

}

4、使用方法

package com.lin;
/**
 * 功能概要:
*/
public class SearchTreeTest { 

  /**
   * @param args
   */
  public static void main(String[] args) {
    SearchTree tree = new SearchTree();
    tree.addTreeNode(50);
    tree.addTreeNode(80);
    tree.addTreeNode(20);
    tree.addTreeNode(60);
    tree.addTreeNode(10);
    tree.addTreeNode(30);
    tree.addTreeNode(70);
    tree.addTreeNode(90);
    tree.addTreeNode(100);
    tree.addTreeNode(40);
    System.out.println("=============================="+"采用递归的前序遍历开始"+"==============================");
    TreeOrder.preOrderMethodOne(tree.root);
    System.out.println();
    System.out.println("=============================="+"采用循环的前序遍历开始"+"==============================");
    TreeOrder.preOrderMethodTwo(tree.root);
    System.out.println();
    System.out.println("=============================="+"采用递归的后序遍历开始"+"==============================");
    TreeOrder.postOrderMethodOne(tree.root);
    System.out.println();
    System.out.println("=============================="+"采用循环的后序遍历开始"+"==============================");
    TreeOrder.postOrderMethodTwo(tree.root);
    System.out.println();
    System.out.println("=============================="+"采用递归的中序遍历开始"+"==============================");
    TreeOrder.medOrderMethodOne(tree.root);
    System.out.println();
    System.out.println("=============================="+"采用循环的中序遍历开始"+"==============================");
    TreeOrder.medOrderMethodTwo(tree.root); 

  } 

}

输出结果:

同样,进行查找过程如下:

TreeNode node = tree.findTreeNode(100);
System.out.println(node); 

结果是正确的

以上就是关于Java二叉排序树的详细介绍,希望对大家的学习java程序设计有所帮助。

时间: 2015-12-29

图解二叉树的三种遍历方式及java实现代码

二叉树(binary tree)是一颗树,其中每个节点都不能有多于两个的儿子. 1.二叉树节点 作为图的特殊形式,二叉树的基本组成单元是节点与边:作为数据结构,其基本的组成实体是二叉树节点(binary tree node),而边则对应于节点之间的相互引用. 如下,给出了二叉树节点的数据结构图示和相关代码: // 定义节点类: private static class BinNode { private Object element; private BinNode lChild;// 定义指向

Java基于二叉查找树实现排序功能示例

本文实例讲述了Java基于二叉查找树实现排序功能.分享给大家供大家参考,具体如下: /** * 无论排序的对象是什么,都要实现Comparable接口 * * @param <T> */ public class BinaryNode<T extends Comparable<T>> { private static int index = 0; // 排序下标 private static int len = 0; // 最大数组长度 private T t; //

Java 实现二叉搜索树的查找、插入、删除、遍历

由于最近想要阅读下JDK1.8 中HashMap的具体实现,但是由于HashMap的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关知识,所以写下这篇随笔备忘,有不对的地方请指出- 学习红黑树,我觉得有必要从二叉搜索树开始学起,本篇随笔就主要介绍Java实现二叉搜索树的查找.插入.删除.遍历等内容. 二叉搜索树需满足以下四个条件: 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 任意节点的左.右子

Java实现求二叉树的深度和宽度

这个是常见的对二叉树的操作.总结一下: 设节点的数据结构,如下: 复制代码 代码如下: class TreeNode {     char val;     TreeNode left = null;     TreeNode right = null; TreeNode(char _val) {         this.val = _val;     } } 1.二叉树深度 这个可以使用递归,分别求出左子树的深度.右子树的深度,两个深度的较大值+1即可. 复制代码 代码如下: // 获取最大

java使用归并删除法删除二叉树中节点的方法

本文实例讲述了java使用归并删除法删除二叉树中节点的方法.分享给大家供大家参考.具体分析如下: 实现的思想很简单: first:找到要删除的节点 second:如果删除的节点没有右子树那么左子树链到父节点 third:如果删除的节点没有左子树那么右子树链到父节点 forth:如果删除的节点又左右孩子,那么可以归并删除节点后的子树:方法有两种一种是用删除节点的左子树的最右节点,指向删除节点的右子树,另一种是用删除节点的用字数的最左节点指向删除节点的左子树. Java 实现如下: public v

java 二叉查找树实例代码

java 二叉查找树实例代码 1.左边<中间<右边 2.前序遍历 左中右 3.中序遍历 中左右 4.后序遍历 左右中 public class BinaryTree { // 二叉树的根节点 public TreeNode rootNode ; // 记录搜索深度 public int count; /** * 利用传入一个数组来建立二叉树 */ public BinaryTree(int[] data) { for (int i = 0; i < data. length; i++)

Java的二叉树排序以及遍历文件展示文本格式的文件树

Java二叉树排序算法 排序二叉树的描述也是一个递归的描述, 所以排序二叉树的构造自然也用递归的: 排序二叉树的3个特征: 1:当前node的所有左孩子的值都小于当前node的值: 2:当前node的所有右孩子的值都大于当前node的值: 3:孩子节点也满足以上两点 package test.sort; public class BinaryNode { private int value;//current value private BinaryNode lChild;//left chil

JAVA 实现二叉树(链式存储结构)

二叉树的分类(按存储结构) 树的分类(按存储结构) 顺序存储(用数组表示(静态二叉树))   链式存储 一些特别的二叉根: 完全二叉树,平衡二叉树(AVL),线索二叉树,三叉的(带父亲的指针)    二叉搜索树或者叫二叉 查找树(BST)  所用二叉树如下图所示: 二叉树的Java实现(链式存储结构) class TreeNode { private int key = 0; private String data = null; private boolean isVisted = false

java二叉查找树的实现代码

本文实例为大家分享了java二叉查找树的具体代码,供大家参考,具体内容如下 package 查找; import edu.princeton.cs.algs4.Queue; import edu.princeton.cs.algs4.StdOut; public class BST<Key extends Comparable<Key>, Value> { private class Node { private Key key; // 键 private Value value;

java实现二叉树的创建及5种遍历方法(总结)

用java实现的数组创建二叉树以及递归先序遍历,递归中序遍历,递归后序遍历,非递归前序遍历,非递归中序遍历,非递归后序遍历,深度优先遍历,广度优先遍历8种遍历方式: package myTest; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Stack; public class myClass { public static void main(

图解红黑树及Java进行红黑二叉树遍历的方法

红黑树 红黑树是一种数据结构与算法课堂上常常提到但又不会细讲的树,也是技术面试中经常被问到的树,然而无论是书上还是网上的资料,通常都比较刻板难以理解,能不能一种比较直观的方式来理解红黑树呢?本文将以图形的方式来解释红黑树的插入与删除操作. 对树结构的学习是一个递进的过程,我们通常所接触的树都是二叉树,二叉树简单来说就是每个非叶子节点都有且只有两个孩子,分别叫做左孩子和右孩子.二叉树中有一类特殊的树叫二叉查找树,二叉查找树是一种有序的树,对于每个非叶子节点,其左子树的值都小于它,其右子树的值都大于

Java中二叉树数据结构的实现示例

来看一个具体的习题实践: 题目 根据二叉树前序遍历序列例如:7,-7,8,#,#,-3,6,#,9,#,#,#,-5,#,#,构建二叉树,并且用前序.中序.后序进行遍历 代码 import java.util.Scanner; public class BinaryTree { public static String[] str; public static int count; /** * 静态内部类,定义二叉树节点 */ static class TreeNode { public Str

Java中二叉树的建立和各种遍历实例代码

这是个常见的面试题,比如说通过二叉树的先序和中序遍历,得到二叉树的层序遍历等问题 先序+中序->建树 假设现在有个二叉树,如下: 此时遍历顺序是: PreOrder: GDAFEMHZ InOrder: ADEFGHMZ PostOrder: AEFDHZMG 现在给出先序(preOrder)和中序(InOrder),建立一颗二叉树 或者给出中序(InOrder)和后序(PostOrder), 建立二叉树,其实是一样的 树节点的定义: class Tree{ char val; Tree lef

数据结构与算法中二叉树子结构的详解

数据结构与算法中二叉树子结构的详解 需求 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 树的描述: class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } 解决思路 使用了栈将元素入栈,并不断的弹出元素,弹出一个元素的时候,拼接成字符串,并用特殊符号进行区分,该方法

java编程队列数据结构代码示例

队列是一种特殊的线性表,只允许在表的前端进行删除,在表的后端进行插入,表的前端称为(front)队头,表的后端称为(rear)队尾. 所以队列跟生活的场景很是相似,在电影院买电影票,人们排成一排,第一个人进入队尾最先到达队头后买票进入影院,后面排队的人按照排队的次序买到票后进入影院. 所以 队列是一种先进先出的数据结构(FIFO). 编程实现对循环链队列的入队和出队操作. ⑴根据输入的队列长度n和各元素值建立一个带头结点的循环链表表示的队列(循环链队列),并且只设一个尾指针来指向尾结点,然后输出

浅谈Java中常用数据结构的实现类 Collection和Map

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类. Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap Collection接口 Collection是最基本的集合接口,一个C

java实现队列数据结构代码详解

什么是队列结构 一种线性结构,具有特殊的运算法则[只能在一端(队头)删除,在另一端(队尾)插入]. 分类: 顺序队列结构 链式队列结构 基本操作: 入队列 出队列 给出一些应用队列的场景 1):当作业被送到打印机的时候,就可以按到达的顺序排起来,因此每一份作业是队列的节点. 2):售票口的人买票的顺序的按照先来先买的顺序售票. 3):当所有的终端被占用,由于资源有限,来访请求需要放在一个队列中等候. 队列是先进先出的! 我们设置一个叫做LinkQueue<T>的泛型集合类,该类里面有 Node

Java实现Swing组件定制Button示例

本文实例讲述了Java实现Swing组件定制Button.分享给大家供大家参考,具体如下: 先来看看运行效果图: 具体代码如下: package themedemo; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.RenderingHin

Java语言实现数据结构栈代码详解

近来复习数据结构,自己动手实现了栈.栈是一种限制插入和删除只能在一个位置上的表.最基本的操作是进栈和出栈,因此,又被叫作"先进后出"表. 首先了解下栈的概念: 栈是限定仅在表头进行插入和删除操作的线性表.有时又叫LIFO(后进先出表).要搞清楚这个概念,首先要明白"栈"原来的意思,如此才能把握本质. "栈"者,存储货物或供旅客住宿的地方,可引申为仓库.中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈.出栈的说法. 实现方式是

java&javascript自定义加密数据传输代码示例

在开发应用过程中,客户端与服务端经常需要进行数据传输,涉及到重要隐私信息时,开发者自然会想到对其进行加密,即使传输过程中被"有心人"截取,也不会将信息泄露.对于加密算法,相信不少开发者也有所耳闻,比如MD5加密,Base64加密,DES加密,AES加密,RSA加密等等..可利用亦或,并,且,等进行简单加密. 示例代码中使用的^运算key=0x01,可自定义自己的规则.定义自己的运算,保证可逆数据不丢失即可.key也可定义,动态key. java代码 public static Stri

java简单实现八叉树图像处理代码示例

一晃工作有段时间了,第一次写博客,有点不知道怎么写,大家将就着看吧,说的有什么不正确的也请大家指正. 最近工作中用到了一个图像压缩的功能.找了一些工具,没有太好的选择.最后选了一个叫jdeli的,奈何效率又成了问题.我迫于无奈就只能研究了下它的源码,却发现自己对它的一个减色量化算法起了兴趣,可是尴尬的自己完全不明白它写的什么,就起了一个自己实现一个量化颜色算法的念头. 自己找了一些资料,找到三个比较常用的颜色处理算法: 流行色算法: 具体的算法就是,先对一个图像的所有颜色出现的次数进行统计,选举