数组扩容分析:
撤入删除效率低
ArrayList底层存储(就是数组扩容)分析:
链式存储分析:
插入,删除效率较高。但检索时需要从头遍历,效率很低。
树存储分析:
树插入,删除,检索效率都很高。
树示意图:
二叉树概念:
前序遍历:先输出父节点,再遍历左子树和右子树
中序遍历:先遍历左子树,再输出父节点,最后遍历右子树
后序遍历:先遍历左子树,再遍历右子树,最后输出父节点
**小结:**看输出父节点的顺序,就确定是前序,中序,还是后序。
package calculate;
public class BinaryTree {
//二叉树
public static void main(String[] args) {
//创建二叉树
BinaryT binaryt = new BinaryT();
//创建需要的节点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "卢俊义");
HeroNode node3 = new HeroNode(3, "吴用");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//先手动创建二叉树,以后递归创建
//root.left = node2; //不能这么写,因为left为私有
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
binaryt.setRoot(root);
System.out.println("前序遍历");
binaryt.preOrder();
System.out.println();
System.out.println("中序遍历");
binaryt.infixOrder();
System.out.println();
System.out.println("后序遍历");
binaryt.postOrder();
System.out.println();
//前序查找(四次)
//中序查找(三次)
//后序查找(两次)
System.out.println("前序查找");
HeroNode resNode = binaryt.preOrderSearch(5);
if (resNode != null) {
System.out.println(resNode.getName());
}else {
System.out.println("没有找到");
}
//删除节点
System.out.println("删除前");
binaryt.preOrder(); //1,2,3,5,4
binaryt.delNode(5);
System.out.println();
System.out.println("删除后");
binaryt.preOrder(); //1,2,3,4
}
}
//定义一个二叉树
class BinaryT{
private HeroNode root; //根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void preOrder() {
if (this.root != null) {
this.root.preOrder(); //调用的HeroNode中的方法
}else {
System.out.println("二叉树为空");
}
}
//中序遍历
public void infixOrder() {
if (this.root != null) {
this.root.infixOrder();
}else {
System.out.println("二叉树为空");
}
}
//后序遍历
public void postOrder() {
if (this.root != null) {
this.root.postOrder();
}else {
System.out.println("二叉树为空");
}
}
//前序查找
public HeroNode preOrderSearch(int no) {
if (root != null) {
return root.preOrderSearch(no);
}else {
return null;
}
}
//前序查找
public HeroNode infixOrderSearch(int no) {
if (root != null) {
return root.infixOrderSearch(no);
}else {
return null;
}
}
//后序查找
public HeroNode postOrderSearch(int no) {
if (root != null) {
return root.postOrderSearch(no);
}else {
return null;
}
}
//删除节点
public void delNode(int no) {
if (root != null) {
if(root.getNo() == no) { //判断root是否是待删除节点
root = null;
}else {
root.delNode(no); //否则递归删除
}
}else {
System.out.println("空树");
}
}
}
//先创建节点HeroNode
class HeroNode{
private int no;
private String name;
private HeroNode left; //默认为空
private HeroNode right;//默认为空
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + ", left=" + left + ", right=" + right + ", toString()="
+ super.toString() + "]";
}
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;
}
public HeroNode(int no, String name) {
super();
this.no = no;
this.name = name;
}
//编写前序遍历方法
public void preOrder() {
System.out.print(this.no); //输出当前节点父节点
//递归左子树
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.print(this.no); //输出当前节点父节点
//递归右子树
if (this.right != null) {
this.right.infixOrder();
}
}
//编写后序遍历方法
public void postOrder() {
//递归左子树
if (this.left != null) {
this.left.postOrder();
}
//递归右子树
if (this.right != null) {
this.right.postOrder();
}
System.out.print(this.no); //输出当前节点父节点
}
//前序查找
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; //找没找到都返回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; //找没找到都返回resNode,找不到为空
}
//后序查找
public HeroNode postOrderSearch(int no) {
//比较当前节点的左子节点是否为空,如果不为空递归前序查找
// 找到节点就返回
HeroNode resNode = null; // 接收找到的节点
if (this.left != null) {
resNode = this.left.infixOrderSearch(no); // 向左递归
}
if (resNode != null) { // 左子树找到了,没找到继续判断
return resNode;
}
if (this.right != null) {
resNode = this.right.infixOrderSearch(no); //向右递归
}
if (resNode != null) { //右子树找到了就返回,没找到继续判断
return resNode;
}
//左右都没有找到
if (this.no == no) {
return this;
}
return resNode;
}
//递归删除节点
//1.如果删除的是叶子节点就删除节点
//2.如果删除的非叶子节点,则删除子树
public void delNode(int no) { //判断当前节点的子节点是否是待删除节点
//1.如果左子节点不为空年并且左子节点就是待删除节点就this.left = null,就结束删除
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
//2.如果右子节点不为空年并且右子节点就是待删除节点就this.right = null,就结束删除
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
//3.向左子树递归删除
if (this.left != null) {
this.left.delNode(no);
}
//4.向右子树递归删除
if (this.right != null) {
this.right.delNode(no);
}
}
}
//输出
前序遍历
12354
中序遍历
21534
后序遍历
25431
前序查找
关胜
删除前
12354
删除后
1234
package calculate;
public class ArrBinaryTree {
//顺序存储二叉树遍历
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7};
ArBinaryTree arBinaryTree = new ArBinaryTree(arr);
System.out.println("前序遍历");
arBinaryTree.preOrder();
}
}
class ArBinaryTree{
private int[] arr; //存储数据节点
public ArBinaryTree(int[] arr) {
this.arr = arr;
}
//重载前序遍历
public void preOrder() {
preOrder(0);
}
//编写方法,完成顺序存储二叉树的前序遍历
public void preOrder(int index) { //index为数组的下标
if (arr == null || arr.length == 0) {
System.out.println("数组为空");
}
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);
}
}
}
//输出
前序遍历
1
2
4
5
3
6
7
package calculate;
import calculate.HeroNode;
public class TreadedBinaryTree {
//线索化二叉树
public static void main(String[] args) {
HeroNode root = new HeroNode(1,"Tom");
HeroNode node2 = new HeroNode(3,"Jack");
HeroNode node3 = new HeroNode(6,"Smith");
HeroNode node4 = new HeroNode(8,"Mary");
HeroNode node5 = new HeroNode(10,"King");
HeroNode node6 = new HeroNode(14,"Dim");
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//中序线索化
BinaryT binaryT = new BinaryT();
binaryT.setRoot(root);
binaryT.threadedNodes(root);
//测试:10号节点的前驱是3号
HeroNode left = node5.getLeft();
System.out.println(left); //输出为3
//线索化遍历二叉树
binaryT.threadedList();
}
}
//创建HeroNode(用之前的)
class HeroNode{
private int no;
private String name;
private HeroNode left; //默认为空
private HeroNode right;//默认为空
//线索化二叉树
//1.如果leftType == 0指向左子树,如果leftType == 1指向前驱结点
//2.如果rightType == 0指向左子树,如果leftType == 1指向后继结点
private int leftType;
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;
}
}
//用之前的BinaryT二叉树
class BinaryT{
private HeroNode root; //根节点
//为了实现线索化,需要创建指向当前节点的前驱结点的指针,在递归pre总是保留前一个节点
private HeroNode pre = null;
public void setRoot(HeroNode root) {
this.root = root;
}
//编写对二叉树中序线索化方法
public void threadedNodes(HeroNode node) { //node就是线索化的节点
//如果node == null不能线索化
if (node == null) {
return ;
}
//1.先线索化左子树
threadedNodes(node.getLeft());
//2.线索化当前节点
//处理当前节点的前驱节点
if(node.getLeft() == null) {
//让当前节点的左指针指向前驱结点
node.setLeft(pre);
//修改当前节点左指针的类型
node.setLeftType(1); //指向前驱节点
}
//处理后继节点
if(pre != null && pre.getRight()==null) {
//让前驱结点的右指针指向当前节点
pre.setRight(node);
//修改前驱结点的右指针类型
pre.setRightType(1);
}
//每处理一个节点后,让当前节点是下一个节点的前驱结点
pre = node;
//3.线索化右子树
threadedNodes(node.getRight());
}
//编写中序线索化二叉树
public void threadedList() {
//定义一个变量,存储当前遍历的节点,从root开始
HeroNode node = root;
while (node != null) {
//leftType == 1的节点就是第一个节点
//后面随着遍历而变化,当leftType==1 的时候,说明该节点按照线索化处理后的有效节点
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();
}
}
}
//输出
3
8
3
10
1
14
6