1.数据结构分析?
- 数组的存储方式分析:
- 优点:通过下标方式访问元素,速度快,对于有序数组还可以使用二分查找提高检索速度。
-
缺点:如果要检索具体某个值,或者插入值会整理移动,效率较低。
-
-
链式储存的方式分析:
-
优点:在一定程序上对数组存储方式有优化,比如插入一个数值时,只需要讲插入点接到链表中即可,删除效率也是同理效果好。
-
缺点:在进行检索时,效率仍然很低,检索某一个值时,需要从链表头一直做检索。
-
-
-
树存储方式分析:
-
能提高数据存储,读取的效率,比如可以使用二叉树既可以保证数据检索速度,同时也可以保证数据的插入,删除,修改的速度。
-
-
2.二叉树介绍:
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。
3.树的结构示意图:
4. 树的常用术语:
-
结点 根结点 父结点 子结点 叶子结点(没有子结点的结点) 结点的全(结点值) 路径(从root结点找到目标结点的线路) 层 子树 树的高度(最大层数) 森林(多颗子树构成森林)
5.二叉树分类:
-
树有很多种,每个结点最多只能有两个子结点的一种形式称之为二叉树,二叉树分为左结点和右结点。
2.如果该二叉树的所有叶子结点都在最后一层,并且结点总数是2^n-1,n是层数,则我们称之为满二叉树。
3.如果该二叉树的所有叶子结点都在最后一层或者倒数第二层,而且最后一层的叶子结点在左边连续,倒数第二层的叶子结点在右边连续,我们称之为全完二叉树。
6.二叉树应用案例:
可以使用前序,中序,后序对下面的二叉树进行遍历
- 前序遍历:先输出父结点,再遍历左子树和右子树
- 中序遍历:先遍历左子树,再遍历父结点,再遍历右子树
-
后序遍历:先遍历左子树,再遍历右子树,最后遍历父结点
结论:看父结点输出顺序即是某序遍历
7. 二叉树应用案例:
- 前序查找
- 中序查找
- 后序查找
8.二叉树应用案例:
- 删除的结点是叶子结点,那么删除当前结点即可。
- 删除的结点是非叶子结点,那么需要删除该子树。
9.完整代码实现:
package tree;
/**
* @author WuChenGuang
*/
public class Node {
private int no;
private String name;
private Node left;
private Node right;
public Node(int no, String name) {
this.no = no;
this.name = 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 Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
", name='" + name + '\'' +
", left=" + left +
", right=" + right +
'}';
}
/**
* 定义前序遍历
*/
public void preSelect() {
// 先输出父结点
System.out.println(this);
if (this.left != null) {
this.left.preSelect();
}
if (this.right != null) {
this.right.preSelect();
}
}
/**
* 中序遍历结点
*/
public void infixSelect() {
// 左节点 父节点 右节点
if (this.left != null) {
this.left.infixSelect();
}
System.out.println(this);
if (this.right != null) {
this.right.infixSelect();
}
}
/**
* 后序遍历
*/
public void postSelect() {
if (this.left != null) {
this.left.postSelect();
}
if (this.right != null) {
this.right.postSelect();
}
System.out.println(this);
}
/**
* 前序遍历查找
*/
public Node preSearch(int no) {
// 判断是否是当前节点
if (this.no == no) {
return this;
}
// 查询左子节点
Node lNode = null;
if (this.left != null) {
lNode = this.left.preSearch(no);
}
if (lNode != null) {
return lNode;
}
// 查询当前节点右子节点,如果不为空,则继续递归前序查找
if (this.right != null) {
lNode = this.right.preSearch(no);
}
return lNode;
}
/**
* 中序遍历查找
*/
public Node infixSearch(int no) {
Node node = null;
if (this.left != null) {
node = this.left.infixSearch(no);
}
if (node != null) {
return node;
}
// 对比当前节点
if (this.no == no) {
return this;
}
// 遍历右子结点
if (this.right != null) {
node = this.right.infixSearch(no);
}
return node;
}
/**
* 后序遍历查找结点
*/
public Node postSearch(int no) {
Node node = null;
if (this.left != null) {
node = this.left.postSearch(no);
}
if (node != null) {
return node;
}
if (this.right != null) {
node = this.right.postSearch(no);
}
if (node != null) {
return node;
}
if (this.no == no) {
return this;
}
return null;
}
/**
* 删除节点两种情况:
* 1.删除的结点是叶子结点
* 2.删除的结点是子树。非叶子结点
* 3.单向二叉树
*/
public void delNode(int no) {
/*
1、当前节点左节点不为空,并且左子节点就是需要删除的结点,this.left=null
2、当前结点右结点不为空,并且右子节点就是需要删除的结点,this.right = null;
3、如果1,2步没有执行,那么需要向左子树进行递归删除
4、如果第3步没有执行,那么则向右子树进行递归删除
*/
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);
}
}
}
package tree;
/**
* @author WuChenGuang
*/
public class BinaryTree {
private Node root;
public void setRoot(Node node) {
this.root = node;
}
public void preSelect() {
if (this.root != null) {
this.root.preSelect();
} else {
System.out.println("空二叉树,无法遍历...");
}
}
public void infixSelect() {
if (this.root != null) {
this.root.infixSelect();
} else {
System.out.println("空二叉树,无法遍历...");
}
}
public void postSelect() {
if (this.root != null) {
this.root.postSelect();
} else {
System.out.println("空二叉树,无法遍历...");
}
}
/**
* 根据结点编号前序查询
*/
public Node preNode(int no) {
if (root != null) {
return root.preSearch(no);
} else {
System.out.println("空二叉树,无法遍历...");
return null;
}
}
/**
* 根据结点编号中序查询
*/
public Node infixNode(int no) {
if (root != null) {
return root.infixSearch(no);
} else {
System.out.println("空二叉树,无法遍历...");
return null;
}
}
/**
* 根据结点编号后序查询
*/
public Node postNode(int no) {
if (root != null) {
return root.postSearch(no);
} else {
System.out.println("空二叉树,无法遍历...");
return null;
}
}
/**
* 删除结点
*/
public void delNode(int no) {
if (root != null) {
if (root.getNo() == no) {
root = null;
} else {
root.delNode(no);
}
} else {
System.out.println("空二叉树,无法删除...");
}
}
}
package tree;
/**
* @author WuChenGuang
*/
public class Test {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
Node root = new Node(1, "孙尚香");
Node node2 = new Node(2, "夏侯惇");
Node node3 = new Node(3, "貂蝉");
Node node4 = new Node(4, "吕布");
Node node5 = new Node(5, "虞姬");
Node node6 = new Node(6, "王昭君");
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node3.setLeft(node5);
node3.setRight(node6);
binaryTree.setRoot(root);
binaryTree.delNode(5);
System.out.println("=====前序遍历=====");
binaryTree.preSelect();
System.out.println("=====中序遍历=====");
binaryTree.infixSelect();
System.out.println("=====后序遍历=====");
binaryTree.postSelect();
System.out.println("==================================================");
Node node = binaryTree.postNode(4);
if (node != null) {
System.out.printf("信息为:id=%d name=%s", node.getNo(), node.getName());
} else {
System.out.println("没有找到结点");
}
}
}
运行结果: