概念:
二叉树是一种特殊的树,其每个节点最多只能有两个子节点。其左子树和右子树是有顺序的,顺序不能颠倒。即使只有一个节点,也要区分左右子树。
斜树:
二叉树中每个节点只有相同方向,全部节点只有左子节点的称为左斜树,只有右子节点的称为右斜树。
满二叉树:
所有的分支节点都具有左子树和右子树,所有的叶子节点都在同一层上,满二叉树追求树的平衡。
满二叉树具备一下特点:
- 叶子节点只能出现在最下面一层。
- 非叶子节点的度数一定是2。
- 在同样深度的二叉树中,满二叉树的节点个数最多,叶子树最多。
完全二叉树:
对一棵具备n个节点的二叉树,对每个节点按照层序编号。如果编号为i的节点,与同样深度的满二叉树编号为i的节点在二叉树的同样位置,那么这棵二叉树就是完全二叉树。满二叉树一定是完全二叉树,完全二叉树不一定树满二叉树。
完全二叉树具备以下性质:
- 叶子节点只能出现在最下一层。
- 最下层的叶子节点一定出现在左部的连续位置。
- 倒数第二层的叶子节点一定出现在右部的连续位置。
- 同样节点数的二叉树,完全二叉树的深度最小。
性质:
一般二叉树的性质:
- 在非空二叉树的i层上,最多有2^(i-1)个节点。
- 在深度为k的二叉树上,最多有2^k-1个节点。
- 对于一棵非空的二叉树,如果叶子节点的个数为n0,度数为2的节点的个数为n2,则有n0=n2+1。
在一棵二叉树中,除了叶子节点(n0)之外,就剩下度为2(n2)和度为1(n1)的节点了,则树的节点总数为T=n0+n1+n2;在二叉树中节点总数为T,而连线数为T-1,所以有:n0+n1+n2=2*n2+n1。
完全二叉树的性质:
- 具有n个节点的完全二叉树的深度为log2(n)+1。满二叉树是完全二叉树,对于深度为k的满二叉树,其节点个数为2^k-1=n,完全二叉树的节点数量肯定最多2^k-1,同时,完全二叉树倒数第一层有节点时,倒数第二层必定是满的。满二叉树就是完全二叉树的极限情况。因此有2^(k-1)-1<n<=2^k-1,可以推出:2^(k-1)<n<=2^k,即得:k-1<=log2(n)<k。
- 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有:a、如果i=1,则节点是二叉树的根,无双亲,如果i>1,则亲双亲为(1/2)(向下取整)。b、如果2i>n,则节点i没有左孩子,否则左孩子为2i。c、如果2i+1>n,则节点i没有右孩子,否则右孩子为
遍历:
遍历之前先上一棵模版树:
前序遍历:
思想:先遍历根结点,在前序遍历左子树,在前序遍历右子树。
结果:5248193
public void preOrderTraverse(Node<T> node) {
if (node != null) {
System.out.println(node.getValue());
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
}
}
public void nrPreOrderTraverse() {
//借助栈实现
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
System.out.println(node.getValue());
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
node = node.getRight();
}
}
}
中序遍历:
思想:先中序遍历左子树,在访问根结点,在中序遍历右子树。
结果:4821539
public void inOrderTraverse(Node<T> node) {
if (node != null) {
inOrderTraverse(node.getLeft());
System.out.println(node.getValue());
inOrderTraverse(node.getRight());
}
}
}
public void nrInOrderTraverse() {
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.pop();
System.out.println(node.getValue());
node = node.getRight();
}
}
}
后序遍历:
思想:先后序遍历左子树,在后序遍历右子树,在访问根结点。
结果:8412395
public void postOrderTraverse(Node<T> node) {
if (node != null) {
postOrderTraverse(node.getLeft());
postOrderTraverse(node.getRight());
System.out.println(node.getValue());
}
}
}
public void nrPostOrderTraverse() {
Stack<Node<T>> stack = new Stack<Node<T>>();
Node<T> node = root;
Node<T> preNode = null;//表示最近一次访问的节点
while (node != null || !stack.isEmpty()) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
node = stack.peek();
if (node.getRight() == null || node.getRight() == preNode) {
System.out.println(node.getValue());
node = stack.pop();
preNode = node;
node = null;
} else {
node = node.getRight();
}
}
}
层序遍历:
思想:按照层级关系遍历整棵二叉树。
实现方法:可以借助队列实现,将根结点入队列,从队列中弹出元素进行访问,同时将访问的节点的子节点压入队列,不断从队列中弹出元素访问,将子节点压入队列,直到队列中全部访问结束。
结果:5294138
public void levelTraverse(Node<T> node) {
//借助队列实现
Queue<Node<T>> queue = new LinkedBlockingQueue<Node<T>>();
queue.add(node);
while (!queue.isEmpty()) {
Node<T> temp = queue.poll();
if (temp != null) {
System.out.println(temp.getValue());
queue.add(temp.getLeft());
queue.add(temp.getRight());
}
}
}
其它方法:
获取树的深度:
private Integer getHeight(Node node){
if(node==null)
return 0;
else{
int left=getHeight(node.getLeft());
int right=getHeight(node.getRight());
return left>right?left+1:right+1;//左子树 右子树最深的,再加上父节点本身深度1
}
}
}
获取节点数量:
private Integer getSize(Node node){
if(node==null)
return 0;
else{
int leftSize=getSize(node.getLeft());
int rightSize=getSize(node.getRight());
return leftSize+rightSize+1;
}
}
}
来源:oschina
链接:https://my.oschina.net/linqiankun/blog/3195928