/**
* 创建树的节点 -----链式
* @author Mona
*
*/
public class TreeNode {
//节点的权
int value;
//左儿子
TreeNode leftNode;
//右儿子
TreeNode rightNode;
public TreeNode(int value) {
this.value = value;
}
//设置左儿子
public void setLeftNode(TreeNode leftNode) {
this.leftNode = leftNode;
}
//设置右儿子
public void setRightNode(TreeNode rightNode) {
this.rightNode = rightNode;
}
//前序遍历
public void frontShow() {
//先打印自己的值[先遍历当前结点的内容]
System.out.println(value);
//左边node
if(leftNode != null) {
leftNode.frontShow();//递归操作可能没有,需在前面添加判断
}
//右结点
if(rightNode != null) {
rightNode.frontShow(); //递归 //前序遍历输出:1 2 4 5 3 6 7
}
}
//中序遍历
public void midShow() {
//左结点
if(leftNode != null) {
leftNode.midShow();
}
//当前结点
System.out.println(value);
//右结点
if(rightNode != null) {
rightNode.midShow();
}
}
//后序遍历
public void afterShow() {
// 左结点
if (leftNode != null) {
leftNode.afterShow();
}
// 右结点
if (rightNode != null) {
rightNode.afterShow();
}
// 当前结点
System.out.println(value);
}
//前序查找 ------------------->二叉树中的结点查找
public TreeNode frontSearch(int i) {
TreeNode target = null;
//对比当前结点的值
if(this.value == i) {
return this;
//当前结点的值不是要查找的结点
}else {
//查找左儿子
if(leftNode != null) {
//有可能查得到,也可能查不到,查不到的话,target还是一个null
target = leftNode.frontSearch(i);
}
//如果不为空,说明在左儿子中已经找到
if(target != null) {
return target;
}
//查找右孩子
if(rightNode != null) {
target = rightNode.frontSearch(i);
}
}
return target;
}
//中序查找
public TreeNode middleSearch(int i) {
TreeNode target = null;
if(leftNode != null) {
target = leftNode.middleSearch(i);
}else {
if(this.value == i) {
return this;
}
if(rightNode != null) {
target = rightNode.middleSearch(i);
}
}
return target;
}
//删除二叉树的子树
public void delete(int i) {
TreeNode parent = this;
//判断左儿子
if(parent.leftNode != null && parent.leftNode.value == i) { //注意判断是否为空
parent.leftNode = null;
return ;
}
if(parent.rightNode != null && parent.rightNode.value == i) {
parent.rightNode = null;
return;
}
//递归检查并删除左儿子
parent = leftNode;
if(parent != null) {
parent.delete(i);
}
parent = rightNode;
if(parent != null) {
parent.delete(i);
}
}
}
/**
* 设置根
* @author Mona
*
*/
public class BinaryTree {
TreeNode root;
//设置根节点
public void setRoot(TreeNode root) {
this.root = root;
}
//获取根节点
public TreeNode getRoot() {
return root;
}
public void frontShow() {
if(root != null) { //删除根结点时使用到的,如果根结点没有了,则不可以进行调用,空指针
//调root
root.frontShow();
}
}
public void midShow() {
if(root != null) {
root.midShow();
}
}
public void afterShow() {
if(root != null) {
root.afterShow();
}
}
public TreeNode frontSearch(int i) {
return root.frontSearch(i);
}
public TreeNode middleSearch(int i) {
return root.middleSearch(i);
}
public void delete(int i) {
if(root.value == i) {
root = null;
}else{
root.delete(i);
}
}
}
/**
* 主方法----测试
* @author Mona
*
*/
public class TestBinaryTree {
public static void main(String[] args) {
//创建一棵树
BinaryTree binTree = new BinaryTree();
//创建一个根结点
TreeNode root = new TreeNode(1);
binTree.setRoot(root);//把根节点赋给树
TreeNode rootL = new TreeNode(2);//创建一个左节点
root.setLeftNode(rootL);//把新创建的节点设置为根节点的子结点
TreeNode rootR = new TreeNode(3);///创建一个右结点
root.setRightNode(rootR);//把新创建的结点设置为根结点的子结点
rootL.setLeftNode(new TreeNode(4));//为第二层的左结点创建两个子结点
rootL.setRightNode(new TreeNode(5));
rootR.setLeftNode(new TreeNode(6));//为第二层的右结点创建两个子结点
rootR.setRightNode(new TreeNode(7));
//前序遍历
binTree.frontShow();
System.out.println("---------------------");
//中序遍历
binTree.midShow();
System.out.println("=====================");
//后序遍历
binTree.afterShow();
//前序查找
TreeNode result = binTree.frontSearch(5);
System.out.println(result);
TreeNode resultm = binTree.middleSearch(4);
System.out.println(resultm);
System.out.println("==========================");
//删除根结点时,相应的它下面的子左右结点都被删除了
//删除二叉树中的一个子树
binTree.delete(2);
binTree.frontShow();
}
}
/**
* 顺序存储的二叉树---前序遍历
* 数组形式
*
* @author Mona
*
*/
public class ArrayBinaryTree {
int[] data;
public ArrayBinaryTree(int[] data) {
this.data = data;
}
public void frontShow() {
frontShow(0);
}
//前序遍历
public void frontShow(int index) {
if(data==null || data.length==0) {
return;
}
System.out.println(data[index]);
//处理左子树
if(2*index+1
public class TestArrayBinaryTree {
public static void main(String[] args) {
int[] data = new int[] {1,2,3,4,5,6,7};
ArrayBinaryTree tree = new ArrayBinaryTree(data);
tree.frontShow();
}
}
/**
* 创建树的节点
* @author Mona
*
*/
public class ThreadedNode {
//节点的权
int value;
//左儿子
ThreadedNode leftNode;
//右儿子
ThreadedNode rightNode;
//标识指针类型
int leftType;
int rightType;
public ThreadedNode(int value) {
this.value = value;
}
//设置左儿子
public void setLeftNode(ThreadedNode leftNode) {
this.leftNode = leftNode;
}
//设置右儿子
public void setRightNode(ThreadedNode rightNode) {
this.rightNode = rightNode;
}
//前序遍历
public void frontShow() {
//先打印自己的值[先遍历当前结点的内容]
System.out.println(value);
//左边node
if(leftNode != null) {
leftNode.frontShow();//递归操作可能没有,需在前面添加判断
}
//右结点
if(rightNode != null) {
rightNode.frontShow(); //递归 //前序遍历输出:1 2 4 5 3 6 7
}
}
//中序遍历
public void midShow() {
//左结点
if(leftNode != null) {
leftNode.midShow();
}
//当前结点
System.out.println(value);
//右结点
if(rightNode != null) {
rightNode.midShow();
}
}
//后序遍历
public void afterShow() {
// 左结点
if (leftNode != null) {
leftNode.afterShow();
}
// 右结点
if (rightNode != null) {
rightNode.afterShow();
}
// 当前结点
System.out.println(value);
}
//前序查找 ------------------->二叉树中的结点查找
public ThreadedNode frontSearch(int i) {
ThreadedNode target = null;
//对比当前结点的值
if(this.value == i) {
return this;
//当前结点的值不是要查找的结点
}else {
//查找左儿子
if(leftNode != null) {
//有可能查得到,也可能查不到,查不到的话,target还是一个null
target = leftNode.frontSearch(i);
}
//如果不为空,说明在左儿子中已经找到
if(target != null) {
return target;
}
//查找右孩子
if(rightNode != null) {
target = rightNode.frontSearch(i);
}
}
return target;
}
//中序查找
public ThreadedNode middleSearch(int i) {
ThreadedNode target = null;
if(leftNode != null) {
target = leftNode.middleSearch(i);
}else {
if(this.value == i) {
return this;
}
if(rightNode != null) {
target = rightNode.middleSearch(i);
}
}
return target;
}
//删除二叉树的子树
public void delete(int i) {
ThreadedNode parent = this;
//判断左儿子
if(parent.leftNode != null && parent.leftNode.value == i) { //注意判断是否为空
parent.leftNode = null;
return ;
}
if(parent.rightNode != null && parent.rightNode.value == i) {
parent.rightNode = null;
return;
}
//递归检查并删除左儿子
parent = leftNode;
if(parent != null) {
parent.delete(i);
}
parent = rightNode;
if(parent != null) {
parent.delete(i);
}
}
}
/**
* 线索二叉树
* 设置根
* @author Mona
*
*/
public class BinaryTree {
ThreadedNode root;
//用于临时存储前驱节点
ThreadedNode pre = null;
//遍历线索二叉树
public void threadIterate() {
//用于临时存储当前遍历节点
ThreadedNode node = root;
while(node != null) {
//循环找到最开始的节点
while(node.leftType == 0) {
node = node.leftNode;
}
//打印当前节点的值
System.out.println(node.value);
//如果当前节点的右指针指向的是后继节点,可能后继节点还有后继节点
while(node.rightType == 1) {
node = node.rightNode;
System.out.println(node.value);
}
//替换遍历的节点
node = node.rightNode;
}
}
// 标识指针类型
int leftType;
int rightType;
//设置根节点
public void setRoot(ThreadedNode root) {
this.root = root;
}
//中序线索化二叉树
public void threadNodes() {
threadNodes(root);
}
public void threadNodes(ThreadedNode node) {
//当前节点如果未null,直接返回
if(node == null) {
return;
}
//处理左子树
threadNodes(node.leftNode);
//处理前驱节点
if(node.leftNode == null) {
//让当前节点的做指针指向前驱节点
node.leftNode = pre;
//改变当前节点左指针的类型
node.leftType = 1;
}
//处理前驱的右指针,如果前驱结点的右指针是null(没有指向右子树)
if(pre!=null &&pre.rightNode == null) {
//让前驱结点的右指针指向当前节点
pre.rightNode = node;
//改变前驱结点的右指针类型
pre.rightType = 1;
}
//每处理一个节点,当前节点是下一个节点的前驱结点
pre = node;
//处理右子树
threadNodes(node.rightNode);
}
//获取根节点
public ThreadedNode getRoot() {
return root;
}
public void frontShow() {
if(root != null) { //删除根结点时使用到的,如果根结点没有了,则不可以进行调用,空指针
//调root
root.frontShow();
}
}
public void midShow() {
if(root != null) {
root.midShow();
}
}
public void afterShow() {
if(root != null) {
root.afterShow();
}
}
public ThreadedNode frontSearch(int i) {
return root.frontSearch(i);
}
public ThreadedNode middleSearch(int i) {
return root.middleSearch(i);
}
public void delete(int i) {
if(root.value == i) {
root = null;
}else{
root.delete(i);
}
}
}
/**
* 主方法----测试
* @author Mona
*
*/
public class TestBinaryTree {
public static void main(String[] args) {
//创建一棵树
BinaryTree binTree = new BinaryTree();
//创建一个根结点
ThreadedNode root = new ThreadedNode(1);
binTree.setRoot(root);//把根节点赋给树
ThreadedNode rootL = new ThreadedNode(2);//创建一个左节点
root.setLeftNode(rootL);//把新创建的节点设置为根节点的子结点
ThreadedNode rootR = new ThreadedNode(3);///创建一个右结点
root.setRightNode(rootR);//把新创建的结点设置为根结点的子结点
rootL.setLeftNode(new ThreadedNode(4));//为第二层的左结点创建两个子结点
ThreadedNode fiveNode = new ThreadedNode(5);
rootL.setRightNode(fiveNode);
rootR.setLeftNode(new ThreadedNode(6));//为第二层的右结点创建两个子结点
rootR.setRightNode(new ThreadedNode(7));
//中序遍历树
binTree.midShow();
System.out.println("=====================");
//中序线索化二叉树
binTree.threadNodes();
binTree.threadIterate();
System.out.println("==============");
//查找5节点的后继节点
ThreadedNode afterNode = fiveNode.rightNode;
System.out.println(afterNode.value);
}
}
线性结构
顺序存储,不排序:查找困难
顺序存储,排序:删除插入困难
链式存储:无论是否排序 查找困难
二叉排序树,也叫二叉查找树、二叉搜索树:BST
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。
public class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
/**
* 向子树中添加节点
*
* @param node
*/
public void add(Node node) {
if(node == null) {
return;
}
//判断传入的节点的只比当前子树的根节点的值是大还是小
//添加的节点比当前节点的值更小
if(node.value < this.value) {
//如果左节点为空
if(this.left == null) {
this.left = node;
//如果不为空
}else {
this.left.add(node);
}
}else {
if(this.right == null) {
this.right = node;
}else {
this.right.add(node);
}
}
}
/**
* 中序遍历
*
* @param node
*/
public void midShow(Node node) {
if(node == null) {
return;
}
midShow(node.left);
System.out.println(node.value);
midShow(node.right);
}
/**
* 查找节点
*
* @param value2
* @return
*/
public Node search(int value) {
if(this.value == value) {
return this;
}else if(value < this.value) {
if(left == null) {
return null;
}
return left.search(value);
}else {
if(right == null) {
return null;
}
return right.search(value);
}
}
/**
* 搜索父节点
*
* @param value2
* @return
*/
public Node searchParent(int value) {
if((this.left!=null && this.left.value==value)||(this.right!=null && this.right.value==value)) {
return this;
}else {
if(this.value>value && this.left!=null) {
return this.left.searchParent(value);
}else if(this.value
public class BinarySortTree {
Node root;
/**
* 向二叉排序树中添加节点
*
* @param node
*/
public void add(Node node) {
//如果是一棵空树
if(root == null) {
root = node;
}else {
root.add(node);
}
}
/**
* 中序遍历二叉排序树,从小到大的顺序
*
*/
public void midShow() {
if(root != null) {
root.midShow(root);
}
}
/**
* 查找节点的方法
*
* @param value
* @return
*/
public Node search(int value) {
if(root == null) {
return null;
}else {
return root.search(value);
}
}
/**
* 删除节点
*
* @param value
* @return
*/
public void delete(int value) {
if(root == null) {
return;
}else {
//找到这个节点
Node target = search(value);
//如果没有这个节点
if(target == null) {
return;
}
//找到他的父节点
Node parent = searchParent(value);
//要删除的节点是叶子节点
if(target.left==null && target.right==null) {
//要删除的节点是父节点的左子节点
if(parent.left.value == value) {
parent.left = null;
//要删除的节点是父节点的右子节点
}else {
parent.right = null;
}
//要删除的节点有两个子节点的情况
}else if(target.left!=null && target.right!=null){
//删除右子树中值最小的节点,去获取到该节点的值
int min = deleteMin(target.right);
//替换目标节点中的值
target.value = min;
//要删除的节点有一个左子节点
}else {
//有左子节点
if(target.left != null) {
//要删除的节点是父节点的左子节点
if(parent.left.value == value) {
parent.left = target.left;
//要删除的节点是夫界定啊的右子节点
}else {
parent.right = target.left;
}
}
}
}
}
/**
* 删除一棵树中最小的节点
*
* @param right
* @return
*/
private int deleteMin(Node node) {
Node target = node;
//递归向左找
while(target.left != null) {
target = target.left;
}
//删除最小的节点
delete(target.value);
return target.value;
}
/**
* 搜索父节点
*
* @param value
* @return
*/
public Node searchParent(int value) {
if(root == null) {
return null;
}else {
return root.searchParent(value);
}
}
}
package binary;
public class TestBinarySortTree {
public static void main(String[] args) {
int[] arr = new int[] {7,3,10,12,5,1,9};
//创建一棵二叉树
BinarySortTree bst = new BinarySortTree();
//循环添加
for(int i:arr) {
bst.add(new Node(i));
}
//查看树中的值
bst.midShow();
//查找
// Node node = bst.search(10);
// System.out.println(node.value);
System.out.println("==============");
// Node node2 = bst.search(20);
// System.out.println(node2);
// Node p1 = bst.searchParent(10);
// System.out.println(p1.value);
// System.out.println("--------------");
// bst.delete(1);
// bst.midShow();
bst.delete(7);
System.out.println("--------");
bst.midShow();
}
}
由于普通的二叉查找树会容易失去“平衡”,极端情况下,二叉查找树会退化成线性的链表,导致插入和查找的复杂度下降到 O(n) ,所以,这也是平衡二叉树设计的初衷。那么平衡二叉树如何保持”平衡“呢?
根据定义,有两个重点,一是左右两子树的高度差的绝对值不能超过1,二是左右两子树也是一颗平衡二叉树。
public class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
/**
* 返回当前节点的高度
*
* @return
*/
public int height() {
return Math.max(left==null?0:left.height(), right==null?0:right.height()) +1;
}
/**
*
* 获取左子树的高度
*
* @return
*/
public int leftHeight() {
if(left == null) {
return 0;
}
return left.height();
}
/**
* 获取右子树的高度
*
*
* @return
*/
public int rightHeight() {
if(right == null) {
return 0;
}
return right.height();
}
/**
* 向子树中添加节点
*
* @param node
*/
public void add(Node node) {
if(node == null) {
return;
}
//判断传入的节点的只比当前子树的根节点的值是大还是小
//添加的节点比当前节点的值更小
if(node.value < this.value) {
//如果左节点为空
if(this.left == null) {
this.left = node;
//如果不为空
}else {
this.left.add(node);
}
}else {
if(this.right == null) {
this.right = node;
}else {
this.right.add(node);
}
}
//查询是否平衡
//进行右旋转
if(leftHeight()-rightHeight() >= 2) {
//双旋转
if(left!=null && left.leftHeight()value && this.left!=null) {
return this.left.searchParent(value);
}else if(this.value
public class BinarySortTree {
Node root;
/**
* 向二叉排序树中添加节点
*
* @param node
*/
public void add(Node node) {
//如果是一棵空树
if(root == null) {
root = node;
}else {
root.add(node);
}
}
/**
* 中序遍历二叉排序树,从小到大的顺序
*
*/
public void midShow() {
if(root != null) {
root.midShow(root);
}
}
/**
* 查找节点的方法
*
* @param value
* @return
*/
public Node search(int value) {
if(root == null) {
return null;
}else {
return root.search(value);
}
}
/**
* 删除节点
*
* @param value
* @return
*/
public void delete(int value) {
if(root == null) {
return;
}else {
//找到这个节点
Node target = search(value);
//如果没有这个节点
if(target == null) {
return;
}
//找到他的父节点
Node parent = searchParent(value);
//要删除的节点是叶子节点
if(target.left==null && target.right==null) {
//要删除的节点是父节点的左子节点
if(parent.left.value == value) {
parent.left = null;
//要删除的节点是父节点的右子节点
}else {
parent.right = null;
}
//要删除的节点有两个子节点的情况
}else if(target.left!=null && target.right!=null){
//删除右子树中值最小的节点,去获取到该节点的值
int min = deleteMin(target.right);
//替换目标节点中的值
target.value = min;
//要删除的节点有一个左子节点
}else {
//有左子节点
if(target.left != null) {
//要删除的节点是父节点的左子节点
if(parent.left.value == value) {
parent.left = target.left;
//要删除的节点是夫界定啊的右子节点
}else {
parent.right = target.left;
}
}
}
}
}
/**
* 删除一棵树中最小的节点
*
* @param right
* @return
*/
private int deleteMin(Node node) {
Node target = node;
//递归向左找
while(target.left != null) {
target = target.left;
}
//删除最小的节点
delete(target.value);
return target.value;
}
/**
* 搜索父节点
*
* @param value
* @return
*/
public Node searchParent(int value) {
if(root == null) {
return null;
}else {
return root.searchParent(value);
}
}
}
public static void main(String[] args) {
//int[] arr = new int[] {8,9,6,7,5,4};
//int[] arr = new int[] {2,1,4,3,5,6};
int[] arr = new int[] {8,9,5,4,6,7};
//创建一棵二叉树
BinarySortTree bst = new BinarySortTree();
//循环添加
for(int i:arr) {
bst.add(new Node(i));
}
//查看高度
System.out.println(bst.root.height());
//没旋转前是8,旋转之后是6,结果正确
System.out.println(bst.root.value);
}
}