BST树
一、基本概念
二叉搜索树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树
二、创建结点类和二叉树类
public class BSTree<T extends Comparable> {
private Entry<T> root;//根节点
/**
*BST树的初始化
*/
public BSTree(Entry<T> root) {
this.root = null;
}
static class Entry<E extends Comparable>{
private E value;//数据域
private Entry<E> left;//左孩子域
private Entry<E> right;//右孩域
public Entry(E value, Entry<E> left, Entry<E> right) {
this.value = value;
this.left = left;
this.right = right;
}
public Entry(E value) {
this.value = value;
}
@Override
public String toString() {
return value+"";
}
}
三、BST树的增删查,前中后层序遍历的递归和非递归等操作
BST树的递归插入:
public void insert(T value) {
root= insert(root, value);
}
public Entry insert(Entry<T> root,T value){
if (root==null){
root = new Entry<>(value);
}else{
if (root.value.compareTo(value)>0){
root.left=insert(root.left,value);
}else if(root.value.compareTo(value)<0){
root.right = insert(root.right,value);
}
}
return root;
}
BST树的非递归插入:
public void ninsert(T value){
if (this.root==null){//根节点为空
this.root = new Entry<>(value);
return;
}
//树不为空,从root开始找合适h插入
Entry<T> parent = null;//记录cur的父节点
Entry<T> cur = this.root;//初始指向根节点
while (cur!=null){
if (cur.value.compareTo(value)>0){
parent = cur;
cur = cur.left;
}else if (cur.value.compareTo(value)<0){
parent = cur;
cur = cur.right;
}else {
return;//不插入相等元素
}
}
/**
* 退出循环后,cur==null
* 把新插入的叶子节点写入父节点相应的地址域中
*/
if (parent.value.compareTo(value)>0){
parent.left = new Entry<>(value);
}else {
parent.right = new Entry<>(value);
}
}
BST树的递归删除:
- 说明:删除有两种大的情况:一、删除的节点有一个子节点和没有子节点的;二、删除的节点左右两个子节点都在,这时候我们寻找前驱(左子树的最大值)或者后继(右子树的最小值)节点,我们把前驱或者后继的值赋给要删除的节点,再删除前驱或者后继节点,因为前驱或者后继节点要么没孩子,要么最多一个孩子,随意删除前驱或者后继节点就可以回到第一种大的情况。
public void remove(T value){
root = remove(root,value);
}
public Entry<T> remove(Entry<T> root,T value){
if (root==null){
return null;
}
if (root.value.compareTo(value)>0){
//当前节点的值比待删节点的值大,则继续在左子树中寻找
root.left = remove(root.left,value);
}else if (root.value.compareTo(value)<0){
//当前节点的值比待删节点的值小,则继续在右子树中寻找
root.right = remove(root.right,value);
}else {
//已找到待删除节点root,考虑有两个孩子的情况--》寻找前驱节
if (root.right!=null && root.left!=null){
//标记待删除节点的前驱节点,(左子树最大节点)
Entry<T> pre = root.left;
while (pre.right != null) {
//使pre指向待删节点的前驱节点
pre = pre.right;
}
root.value = pre.value;
//继续递归删除节点的前驱节点
root.left = remove(root.left, pre.value);
}else {
if (root.left!=null){
return root.left;
}else if (root.right!=null){
return root.right;
}else {
return null;
}
}
}
return root;
}
BST树非递归删除:
public void nremove(T value){
if (this.root == null){
return;
}
Entry<T> parent=null;
Entry<T> cur = this.root;
while (cur!=null){
if (cur.value.compareTo(value)>0){
parent = cur;
cur = cur.left;
}else if(cur.value.compareTo(value)<0){
parent = cur;
cur = cur.right;
}else{
break;//结束while循环,但是否找到,要看cur是否为空
}
if (cur==null){//没找到
return;
}
}
/**
* 找到了待删value节点,cur指向待删节点
* 先处理 待删节点有两个孩子:及就是要删除的节点有左右两个孩子
*/
if(cur.left != null && cur.right != null){
//找前驱节点代替待删除节点的值,然后删除前驱节点
Entry<T> old = cur; //记录待删节点
parent = cur;
cur = cur.left; //cur指向待删节点的左孩子域
while (cur.right != null){ //找前驱结点
parent = cur;
cur = cur.right;
}
//此时cur指向前驱结点
old.value = cur.value;
}
/**
* 统一删除cur指向的节点 即:有一个节点或者没有节点的情况
* child指向待删节点的不为空的孩子,可能为null
*/
Entry<T> child = cur.left;
if(child == null){
child = cur.right;
}
if (parent== null){//说明是根节点
this.root = child;
}else if (parent.left ==cur){
parent.left = child;
}else {
parent.right = child;
}
}
BST树的递归查找
public boolean search(T value) {
return search(root, value);
}
public boolean search(Entry<T> root,T value){
if (root==null){
return false;
}
if (root.value==value){
return true;
}else if (root.value.compareTo(value)>0){
return search(root.left,value);
}else{
return search(root.right,value);
}
}
BST树的非递归查找
public boolean nsearch(T value){
Entry<T> cur = this.root;//让cue先指向根节点root
while (cur!=null){
if (cur.value.compareTo(value)>0){
cur = cur.left;
}else if(cur.value.compareTo(value)<0){
cur = cur.right;
}else {
return true;//找到了
}
}
return false;
}
递归前序遍历:
public void preOrder() {
System.out.print("递归实现前序遍历"+" ");
preOrder(root);
System.out.println();
}
/**
* 前序递归实现BST树的前序遍历
*/
public void preOrder(Entry<T> root){
if (root==null){
return;
}
System.out.print(root.value+" ");
preOrder(root.left);
preOrder(root.right);
}
非递归前序遍历:
public void npreOrder(){
Stack<Entry> stack1 = new Stack<>();
if (root!=null){
stack1.push(root);//把根节点入栈
while (!stack1.empty()){
Entry<T> node = stack1.pop();//node为根节点 底下不断地把左右节点入栈
System.out.println(node.value);
if (node.right!=null) stack1.push(node.right);
if (node.left!=null) stack1.push(node.left);
}
}
}
递归中序遍历:
public void inOrder(){
System.out.print("递归实现中序遍历:");
inOrder(this.root);
System.out.println();
}
/**
* 以root指向的节点为起始节点进行中序遍历访问
* @param root
*/
private void inOrder(Entry<T> root) {
if(root ==null){
return;
}
inOrder(root.left);
System.out.print(root.value+" ");
inOrder(root.right);
}
非递归中序遍历:
public void ninOrder(){
Stack<Entry> stack2 = new Stack<>();
Entry<T> node = root;
while (node!=null || !stack2.empty()){
//左子树一直入栈
while (node!=null){
stack2.push(node);
node = node.left;
}
node = stack2.pop();
System.out.println(node.value);
node = node.right;
}
}
递归后序遍历:
public void postOrder(){
System.out.print("递归实现后序遍历:");
postOrder(this.root);
System.out.println();
}
/**
* 以root指向的节点为起始节点进行后序遍历访问
* @param root
*/
private void postOrder(Entry<T> root) {
if(root ==null){
return;
}
postOrder(root.left); //L
postOrder(root.right); //R
System.out.print(root.value+" "); //V
}
非递归后序遍历:
public void npostOrder(){
Entry<T> node = root;
Entry<T> cur =null;//记录之前走过的右节点
Stack<Entry> stack3 = new Stack<>();
while (node!=null || !stack3.empty()){
while (node!=null){//一直把左节点入栈
stack3.push(node);
node = node.left;
}
node = stack3.peek();
if (node.right==null || node.right== cur){
System.out.print(node.value+ " ");
node = stack3.pop();
cur = node;
node = null;
}else {
node = node.right;
}
}
}
递归层序遍历:
public int level(){
return level(this.root);
}
//从root指向的节点开始,计算BST树的层数
private int level(Entry<T> root) {
if(root == null){
return 0;
}
int left = level(root.left);
int right = level(root.right);
return left > right ? left+1 : right+1;
}
/**
* 以root指定的节点为起始节点,进行深度遍历,打印指定的第i层的节点
* @param root
* @param i
*/
private void levelOrder(Entry<T> root, int i) {
if(root == null){
return;
}
if(i == 0){
System.out.print(root.value+" ");
return;
}
levelOrder(root.left,i-1);//i-1最终是0 就是打印当前层元素
levelOrder(root.right,i-1);
}
/**
* 递归实现BST树的层序遍历
*/
public void levelOrder(){
System.out.print("递归实现层序遍历:");
int l = level();
for(int i = 0;i<l;i++){
levelOrder(this.root,i);
}
System.out.println();
}
非递归层序遍历:
public void nleveOrder(){
if (root==null){
return;
}
LinkedList<Entry<T>> queue = new LinkedList<>();
queue.offer(root);//把根节点root加入队列 先进先出的原则
while (!queue.isEmpty()){
Entry<T> front = queue.poll();//弹出队列
System.out.println(front.value+" ");
if (front.left!=null){
queue.offer(front.left);//把当前节点的左孩子加入队列
}
if (front.right!=null){
queue.offer(front.left);//把当前节点的右孩子加入队列
}
}
}
输出节点个数:
public int num(){
return num(this.root);
}
private int num(Entry<T> root){
if (root==null){
return 0;
}else {
return num(root.left)+num(root.right)+1;
}
}
判断一个树是否是二叉节点树
* 思路:也就是看左右孩子和父节点比较,然后递归就好
public boolean isBstree() {
return isBstree(root);
}
public boolean isBstree(Entry<T> root){
if (root==null){
return true;
}
if (root.left!=null&& root.left.value.compareTo(root.value)>0){
return false;
}
if (root.right!=null&&root.right.value.compareTo(root.value)<0) {
return false;
}
return isBstree(root.left)&&isBstree(root.right);
}
中序遍历方式,求第k个节点
public Entry ngetValue(int k){
return ngetValue(root,5);
}
public Entry ngetValue(Entry<T> root,int k){
if (root==null|| k<=0 ){
return null;
}
Stack<Entry<T>> stack = new Stack<>();
Entry<T> cur = root;
while (cur!=null || !stack.isEmpty()) {//中序遍历的方式
if (cur!=null){
stack.push(cur);//把的左孩子一直入栈
cur=cur.left;
}else {
cur = stack.pop();//当前节点null则弹出栈顶元素,
//相当于按顺序输出最小
if (--k==0){
return cur;
}
cur = cur.right;
}
}
return null;
}
while(true){
输出("谢谢大家观看=-=");
}