1、树的概念
1.1、树的常用术语
1.2、二叉树
2、树的遍历
2.1、前中后序遍历代码实现
public class BinnaryTree {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢晋宇");
HeroNode node4 = new HeroNode(4, "灵宠");
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
binaryTree.setRoot(root);
System.out.println("前序遍历");
binaryTree.preOrder();
System.out.println("中序遍历");
binaryTree.infixOrder();
System.out.println("后序遍历");
binaryTree.suffixOrder();
}
}
//定义二叉树
class BinaryTree{
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder(){
if (this.root!=null){
root.preOrder();
}else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder(){
if (this.root!=null){
root.infixOrder();
}else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void suffixOrder(){
if (this.root!=null){
root.suffixOrder();
}else {
System.out.println("当前二叉树为空,无法遍历");
}
}
}
//创建HeroNode节点
class HeroNode {
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
private int no;
private String name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
private HeroNode left;
private HeroNode right;
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}//当输出是对象的时候,这个时候toString作用就很大了
//前序遍历
public void preOrder(){
System.out.println(this);//先输出父节点
if (this.left!=null){
this.left.preOrder();
}
if (this.right!=null){
this.right.preOrder();
}
}
//中序遍历
public void infixOrder(){
if (this.left!=null){
this.left.infixOrder();
}
System.out.println(this);//先输出父节点
if (this.right!=null){
this.right.infixOrder();
}
}
//后序遍历
public void suffixOrder(){
if (this.left!=null){
this.left.suffixOrder();
}
if (this.right!=null){
this.right.suffixOrder();
}
System.out.println(this);//先输出父节点
}
}
3、树的查找
3.1、思路分析
3.2、代码实现
package com.qingchengxiaoye.tree;
public class BinnaryTree {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢晋宇");
HeroNode node4 = new HeroNode(4, "灵宠");
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
binaryTree.setRoot(root);
System.out.println("前序遍历");
binaryTree.preOrder();
System.out.println("中序遍历");
binaryTree.infixOrder();
System.out.println("后序遍历");
binaryTree.suffixOrder();
System.out.println("前序查找");
HeroNode resultNode = binaryTree.preOrderSearch(4);
if (resultNode!=null){
System.out.printf("找到了,信息为no=%d name=%s",resultNode.getNo(),resultNode.getName());
}else {
System.out.printf("没有找到");
}
}
}
//定义二叉树
class BinaryTree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
public void preOrder() {
if (this.root != null) {
root.preOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder() {
if (this.root != null) {
root.infixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void suffixOrder() {
if (this.root != null) {
root.suffixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public HeroNode preOrderSearch(int no) {
if (root!=null){
HeroNode node = this.root.preOrderSearch(no);
return node;
}
return null;
}
public HeroNode infixOrderSearch(int no) {
if (root!=null){
HeroNode node = this.root.infixOrderSearch(no);
return node;
}
return null;
}
public HeroNode suffixOrderSearch(int no) {
if (root!=null){
HeroNode node = this.root.suffixOrderSearch(no);
return node;
}
return null;
}
}
//创建HeroNode节点
class HeroNode {
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
private int no;
private String name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
private HeroNode left;
private HeroNode right;
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}//当输出是对象的时候,这个时候toString作用就很大了
//前序遍历
public void preOrder() {
System.out.println(this);//先输出父节点
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);//先输出父节点
if (this.right != null) {
this.right.infixOrder();
}
}
//后序遍历
public void suffixOrder() {
if (this.left != null) {
this.left.suffixOrder();
}
if (this.right != null) {
this.right.suffixOrder();
}
System.out.println(this);//先输出父节点
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (this.no == no) {
return this;
}
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
public HeroNode infixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
public HeroNode suffixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
return resNode;
}
}
4、删除节点
4.1、思路分析
4.2、代码实现
package com.qingchengxiaoye.tree;
public class BinnaryTree {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢晋宇");
HeroNode node4 = new HeroNode(4, "灵宠");
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
binaryTree.setRoot(root);
System.out.println("前序遍历");
binaryTree.preOrder();
System.out.println("中序遍历");
binaryTree.infixOrder();
System.out.println("后序遍历");
binaryTree.suffixOrder();
System.out.println("前序查找");
HeroNode resultNode = binaryTree.preOrderSearch(4);
if (resultNode != null) {
System.out.printf("找到了,信息为no=%d name=%s", resultNode.getNo(), resultNode.getName());
} else {
System.out.printf("没有找到");
}
}
}
//定义二叉树
class BinaryTree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
//删除节点
public void delNode(int no){
if (root!=null){
if (root.getNo()==no){
root=null;
}else {
root.delNode(no);
}
}else {
System.out.println("这是空树,无法进行删除");
}
}
public void preOrder() {
if (this.root != null) {
root.preOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder() {
if (this.root != null) {
root.infixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void suffixOrder() {
if (this.root != null) {
root.suffixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public HeroNode preOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.preOrderSearch(no);
return node;
}
return null;
}
public HeroNode infixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.infixOrderSearch(no);
return node;
}
return null;
}
public HeroNode suffixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.suffixOrderSearch(no);
return node;
}
return null;
}
}
//创建HeroNode节点
class HeroNode {
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
private int no;
private String name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
private HeroNode left;
private HeroNode right;
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}//当输出是对象的时候,这个时候toString作用就很大了
//递归删除节点
public void delNode(int no) {
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
if (this.left!=null){
this.left.delNode(no);
}
if (this.right!=null){
this.right.delNode(no);
}
}
//前序遍历
public void preOrder() {
System.out.println(this);//先输出父节点
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);//先输出父节点
if (this.right != null) {
this.right.infixOrder();
}
}
//后序遍历
public void suffixOrder() {
if (this.left != null) {
this.left.suffixOrder();
}
if (this.right != null) {
this.right.suffixOrder();
}
System.out.println(this);//先输出父节点
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (this.no == no) {
return this;
}
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
public HeroNode infixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
public HeroNode suffixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
return resNode;
}
}
5、顺序存储二叉树
5.1、思路分析
5.2、代码实现
package com.qingchengxiaoye.tree;
public class ArrBinnaryTree {
public static void main(String[] args) {
int[] arr={1,2,3,4,5,6,7};
ArrTree arrTree = new ArrTree(arr);
arrTree.preOrder();
}
}
class ArrTree{
private int[] arr;
public ArrTree(int[] arr) {
this.arr = arr;
}
public void preOrder(){
this.preOrder(0);
}
public void preOrder(int index){
if (arr==null||arr.length==0){
System.out.println("数组为空,不能按照二叉树进行遍历");
return;
}
System.out.println(arr[index]);
if ((index*2+1)<arr.length){
preOrder(index*2+1);
}
if ((index*2+2)<arr.length){
preOrder(index*2+2);
}
}
}
6、线索化二叉树
6.1、思路分析
6.2、代码实现
package com.qingchengxiaoye.tree1;
public class ThreadedBinaryTreeDemo {
public static void main(String[] args) {
HeroNode root = new HeroNode(1, "1");
HeroNode node2 = new HeroNode(3, "3");
HeroNode node3 = new HeroNode(6, "6");
HeroNode node4 = new HeroNode(8, "8");
HeroNode node5 = new HeroNode(10, "10");
HeroNode node6 = new HeroNode(14, "14");
//先手动创建
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
threadedBinaryTree.setRoot(root);
threadedBinaryTree.threadedNodes();
System.out.println(node5.getLeft());
System.out.println(node5.getRight());
}
}
//定义二叉树
class ThreadedBinaryTree {
private HeroNode root;
//为了实现线索化,需要创建指向当前节点前驱节点的指针
//在进行递归的时候,pre总是保留前一个节点
private HeroNode pre = null;
public void setRoot(HeroNode root) {
this.root = root;
}
public void threadedNodes() {
this.threadedNodes(root);
}
//编写对二叉树进行中序线索化
public void threadedNodes(HeroNode node) {//node就是当前需要线索化的节点
if (node == null) {
return;
}
//先线索化左子树
threadedNodes(node.getLeft());
//再处理当前节点
if (node.getLeft() == null) {
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null) {
pre.setRight(node);
pre.setRightType(1);
}
//没处理一个节点后,让当前这个节点是下一个节点的前驱节点
pre =node;
//在处理右子树
threadedNodes(node.getRight());
}
//删除节点
public void delNode(int no) {
if (root != null) {
if (root.getNo() == no) {
root = null;
} else {
root.delNode(no);
}
} else {
System.out.println("这是空树,无法进行删除");
}
}
public void preOrder() {
if (this.root != null) {
root.preOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder() {
if (this.root != null) {
root.infixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void suffixOrder() {
if (this.root != null) {
root.suffixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public HeroNode preOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.preOrderSearch(no);
return node;
}
return null;
}
public HeroNode infixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.infixOrderSearch(no);
return node;
}
return null;
}
public HeroNode suffixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.suffixOrderSearch(no);
return node;
}
return null;
}
}
//创建HeroNode节点
class HeroNode {
private int leftType;//0表示指示的是左子树,1就是前驱节点
private int rightType;
public int getLeftType() {
return leftType;
}
public void setLeftType(int leftType) {
this.leftType = leftType;
}
public int getRightType() {
return rightType;
}
public void setRightType(int rightType) {
this.rightType = rightType;
}
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
private int no;
private String name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
private HeroNode left;
private HeroNode right;
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}//当输出是对象的时候,这个时候toString作用就很大了
//递归删除节点
public void delNode(int no) {
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
if (this.left != null) {
this.left.delNode(no);
}
if (this.right != null) {
this.right.delNode(no);
}
}
//前序遍历
public void preOrder() {
System.out.println(this);//先输出父节点
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);//先输出父节点
if (this.right != null) {
this.right.infixOrder();
}
}
//后序遍历
public void suffixOrder() {
if (this.left != null) {
this.left.suffixOrder();
}
if (this.right != null) {
this.right.suffixOrder();
}
System.out.println(this);//先输出父节点
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (this.no == no) {
return this;
}
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
public HeroNode infixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
public HeroNode suffixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
return resNode;
}
}
7、遍历线索化二叉树
7.1、思路分析
7.2、代码实现
package com.qingchengxiaoye.tree1;
public class ThreadedBinaryTreeDemo {
public static void main(String[] args) {
HeroNode root = new HeroNode(1, "1");
HeroNode node2 = new HeroNode(3, "3");
HeroNode node3 = new HeroNode(6, "6");
HeroNode node4 = new HeroNode(8, "8");
HeroNode node5 = new HeroNode(10, "10");
HeroNode node6 = new HeroNode(14, "14");
//先手动创建
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
threadedBinaryTree.setRoot(root);
threadedBinaryTree.threadedNodes();
System.out.println(node5.getLeft());
System.out.println(node5.getRight());
System.out.println("使用线索化方式遍历二叉树");
threadedBinaryTree.threadedList();
}
}
//定义二叉树
class ThreadedBinaryTree {
private HeroNode root;
//为了实现线索化,需要创建指向当前节点前驱节点的指针
//在进行递归的时候,pre总是保留前一个节点
private HeroNode pre = null;
public void setRoot(HeroNode root) {
this.root = root;
}
public void threadedNodes() {
this.threadedNodes(root);
}
//遍历线索化二叉树的方法
public void threadedList() {
HeroNode node = root;
while (node != null) {
while (node.getLeftType() == 0) {
node = node.getLeft();
}
System.out.println(node);
while (node.getRightType()==1){
node=node.getRight();
System.out.println(node);
}
node=node.getRight();
}
}
//编写对二叉树进行中序线索化
public void threadedNodes(HeroNode node) {//node就是当前需要线索化的节点
if (node == null) {
return;
}
//先线索化左子树
threadedNodes(node.getLeft());
//再处理当前节点
if (node.getLeft() == null) {
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null) {
pre.setRight(node);
pre.setRightType(1);
}
//没处理一个节点后,让当前这个节点是下一个节点的前驱节点
pre = node;
//在处理右子树
threadedNodes(node.getRight());
}
//删除节点
public void delNode(int no) {
if (root != null) {
if (root.getNo() == no) {
root = null;
} else {
root.delNode(no);
}
} else {
System.out.println("这是空树,无法进行删除");
}
}
public void preOrder() {
if (this.root != null) {
root.preOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder() {
if (this.root != null) {
root.infixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public void suffixOrder() {
if (this.root != null) {
root.suffixOrder();
} else {
System.out.println("当前二叉树为空,无法遍历");
}
}
public HeroNode preOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.preOrderSearch(no);
return node;
}
return null;
}
public HeroNode infixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.infixOrderSearch(no);
return node;
}
return null;
}
public HeroNode suffixOrderSearch(int no) {
if (root != null) {
HeroNode node = this.root.suffixOrderSearch(no);
return node;
}
return null;
}
}
//创建HeroNode节点
class HeroNode {
private int leftType;//0表示指示的是左子树,1就是前驱节点
private int rightType;
public int getLeftType() {
return leftType;
}
public void setLeftType(int leftType) {
this.leftType = leftType;
}
public int getRightType() {
return rightType;
}
public void setRightType(int rightType) {
this.rightType = rightType;
}
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
private int no;
private String name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
private HeroNode left;
private HeroNode right;
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}//当输出是对象的时候,这个时候toString作用就很大了
//递归删除节点
public void delNode(int no) {
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
if (this.left != null) {
this.left.delNode(no);
}
if (this.right != null) {
this.right.delNode(no);
}
}
//前序遍历
public void preOrder() {
System.out.println(this);//先输出父节点
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);//先输出父节点
if (this.right != null) {
this.right.infixOrder();
}
}
//后序遍历
public void suffixOrder() {
if (this.left != null) {
this.left.suffixOrder();
}
if (this.right != null) {
this.right.suffixOrder();
}
System.out.println(this);//先输出父节点
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (this.no == no) {
return this;
}
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
public HeroNode infixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
public HeroNode suffixOrderSearch(int no) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.suffixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
if (this.no == no) {
return this;
}
return resNode;
}
}
8、树结构实际应用
8.1、堆排序
8.1.1、实现思路
8.1.2、题目求解
从最后一个非叶子节点开始
8.1.2.1、解题思路
8.1.2.2、代码实现
package com.qingchengxiaoye.tree1;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr={4,6,8,5,9};
heapSort(arr);
}
//编写一个堆排序的方法
public static void heapSort(int[] arr){
int temp=0;
// adjustHeap(arr,1,arr.length);
// System.out.println(Arrays.toString(arr));
//
// adjustHeap(arr,0,arr.length);
// System.out.println(Arrays.toString(arr));
//根据升序降序,调整为大小堆
for (int i = arr.length/2-1; i >=0 ; i--) {
adjustHeap(arr,i,arr.length);
}
for (int j = arr.length-1; j >0 ; j--) {
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);
}
System.out.println(Arrays.toString(arr));
}
//将一个数组(二叉树),调整成为一个大顶堆
/**
*
* @param arr 待调整的数组 @param i 非叶子节点在数组中的索引
* @param length 表示对多少个元素进行调整 length是在逐渐减少
*/
public static void adjustHeap(int[] arr,int i,int length){
int temp=arr[i];
for (int k = i*2+1; k < length; k=k*2+1) {
if (k+1<length&&arr[k]<arr[k+1]){
k++;
}
if (arr[k]>temp){
arr[i]=arr[k];
i=k;
}else {
break;
}
}
arr[i]=temp;
}
}
9、哈夫曼树
9.1、基本介绍
9.2、题目求解
9.3、代码实现
package com.qingchengxiaoye.huffmanTree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = {13, 7, 8, 3, 29, 6, 1};
Node root = create(arr);
preOrder(root);
}
//便写一个前序遍历的方法
public static void preOrder(Node root){
if (root!=null){
root.preOrder();
}else {
System.out.println("为空树,不能遍历!");
}
}
//返回的就是赫夫曼树的根节点
public static Node create(int[] arr) {
/**
* 为了方便操作
* 1、遍历arr数组
* 2、将arr每个元素都构成一个 Node
* 3、将Node放入ArrayList中
*/
List<Node> nodes = new ArrayList<>();
for (int value : arr) {
nodes.add(new Node(value));
}
while (nodes.size() > 1) {
//排序,从小到大
Collections.sort(nodes);
//取出根节点最小的两颗二叉树
Node left = nodes.get(0);
Node right = nodes.get(1);
//构建一颗新的二叉树
Node parent = new Node(left.value + right.value);
parent.left = left;
parent.right = right;
//从arraylist中删除处理过的二叉树
nodes.remove(left);
nodes.remove(right);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建节点类
//为了让Node对象持续排序Collections集合排序
//让Node实现Comparable接口
class Node implements Comparable<Node> {
int value;//节点权值
Node left;
Node right;
//写一个前序遍历
public void preOrder(){
System.out.println(this);
if (this.left!=null){
this.left.preOrder();
}
if (this.right!=null){
this.right.preOrder();
}
}
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" + "value=" + value + '}';
}
@Override
public int compareTo(Node o) {
//表示从小到大进行排序
return this.value - o.value;
}
}
10、赫夫曼编码
10.1、基本介绍
10.1.1、实践操作
10.1.2、思路分析
10.1.3、代码实现
package com.qingchengxiaoye.huffumancode;
import java.util.*;
public class Code {
public static void main(String[] args) {
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
System.out.println(contentBytes.length);//40
List<Node> nodes = getNodes(contentBytes);
System.out.println(nodes);
System.out.println("赫夫曼树");
Node huffmanTreeRoot = create(nodes);
System.out.println("前序遍历");
huffmanTreeRoot.preOrder();
System.out.println("测试是否已经生成了对应的哈夫曼编码");
getCodes(huffmanTreeRoot);
System.out.println(huffmanCodes);
System.out.println("测试压缩后的byte");
byte[] zip = zip(contentBytes, huffmanCodes);
System.out.println(Arrays.toString(zip));
}
/**
* @param bytes 这是原始字符串对应的byte数组
* @param huffmanCodes 生成的哈夫曼编码表
* @return 返回哈夫曼处理后的
*/
//将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]
private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
//1、利用哈夫曼编码将byte转成哈夫曼编码对应的字符串
StringBuilder stringBuilder = new StringBuilder();
for (byte aByte : bytes) {
stringBuilder.append(huffmanCodes.get(aByte));
}
//将字符串转为byte数组
//统计返回byte[] huffmanCodesBytes的长度
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
//创建存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;//记录是第几个byte
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {//不够八位
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
//将strByte转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index++] = (byte) Integer.parseInt(strByte, 2);
}
return huffmanCodeBytes;
}
//生成赫夫曼树对应的编码表
//将赫夫曼编码存放到Map<Byte,String>形式
//32-》01
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//再生成赫夫曼编码表示,需要拼接路径,定义一个StringBuild,存储叶子节点的路径
static StringBuilder stringBuilder = new StringBuilder();
//为了方便,重载getCode
private static Map<Byte, String> getCodes(Node root) {
if (root == null) {
return null;
}
//处理左子树
getCodes(root.left, "0", stringBuilder);
getCodes(root.rigth, "1", stringBuilder);
return huffmanCodes;
}
/**
* 功能:将传入的node节点所有的叶子节点的赫夫曼编码得到,并放入到huffmanCodes中
*
* @param node 传入节点
* @param code 路径 左节点是0 右节点是1
* @param stringBuilder 用于拼接路径
*/
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
//将code加入到stringBuilder1
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {//非叶子节点
//向左递归
getCodes(node.left, "0", stringBuilder1);
//向右递归
getCodes(node.rigth, "1", stringBuilder1);
} else {//说明这是一个叶子节点
//就表示找到了叶子节点的最后
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
private static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("赫夫曼数为空");
}
}
/**
* @param bytes 接收字符数组
* @return
*/
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> counts = new HashMap<>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
//把每一个键值对转成一个Node对象,并加入到nodes集合
//遍历map
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
//通过list创建对应的赫夫曼树
public static Node create(List<Node> nodes) {
while (nodes.size() > 1) {
//从小到大排序
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,他的根节点没有data,只有权值
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.rigth = rightNode;
//将已经处理的
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建Node 带数据和权值
class Node implements Comparable<Node> {
//byte 字节 ,一字节等于八位
Byte data;//存放数据本身,比如‘a’ =》97 ''=>32
int weight;//权值,表示字符出现的次数
Node left;
Node rigth;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
//前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.rigth != null) {
this.rigth.preOrder();
}
}
}
10.1.4、封装操作
package com.qingchengxiaoye.huffumancode;
import java.util.*;
public class Code {
public static void main(String[] args) {
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
byte[] bytes = huffmanZip(contentBytes);
System.out.println("压缩后的结果是");
System.out.println(Arrays.toString(bytes));
System.out.println("长度是:==》"+bytes.length);
//分步过程
/*
List<Node> nodes = getNodes(contentBytes);
System.out.println(nodes);
System.out.println("赫夫曼树");
Node huffmanTreeRoot = create(nodes);
System.out.println("前序遍历");
huffmanTreeRoot.preOrder();
System.out.println("测试是否已经生成了对应的哈夫曼编码");
getCodes(huffmanTreeRoot);
System.out.println(huffmanCodes);
System.out.println("测试压缩后的byte");
byte[] zip = zip(contentBytes, huffmanCodes);
System.out.println(Arrays.toString(zip));*/
}
//使用一个方法,将前面的方法封装起来,便于我们调用
/**
*
* @param bytes 原始字符串对应的字节数组
* @return 是经过哈夫曼处理后的字节数组(压缩后的数组)
*/
private static byte[] huffmanZip(byte[] bytes){
List<Node> nodes = getNodes(bytes);
//创建赫夫曼树
Node huffmanTreeRoot = create(nodes);
//生成对应的赫夫曼编码表
getCodes(huffmanTreeRoot);
//根据生成的赫夫曼编码压缩,得到压缩后的赫夫曼编码字节数组
byte[] zip = zip(bytes, huffmanCodes);
return zip;
}
/**
* @param bytes 这是原始字符串对应的byte数组
* @param huffmanCodes 生成的哈夫曼编码表
* @return 返回哈夫曼处理后的
*/
//将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]
private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
//1、利用哈夫曼编码将byte转成哈夫曼编码对应的字符串
StringBuilder stringBuilder = new StringBuilder();
for (byte aByte : bytes) {
stringBuilder.append(huffmanCodes.get(aByte));
}
//将字符串转为byte数组
//统计返回byte[] huffmanCodesBytes的长度
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
//创建存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;//记录是第几个byte
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {//不够八位
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
//将strByte转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index++] = (byte) Integer.parseInt(strByte, 2);
}
return huffmanCodeBytes;
}
//生成赫夫曼树对应的编码表
//将赫夫曼编码存放到Map<Byte,String>形式
//32-》01
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//再生成赫夫曼编码表示,需要拼接路径,定义一个StringBuild,存储叶子节点的路径
static StringBuilder stringBuilder = new StringBuilder();
//为了方便,重载getCode
private static Map<Byte, String> getCodes(Node root) {
if (root == null) {
return null;
}
//处理左子树
getCodes(root.left, "0", stringBuilder);
getCodes(root.rigth, "1", stringBuilder);
return huffmanCodes;
}
/**
* 功能:将传入的node节点所有的叶子节点的赫夫曼编码得到,并放入到huffmanCodes中
*
* @param node 传入节点
* @param code 路径 左节点是0 右节点是1
* @param stringBuilder 用于拼接路径
*/
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
//将code加入到stringBuilder1
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {//非叶子节点
//向左递归
getCodes(node.left, "0", stringBuilder1);
//向右递归
getCodes(node.rigth, "1", stringBuilder1);
} else {//说明这是一个叶子节点
//就表示找到了叶子节点的最后
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
private static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("赫夫曼数为空");
}
}
/**
* @param bytes 接收字符数组
* @return
*/
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> counts = new HashMap<>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
//把每一个键值对转成一个Node对象,并加入到nodes集合
//遍历map
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
//通过list创建对应的赫夫曼树
public static Node create(List<Node> nodes) {
while (nodes.size() > 1) {
//从小到大排序
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,他的根节点没有data,只有权值
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.rigth = rightNode;
//将已经处理的
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建Node 带数据和权值
class Node implements Comparable<Node> {
//byte 字节 ,一字节等于八位
Byte data;//存放数据本身,比如‘a’ =》97 ''=>32
int weight;//权值,表示字符出现的次数
Node left;
Node rigth;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
//前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.rigth != null) {
this.rigth.preOrder();
}
}
}
10.2、数据解压
10.2.1、实现思路
10.2.1、代码实现
package com.qingchengxiaoye.huffumancode;
import java.util.*;
public class Code {
public static void main(String[] args) {
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
byte[] huffmanCodeBytes = huffmanZip(contentBytes);
System.out.println("压缩后的结果是");
System.out.println(Arrays.toString(huffmanCodeBytes));
System.out.println("长度是:==》" + huffmanCodeBytes.length);
//解码
byte[] sourceBytes = decode(huffmanCodes, huffmanCodeBytes);
System.out.println(new String(sourceBytes));
}
//编写一个方法。完成对压缩数据的解码
/**
* @param huffmanCodes 哈夫曼编码表
* @param huffmanBytes 赫夫曼编码得到的字节数组
* @return 原来字符串对应的数组
*/
private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
//1、先得到huffmanBytes对应的二进制字符串,形式10100101010.。。
StringBuilder stringBuilder = new StringBuilder();
//2、将byte数组转为二进制的字符串
for (int i = 0; i < huffmanBytes.length; i++) {
//判断是不是最后一个字节
boolean flag = i == huffmanBytes.length - 1;
stringBuilder.append(byteToBitString(!flag, huffmanBytes[i]));
}
//把字符串按照指定的赫夫曼编码进行解码
//把赫夫曼编码进行调换,因为反向查询a->100 100->a
Map<String, Byte> map = new HashMap<String, Byte>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
//创建一个集合,存放byte
List<Byte> list = new ArrayList<>();
//i可以理解为索引,扫描stringBuilder
for (int i = 0; i < stringBuilder.length(); ) {
int count = 1;//小的计数器
boolean flag = true;
Byte b = null;
while (flag) {
//递增取出key
String key = stringBuilder.substring(i, i + count);//i不动,让count移动,指定匹配一个字符
b = map.get(key);
if (b == null) {
count++;
} else {//匹配到了
flag = false;
}
}
list.add(b);
i += count;
}
//当for循环结束后,我们list中存放了所有的字符
//将list中的数据放入到byte[]
byte[] b = new byte[list.size()];
for (int i = 0; i < b.length; i++) {
b[i]=list.get(i);
}
return b;
}
/**
* 将一个byte转成一个二进制的字符串
*
* @param b 传入的byte
* @param flag flag表示是否需要补高位,如果是true就是需要 最后一个字节不需要不高为
* @return 是该b对应的二进制字符串
*/
private static String byteToBitString(boolean flag, byte b) {
//使用变量保存b
int temp = b;//将b转成int
//如果是正数,需要补高位
if (flag) {
temp |= 256;//按位与 1 0000 0000 |0000 0001 =》1 0000 0001
}
String str = Integer.toBinaryString(temp);
if (flag) {
return str.substring(str.length() - 8);
} else {
return str;
}
}
//使用一个方法,将前面的方法封装起来,便于我们调用
/**
* @param bytes 原始字符串对应的字节数组
* @return 是经过哈夫曼处理后的字节数组(压缩后的数组)
*/
private static byte[] huffmanZip(byte[] bytes) {
List<Node> nodes = getNodes(bytes);
//创建赫夫曼树
Node huffmanTreeRoot = create(nodes);
//生成对应的赫夫曼编码表
getCodes(huffmanTreeRoot);
//根据生成的赫夫曼编码压缩,得到压缩后的赫夫曼编码字节数组
byte[] zip = zip(bytes, huffmanCodes);
return zip;
}
/**
* @param bytes 这是原始字符串对应的byte数组
* @param huffmanCodes 生成的哈夫曼编码表
* @return 返回哈夫曼处理后的
*/
//将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]
private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
//1、利用哈夫曼编码将byte转成哈夫曼编码对应的字符串
StringBuilder stringBuilder = new StringBuilder();
for (byte aByte : bytes) {
stringBuilder.append(huffmanCodes.get(aByte));
}
//将字符串转为byte数组
//统计返回byte[] huffmanCodesBytes的长度
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
//创建存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;//记录是第几个byte
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {//不够八位
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
//将strByte转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index++] = (byte) Integer.parseInt(strByte, 2);
}
return huffmanCodeBytes;
}
//生成赫夫曼树对应的编码表
//将赫夫曼编码存放到Map<Byte,String>形式
//32-》01
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//再生成赫夫曼编码表示,需要拼接路径,定义一个StringBuild,存储叶子节点的路径
static StringBuilder stringBuilder = new StringBuilder();
//为了方便,重载getCode
private static Map<Byte, String> getCodes(Node root) {
if (root == null) {
return null;
}
//处理左子树
getCodes(root.left, "0", stringBuilder);
getCodes(root.rigth, "1", stringBuilder);
return huffmanCodes;
}
/**
* 功能:将传入的node节点所有的叶子节点的赫夫曼编码得到,并放入到huffmanCodes中
*
* @param node 传入节点
* @param code 路径 左节点是0 右节点是1
* @param stringBuilder 用于拼接路径
*/
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
//将code加入到stringBuilder1
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {//非叶子节点
//向左递归
getCodes(node.left, "0", stringBuilder1);
//向右递归
getCodes(node.rigth, "1", stringBuilder1);
} else {//说明这是一个叶子节点
//就表示找到了叶子节点的最后
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
private static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("赫夫曼数为空");
}
}
/**
* @param bytes 接收字符数组
* @return
*/
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> counts = new HashMap<>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
//把每一个键值对转成一个Node对象,并加入到nodes集合
//遍历map
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
//通过list创建对应的赫夫曼树
public static Node create(List<Node> nodes) {
while (nodes.size() > 1) {
//从小到大排序
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,他的根节点没有data,只有权值
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.rigth = rightNode;
//将已经处理的
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建Node 带数据和权值
class Node implements Comparable<Node> {
//byte 字节 ,一字节等于八位
Byte data;//存放数据本身,比如‘a’ =》97 ''=>32
int weight;//权值,表示字符出现的次数
Node left;
Node rigth;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
//前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.rigth != null) {
this.rigth.preOrder();
}
}
}
10.3、文件压缩
10.2.1、代码实现
package com.qingchengxiaoye.huffumancode;
import java.io.*;
import java.util.*;
public class Code {
public static void main(String[] args) {
//测试压缩文件的代码
String srcFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\压缩测试文件\\src.bmp";
String dstFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\dst.zip";
zipFile(srcFile,dstFile);
System.out.println("压缩文件成功");
/*
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
byte[] huffmanCodeBytes = huffmanZip(contentBytes);
System.out.println("压缩后的结果是");
System.out.println(Arrays.toString(huffmanCodeBytes));
System.out.println("长度是:==》" + huffmanCodeBytes.length);
//解码
byte[] sourceBytes = decode(huffmanCodes, huffmanCodeBytes);
System.out.println(new String(sourceBytes));
*/
}
//对文件进行压缩
/**
*
* @param srcFile 压缩文件全路径
* @param dstFile
*/
public static void zipFile(String srcFile,String dstFile){
//创建输出流
OutputStream os=null;
InputStream is=null;
ObjectOutputStream oos=null;
try {
//创建文件输入流
is = new FileInputStream(srcFile);
//创建一个和源文件大小一样的byte[]
byte[] b = new byte[is.available()];
//读取文件
is.read(b);
//直接对源文件进行压缩
byte[] huffmanBytes = huffmanZip(b);
//创建文件输出流,存放压缩文件
os = new FileOutputStream(dstFile);
//创建一个与文件输出流关联的ObjectOutputStream
oos = new ObjectOutputStream(os);
//把赫夫曼编码后的字节数组写入文件
oos.writeObject(huffmanBytes);
//这里我们以对象流的方式写入赫夫曼编码,是为了我们以后恢复文件使用
//把赫夫曼编码写入压缩文件
oos.writeObject(huffmanCodes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
oos.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//编写一个方法。完成对压缩数据的解码
/**
* @param huffmanCodes 哈夫曼编码表
* @param huffmanBytes 赫夫曼编码得到的字节数组
* @return 原来字符串对应的数组
*/
private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
//1、先得到huffmanBytes对应的二进制字符串,形式10100101010.。。
StringBuilder stringBuilder = new StringBuilder();
//2、将byte数组转为二进制的字符串
for (int i = 0; i < huffmanBytes.length; i++) {
//判断是不是最后一个字节
boolean flag = i == huffmanBytes.length - 1;
stringBuilder.append(byteToBitString(!flag, huffmanBytes[i]));
}
//把字符串按照指定的赫夫曼编码进行解码
//把赫夫曼编码进行调换,因为反向查询a->100 100->a
Map<String, Byte> map = new HashMap<String, Byte>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
//创建一个集合,存放byte
List<Byte> list = new ArrayList<>();
//i可以理解为索引,扫描stringBuilder
for (int i = 0; i < stringBuilder.length(); ) {
int count = 1;//小的计数器
boolean flag = true;
Byte b = null;
while (flag) {
//递增取出key
String key = stringBuilder.substring(i, i + count);//i不动,让count移动,指定匹配一个字符
b = map.get(key);
if (b == null) {
count++;
} else {//匹配到了
flag = false;
}
}
list.add(b);
i += count;
}
//当for循环结束后,我们list中存放了所有的字符
//将list中的数据放入到byte[]
byte[] b = new byte[list.size()];
for (int i = 0; i < b.length; i++) {
b[i]=list.get(i);
}
return b;
}
/**
* 将一个byte转成一个二进制的字符串
*
* @param b 传入的byte
* @param flag flag表示是否需要补高位,如果是true就是需要 最后一个字节不需要不高为
* @return 是该b对应的二进制字符串
*/
private static String byteToBitString(boolean flag, byte b) {
//使用变量保存b
int temp = b;//将b转成int
//如果是正数,需要补高位
if (flag) {
temp |= 256;//按位与 1 0000 0000 |0000 0001 =》1 0000 0001
}
String str = Integer.toBinaryString(temp);
if (flag) {
return str.substring(str.length() - 8);
} else {
return str;
}
}
//使用一个方法,将前面的方法封装起来,便于我们调用
/**
* @param bytes 原始字符串对应的字节数组
* @return 是经过哈夫曼处理后的字节数组(压缩后的数组)
*/
private static byte[] huffmanZip(byte[] bytes) {
List<Node> nodes = getNodes(bytes);
//创建赫夫曼树
Node huffmanTreeRoot = create(nodes);
//生成对应的赫夫曼编码表
getCodes(huffmanTreeRoot);
//根据生成的赫夫曼编码压缩,得到压缩后的赫夫曼编码字节数组
byte[] zip = zip(bytes, huffmanCodes);
return zip;
}
/**
* @param bytes 这是原始字符串对应的byte数组
* @param huffmanCodes 生成的哈夫曼编码表
* @return 返回哈夫曼处理后的
*/
//将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]
private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
//1、利用哈夫曼编码将byte转成哈夫曼编码对应的字符串
StringBuilder stringBuilder = new StringBuilder();
for (byte aByte : bytes) {
stringBuilder.append(huffmanCodes.get(aByte));
}
//将字符串转为byte数组
//统计返回byte[] huffmanCodesBytes的长度
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
//创建存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;//记录是第几个byte
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {//不够八位
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
//将strByte转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index++] = (byte) Integer.parseInt(strByte, 2);
}
return huffmanCodeBytes;
}
//生成赫夫曼树对应的编码表
//将赫夫曼编码存放到Map<Byte,String>形式
//32-》01
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//再生成赫夫曼编码表示,需要拼接路径,定义一个StringBuild,存储叶子节点的路径
static StringBuilder stringBuilder = new StringBuilder();
//为了方便,重载getCode
private static Map<Byte, String> getCodes(Node root) {
if (root == null) {
return null;
}
//处理左子树
getCodes(root.left, "0", stringBuilder);
getCodes(root.rigth, "1", stringBuilder);
return huffmanCodes;
}
/**
* 功能:将传入的node节点所有的叶子节点的赫夫曼编码得到,并放入到huffmanCodes中
*
* @param node 传入节点
* @param code 路径 左节点是0 右节点是1
* @param stringBuilder 用于拼接路径
*/
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
//将code加入到stringBuilder1
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {//非叶子节点
//向左递归
getCodes(node.left, "0", stringBuilder1);
//向右递归
getCodes(node.rigth, "1", stringBuilder1);
} else {//说明这是一个叶子节点
//就表示找到了叶子节点的最后
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
private static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("赫夫曼数为空");
}
}
/**
* @param bytes 接收字符数组
* @return
*/
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> counts = new HashMap<>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
//把每一个键值对转成一个Node对象,并加入到nodes集合
//遍历map
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
//通过list创建对应的赫夫曼树
public static Node create(List<Node> nodes) {
while (nodes.size() > 1) {
//从小到大排序
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,他的根节点没有data,只有权值
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.rigth = rightNode;
//将已经处理的
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建Node 带数据和权值
class Node implements Comparable<Node> {
//byte 字节 ,一字节等于八位
Byte data;//存放数据本身,比如‘a’ =》97 ''=>32
int weight;//权值,表示字符出现的次数
Node left;
Node rigth;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
//前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.rigth != null) {
this.rigth.preOrder();
}
}
}
10.4、文件解压
10.4.1、代码实现
package com.qingchengxiaoye.huffumancode;
import java.io.*;
import java.util.*;
public class Code {
public static void main(String[] args) {
//测试压缩文件的代码
// String srcFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\压缩测试文件\\src.bmp";
// String dstFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\dst.zip";
// zipFile(srcFile,dstFile);
// System.out.println("压缩文件成功");
//测试解压
String zipFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\dst.zip";
String dstFile="E:\\资料\\图解Java数据结构和算法-尚硅谷-韩顺平\\资料\\src.bmp";
unZipFile(zipFile,dstFile);
System.out.println("解压成功");
/*
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
byte[] huffmanCodeBytes = huffmanZip(contentBytes);
System.out.println("压缩后的结果是");
System.out.println(Arrays.toString(huffmanCodeBytes));
System.out.println("长度是:==》" + huffmanCodeBytes.length);
//解码
byte[] sourceBytes = decode(huffmanCodes, huffmanCodeBytes);
System.out.println(new String(sourceBytes));
*/
}
//对文件解压
public static void unZipFile(String zipFile,String dstFile){
//定义文件输入流
InputStream is=null;
//定义一个对象输入流
ObjectInputStream ois=null;
//定义文件输出流
OutputStream os=null;
try {
//创建文件输入流
is=new FileInputStream(zipFile);
//创建一个和is关联的对象输入流
ois=new ObjectInputStream(is);
//读取byte数组 huffmanBytes
byte[] huffmanBytes = (byte[]) ois.readObject();
//读取赫夫曼编码表
Map<Byte,String> huffmanCodes= (Map<Byte, String>) ois.readObject();
//解码
byte[] bytes = decode(huffmanCodes, huffmanBytes);
//将bytes写入到目标问价
os = new FileOutputStream(dstFile);
//写数据到文件中
os.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
ois.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//对文件进行压缩
/**
*
* @param srcFile 压缩文件全路径
* @param dstFile
*/
public static void zipFile(String srcFile,String dstFile){
//创建输出流
OutputStream os=null;
InputStream is=null;
ObjectOutputStream oos=null;
try {
//创建文件输入流
is = new FileInputStream(srcFile);
//创建一个和源文件大小一样的byte[]
byte[] b = new byte[is.available()];
//读取文件
is.read(b);
//直接对源文件进行压缩
byte[] huffmanBytes = huffmanZip(b);
//创建文件输出流,存放压缩文件
os = new FileOutputStream(dstFile);
//创建一个与文件输出流关联的ObjectOutputStream
oos = new ObjectOutputStream(os);
//把赫夫曼编码后的字节数组写入文件
oos.writeObject(huffmanBytes);
//这里我们以对象流的方式写入赫夫曼编码,是为了我们以后恢复文件使用
//把赫夫曼编码写入压缩文件
oos.writeObject(huffmanCodes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
oos.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//编写一个方法。完成对压缩数据的解码
/**
* @param huffmanCodes 哈夫曼编码表
* @param huffmanBytes 赫夫曼编码得到的字节数组
* @return 原来字符串对应的数组
*/
private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
//1、先得到huffmanBytes对应的二进制字符串,形式10100101010.。。
StringBuilder stringBuilder = new StringBuilder();
//2、将byte数组转为二进制的字符串
for (int i = 0; i < huffmanBytes.length; i++) {
//判断是不是最后一个字节
boolean flag = i == huffmanBytes.length - 1;
stringBuilder.append(byteToBitString(!flag, huffmanBytes[i]));
}
//把字符串按照指定的赫夫曼编码进行解码
//把赫夫曼编码进行调换,因为反向查询a->100 100->a
Map<String, Byte> map = new HashMap<String, Byte>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
//创建一个集合,存放byte
List<Byte> list = new ArrayList<>();
//i可以理解为索引,扫描stringBuilder
for (int i = 0; i < stringBuilder.length(); ) {
int count = 1;//小的计数器
boolean flag = true;
Byte b = null;
while (flag) {
//递增取出key
String key = stringBuilder.substring(i, i + count);//i不动,让count移动,指定匹配一个字符
b = map.get(key);
if (b == null) {
count++;
} else {//匹配到了
flag = false;
}
}
list.add(b);
i += count;
}
//当for循环结束后,我们list中存放了所有的字符
//将list中的数据放入到byte[]
byte[] b = new byte[list.size()];
for (int i = 0; i < b.length; i++) {
b[i]=list.get(i);
}
return b;
}
/**
* 将一个byte转成一个二进制的字符串
*
* @param b 传入的byte
* @param flag flag表示是否需要补高位,如果是true就是需要 最后一个字节不需要不高为
* @return 是该b对应的二进制字符串
*/
private static String byteToBitString(boolean flag, byte b) {
//使用变量保存b
int temp = b;//将b转成int
//如果是正数,需要补高位
if (flag) {
temp |= 256;//按位与 1 0000 0000 |0000 0001 =》1 0000 0001
}
String str = Integer.toBinaryString(temp);
if (flag) {
return str.substring(str.length() - 8);
} else {
return str;
}
}
//使用一个方法,将前面的方法封装起来,便于我们调用
/**
* @param bytes 原始字符串对应的字节数组
* @return 是经过哈夫曼处理后的字节数组(压缩后的数组)
*/
private static byte[] huffmanZip(byte[] bytes) {
List<Node> nodes = getNodes(bytes);
//创建赫夫曼树
Node huffmanTreeRoot = create(nodes);
//生成对应的赫夫曼编码表
getCodes(huffmanTreeRoot);
//根据生成的赫夫曼编码压缩,得到压缩后的赫夫曼编码字节数组
byte[] zip = zip(bytes, huffmanCodes);
return zip;
}
/**
* @param bytes 这是原始字符串对应的byte数组
* @param huffmanCodes 生成的哈夫曼编码表
* @return 返回哈夫曼处理后的
*/
//将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]
private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
//1、利用哈夫曼编码将byte转成哈夫曼编码对应的字符串
StringBuilder stringBuilder = new StringBuilder();
for (byte aByte : bytes) {
stringBuilder.append(huffmanCodes.get(aByte));
}
//将字符串转为byte数组
//统计返回byte[] huffmanCodesBytes的长度
int len;
if (stringBuilder.length() % 8 == 0) {
len = stringBuilder.length() / 8;
} else {
len = stringBuilder.length() / 8 + 1;
}
//创建存储压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;//记录是第几个byte
for (int i = 0; i < stringBuilder.length(); i += 8) {
String strByte;
if (i + 8 > stringBuilder.length()) {//不够八位
strByte = stringBuilder.substring(i);
} else {
strByte = stringBuilder.substring(i, i + 8);
}
//将strByte转成byte,放入到huffmanCodeBytes
huffmanCodeBytes[index++] = (byte) Integer.parseInt(strByte, 2);
}
return huffmanCodeBytes;
}
//生成赫夫曼树对应的编码表
//将赫夫曼编码存放到Map<Byte,String>形式
//32-》01
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//再生成赫夫曼编码表示,需要拼接路径,定义一个StringBuild,存储叶子节点的路径
static StringBuilder stringBuilder = new StringBuilder();
//为了方便,重载getCode
private static Map<Byte, String> getCodes(Node root) {
if (root == null) {
return null;
}
//处理左子树
getCodes(root.left, "0", stringBuilder);
getCodes(root.rigth, "1", stringBuilder);
return huffmanCodes;
}
/**
* 功能:将传入的node节点所有的叶子节点的赫夫曼编码得到,并放入到huffmanCodes中
*
* @param node 传入节点
* @param code 路径 左节点是0 右节点是1
* @param stringBuilder 用于拼接路径
*/
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
//将code加入到stringBuilder1
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {//非叶子节点
//向左递归
getCodes(node.left, "0", stringBuilder1);
//向右递归
getCodes(node.rigth, "1", stringBuilder1);
} else {//说明这是一个叶子节点
//就表示找到了叶子节点的最后
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
private static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("赫夫曼数为空");
}
}
/**
* @param bytes 接收字符数组
* @return
*/
private static List<Node> getNodes(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
HashMap<Byte, Integer> counts = new HashMap<>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
//把每一个键值对转成一个Node对象,并加入到nodes集合
//遍历map
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
//通过list创建对应的赫夫曼树
public static Node create(List<Node> nodes) {
while (nodes.size() > 1) {
//从小到大排序
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,他的根节点没有data,只有权值
Node parent = new Node(null, leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.rigth = rightNode;
//将已经处理的
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建Node 带数据和权值
class Node implements Comparable<Node> {
//byte 字节 ,一字节等于八位
Byte data;//存放数据本身,比如‘a’ =》97 ''=>32
int weight;//权值,表示字符出现的次数
Node left;
Node rigth;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
//前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.rigth != null) {
this.rigth.preOrder();
}
}
}
10.5、注意事项
11、二叉排序树
11.1、需求分析
11.2、介绍
11.3、代码实现
package com.qingchengxiaoye.binarysorttree;
import com.qingchengxiaoye.tree.BinnaryTree;
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr={7,3,10,12,5,1,9};
BinarySortTree binarySortTree = new BinarySortTree();
for (int i : arr) {
binarySortTree.add(new Node(i));
}
binarySortTree.infixOrder();
}
}
//创建二叉排序树
class BinarySortTree{
private Node root;
//添加节点的方法
public void add(Node node){
if (root==null){
root=node;
}else {
root.add(node);
}
}
//遍历方法,中序遍历
public void infixOrder(){
if (root!=null){
root.infixOrder();
}else {
System.out.println("二叉排序树为空,不能遍历");
}
}
}
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//添加节点的方法
//递归的形式添加节点,
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);
}
}
}
//中序遍历
public void infixOrder(){
if (this.left!=null){
this.left.infixOrder();
}
System.out.println(this);
if (this.right!=null){
this.right.infixOrder();
}
}
}
11.4、二叉树的删除
11.5代码实现
package com.qingchengxiaoye.binarysorttree;
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
BinarySortTree binarySortTree = new BinarySortTree();
for (int i : arr) {
binarySortTree.add(new Node(i));
}
System.out.println("中序遍历二叉排序树·");
binarySortTree.infixOrder();
//测试一下删除叶子节点
binarySortTree.delNode(10);
System.out.println("删除叶子节点后");
binarySortTree.infixOrder();
}
}
//创建二叉排序树
class BinarySortTree {
private Node root;
/**
* @param node 传入的节点,(当作二叉排序树的根节点)
* @return 返回以node节点为根节点的二叉树的 最小节点的值
* 还要删除这个值
*/
public int delRightTreeMin(Node node) {
Node target = node;
//循环查找左节点,就会找到最小值
while (target.left != null) {
target = target.left;
}
//这是target指向最小的值
delNode(target.value);
return target.value;
}
//删除节点
public void delNode(int value) {
if (root == null) {
return;
} else {
Node targetNode = search(value);
//如果没有找到要删除的的节点
if (targetNode == null) {
return;
}
//如果发现当前这颗二叉排序树只有一个节点
if (root.left == null && root.right == null) {
root = null;
return;
}
//去找到targetNode的父节点
Node parent = searchParent(value);
//如果要删除的节点是叶子节点
if (targetNode.left == null && targetNode.right == null) {
//判断targetNode是父节点的左子节点还是右子节点
if (parent.left != null && parent.left.value == value) {//是左子节点
parent.left = null;
} else if (parent.right != null && parent.right.value == value) {//是右子节点
parent.right = null;
}
} else if (targetNode.left != null && targetNode.right != null) {
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
} else {//删除只有一棵子树的节点
//如果要删除的节点有左子节点
if (targetNode.left != null) {
if (parent != null) {
//如果targetNode是parent的左节点
if (parent.left.value == value) {
parent.left = targetNode.left;
} else {//如果targetNode是parent的右节点
parent.right = targetNode.left;
}
} else {
root = targetNode.left;
}
} else {//如果要删除的节点有右子节点
if (parent != null) {
//如果targetNode是parent的左节点
if (parent.left.value == value) {
parent.left = targetNode.right;
} else {//如果targetNode是parent的右节点
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
}
}
}
//查找父节点
public Node searchParent(int value) {
if (root == null) {
return null;
} else {
return root.searchParent(value);
}
}
//查找要删除的节点
public Node search(int value) {
if (root == null) {
return null;
} else {
return root.search(value);
}
}
//添加节点的方法
public void add(Node node) {
if (root == null) {
root = node;
} else {
root.add(node);
}
}
//遍历方法,中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("二叉排序树为空,不能遍历");
}
}
}
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
//查找要删除的节点
public Node search(int value) {
if (this.value == value) {
return this;
} else if (value < this.value) {
if (this.left == null) {
return null;
}
return this.left.search(value);
} else {
if (this.right == null) {
return null;
}
return this.right.search(value);
}
}
//查找要删除节点的父节点
/**
* @param value
* @return 返回的是要删除父节点的值,如果没有就返回null
*/
public Node searchParent(int value) {
//如果当前节点就是要删除节点的父节点,就返回
if ((this.left != null && this.left.value == value) ||
(this.right != null && this.right.value == value)) {
return this;
} else {
//如果当前要查找的值小于当前节点,并且当前节点的左子节点不为空
if (value < this.value && this.left != null) {
return this.left.searchParent(value);//向左子树递归查找
} else if (value >= this.value && this.right != null) {
return this.right.searchParent(value);//向右子树
} else {
return null;//没有找到父节点
}
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//添加节点的方法
//递归的形式添加节点,
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);
}
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
}
12、平衡二叉树
12.1、介绍
12.2、案例分析
12.2.1、左旋转
12.2.2、右旋转
12.2.3、双旋转
12.3、代码实现
package com.qingchengxiaoye.avl;
public class AVLTreeDemo {
public static void main(String[] args) {
// int[] arr = {4, 3, 6, 5, 7, 8};
// int[] arr = {10, 12, 8, 9, 7, 6};
int [] arr={10,11,7,6,8,9};
//创建一个AVl树
AVLTree avlTree = new AVLTree();
for (int i : arr) {
avlTree.add(new Node(i));
}
//遍历
System.out.println("中序遍历");
avlTree.infixOrder();
System.out.println("在没有平衡处理前");
System.out.println("树的高度=" + avlTree.getRoot().height());
System.out.println("树的左子树高度=" + avlTree.getRoot().leftHeight());
System.out.println("树的右子树高度=" + avlTree.getRoot().rightHeight());
System.out.println("当前根节点="+avlTree.getRoot());
}
}
//创建AVLTree
class AVLTree {
private Node root;
public Node getRoot() {
return root;
}
/**
* @param node 传入的节点,(当作二叉排序树的根节点)
* @return 返回以node节点为根节点的二叉树的 最小节点的值
* 还要删除这个值
*/
public int delRightTreeMin(Node node) {
Node target = node;
//循环查找左节点,就会找到最小值
while (target.left != null) {
target = target.left;
}
//这是target指向最小的值
delNode(target.value);
return target.value;
}
//删除节点
public void delNode(int value) {
if (root == null) {
return;
} else {
Node targetNode = search(value);
//如果没有找到要删除的的节点
if (targetNode == null) {
return;
}
//如果发现当前这颗二叉排序树只有一个节点
if (root.left == null && root.right == null) {
root = null;
return;
}
//去找到targetNode的父节点
Node parent = searchParent(value);
//如果要删除的节点是叶子节点
if (targetNode.left == null && targetNode.right == null) {
//判断targetNode是父节点的左子节点还是右子节点
if (parent.left != null && parent.left.value == value) {//是左子节点
parent.left = null;
} else if (parent.right != null && parent.right.value == value) {//是右子节点
parent.right = null;
}
} else if (targetNode.left != null && targetNode.right != null) {
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
} else {//删除只有一棵子树的节点
//如果要删除的节点有左子节点
if (targetNode.left != null) {
if (parent != null) {
//如果targetNode是parent的左节点
if (parent.left.value == value) {
parent.left = targetNode.left;
} else {//如果targetNode是parent的右节点
parent.right = targetNode.left;
}
} else {
root = targetNode.left;
}
} else {//如果要删除的节点有右子节点
if (parent != null) {
//如果targetNode是parent的左节点
if (parent.left.value == value) {
parent.left = targetNode.right;
} else {//如果targetNode是parent的右节点
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
}
}
}
//查找父节点
public Node searchParent(int value) {
if (root == null) {
return null;
} else {
return root.searchParent(value);
}
}
//查找要删除的节点
public Node search(int value) {
if (root == null) {
return null;
} else {
return root.search(value);
}
}
//添加节点的方法
public void add(Node node) {
if (root == null) {
root = node;
} else {
root.add(node);
}
}
//遍历方法,中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("二叉排序树为空,不能遍历");
}
}
}
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
//右旋转
private void rightRotate() {
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
//左旋转的方法
private void leftRotate() {
//创建新的节点,以以前根节点的值
Node newNode = new Node(value);
//把新的节点的左子树设置为当前节点的左子树
newNode.left = left;
//把新的节点的右子树设置为当前节点的右子树的左子树
newNode.right = right.left;
//把当前节点的值替换成右子节点的值
value = right.value;
//把当前节点的右子树设置成当前节点右子树的右子树
right = right.right;
//把当前节点的左子树设置成新的节点
left = newNode;
}
//返回左子树的高度
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
//返回右子树的高度
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
//返回以该节点为根节点的高度
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
//查找要删除的节点
Node search(int value) {
if (this.value == value) {
return this;
} else if (value < this.value) {
if (this.left == null) {
return null;
}
return this.left.search(value);
} else {
if (this.right == null) {
return null;
}
return this.right.search(value);
}
}
//查找要删除节点的父节点
/**
* @param value
* @return 返回的是要删除父节点的值,如果没有就返回null
*/
Node searchParent(int value) {
//如果当前节点就是要删除节点的父节点,就返回
if ((this.left != null && this.left.value == value) ||
(this.right != null && this.right.value == value)) {
return this;
} else {
//如果当前要查找的值小于当前节点,并且当前节点的左子节点不为空
if (value < this.value && this.left != null) {
return this.left.searchParent(value);//向左子树递归查找
} else if (value >= this.value && this.right != null) {
return this.right.searchParent(value);//向右子树
} else {
return null;//没有找到父节点
}
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//添加节点的方法
//递归的形式添加节点,
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);
}
}
//当添加一个节点后,如果:(右子树高度-左子树的高度)>1 ,左旋转
if (rightHeight() - leftHeight() > 1) {
if (right!=null&&right.leftHeight()>right.rightHeight()){
//先对当前节点的右子树进行左旋转
left.leftRotate();
}
leftRotate();
return;
}
//当添加一个节点后,如果:(左子树高度-右子树的高度)>1 ,右旋转
if (leftHeight() - rightHeight() > 1) {
//如果左子树的右子树高度大于他的左子树的高度
if (left!=null&&left.rightHeight()>left.leftHeight()){
//先对当前节点的左子树进行左旋转
left.leftRotate();
}
//针对当前节点进行旋转
rightRotate();
return;
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
}
13、多路查找树
13.1、问题分析
left = newNode;
}
//返回左子树的高度
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
//返回右子树的高度
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
//返回以该节点为根节点的高度
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
//查找要删除的节点
Node search(int value) {
if (this.value == value) {
return this;
} else if (value < this.value) {
if (this.left == null) {
return null;
}
return this.left.search(value);
} else {
if (this.right == null) {
return null;
}
return this.right.search(value);
}
}
//查找要删除节点的父节点
/**
* @param value
* @return 返回的是要删除父节点的值,如果没有就返回null
*/
Node searchParent(int value) {
//如果当前节点就是要删除节点的父节点,就返回
if ((this.left != null && this.left.value == value) ||
(this.right != null && this.right.value == value)) {
return this;
} else {
//如果当前要查找的值小于当前节点,并且当前节点的左子节点不为空
if (value < this.value && this.left != null) {
return this.left.searchParent(value);//向左子树递归查找
} else if (value >= this.value && this.right != null) {
return this.right.searchParent(value);//向右子树
} else {
return null;//没有找到父节点
}
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//添加节点的方法
//递归的形式添加节点,
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);
}
}
//当添加一个节点后,如果:(右子树高度-左子树的高度)>1 ,左旋转
if (rightHeight() - leftHeight() > 1) {
if (right!=null&&right.leftHeight()>right.rightHeight()){
//先对当前节点的右子树进行左旋转
left.leftRotate();
}
leftRotate();
return;
}
//当添加一个节点后,如果:(左子树高度-右子树的高度)>1 ,右旋转
if (leftHeight() - rightHeight() > 1) {
//如果左子树的右子树高度大于他的左子树的高度
if (left!=null&&left.rightHeight()>left.leftHeight()){
//先对当前节点的左子树进行左旋转
left.leftRotate();
}
//针对当前节点进行旋转
rightRotate();
return;
}
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
}