树的基本概念
- 树的定义
树是n>=0个结点的有限集合T;- 有且仅有一个特殊结点成为树的根结点
- n>1时,分为了不相交的子集,每个子集本身又是一棵树(相交的子集不能称为树);
- 树的基本术语
- 结点:包含数据元素,和指向其他分支;
- 结点的度:包含的子树的棵树;
- 树的度:树中结点的度最大的值;
- 叶子结点:度=0;
- 非叶结点:度不等于0;
- 子结点:兄弟结点,顾名思义;
- 层次路径:从根结点开始,到达p所经历的所有结点;称为结点p的层次路径;
- 树的深度:树中结点的最大层次数;
二叉树
- 定义:度小于或等于2;
- 左右子树;
- 满二叉树:每个都满了,如图
- 完全二叉树,从上至下,从左至右,如图所说编号和次序不变;理解:即相对比满二叉树,只能在左右一次右边少,左边少,右边部分有及不是完全二叉树;
二叉树的性质:
- 第i层最多2^(i-1)个结点
- 深度k总个数最多2^k -1个结点;
- 重要性质:度为1的结点记为n1,度为0记为n0,度为2记为n2;
n0=n2+1;
证明:总结点数 N=n0+n1+n2;
边数(两个结点的连线的数量)B=N-1;
B=n1+2*n2 ; (每个边都是从n1和n2开始);
三等式化简,得n0=n2+1;
二叉树存储结构
顺序结构
顺序结构很浪费空间,理解为一个数组来存放二叉树(想象一个满二叉树,从上至下,从左至右,依次为索引结点),不存在的结点记为null;
如图,数字为数组的索引(java的数组需-1);若H节点不存在,则数组中索引8记为null;
链式结构
每个结点的程序构造:
二叉树的遍历
遍历方法:先序,中序,后序,层次遍历;
先序
根结点开始,先访问左子树,后右子树–》递归;
//伪代码如下:
public void traversal(Tree tree){
if(tree==null) return;
system.out.println(tree.data);
traversal(tree.leftNode);
traversal(tree.rightNode);
}
中序
先左子树,中:根结点,右子树
//伪代码如下:
public void traversal(Tree tree){
if(tree==null) return;
traversal(tree.leftNode);
system.out.println(tree.data);
traversal(tree.rightNode);
}
执行结果理解:
后序
//伪代码如下:
public void traversal(Tree tree){
if(tree==null) return;
traversal(tree.leftNode);
traversal(tree.rightNode);
system.out.println(tree.data);
}
执行结果理解:
此3种遍历,访问的顺序都是一致的,唯一的区别就是何时打印结果(访问时刻–读取数据的时候):访问的路径如下所述
每个结点都有3次访问的机会
先序非递归算法
**核心思想:**借助栈保存结点,在中序时抛出;
步骤
- 遇到结点,压栈;遍历左树;
- 左树结束,弹栈并访问;
- 遍历右树,压栈弹栈访问;
//伪代码如下
public void traversal(Tree tree){
Stack s=Stack.creatStack(size);//得到栈
while(tree!=null || !s.isEmpty()){
while(tree!=null){
s.push(tree);
tree=tree.left;
}
if(!s.isEmpty()){
print(tree.data);
tree=s.pop();
tree = tree.right;
}
}
}
中序,后序即改访问位置即可;
层序遍历
核心思想,如先序非递归遍历所述,采用栈保存,如何做到一层一层的,即访问左子树时,已保存其兄弟序列,同时输出左子树后,保存其左右子树,保存到哪儿呢?队列比较何时,
如图所示:
访问A时----保存B,C 队列B,C —出列B
访问B时----保存D,F 队列C,D,F ----出列C
如此步骤,可完成层级访问
//伪代码如下
public void traversal(Tree tree){
if(tree!=null){
Queue que = Queue.getQueue(size);
que.add(tree);
while(!que.isEmpty()){
Tree treeTemp = que.pop();
System.out.println(treeTemp.data);
que.add(tree.left);
que.add(tree.right);
}
}
}