java创建二叉树并且遍历二叉树的几种方式,按层,递归,非递归,分别借助了工具队列和栈
(一).二叉树的重要概念
1.二叉树的定义
二叉树是另一种树形结构,他的特点是每个节点至多有两棵子树(所有节点度都不大于2)并且二叉树有左右之分,其次序不能任意颠倒。
2: 二叉树的类型
二叉树中两个中比较重要的概念
(1) 满二叉树:一个深度为k且有2k-1个节点的二叉树成为满二叉树
(2)完全二叉树:深度为k有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树的编号从1至n一一对应时,成为完全二叉树。
3: 二叉树的性质(c语言版的数据结构)二叉树中的5个特性
(1)二叉树的第i层至多有2的(i-1)次方个节点,下图中第三层最多有DEFG四个节点(归纳假设即可证明,过程简单不做赘述,归纳证明的步骤附上,帮自己回忆回忆,哈...)
1)当n=1时,显然成立.
2)假设当n=k时(把式中n换成k,写出来)成立,
则当n=k+1时,(这步比较困难,化简步骤往往繁琐,考试时可以直接写结果)该式也成立.
由(1)(2)得,原命题对任意正整数均成立
(2)深度为k的二叉树至多有2的k次方减1个节点,下图深度为3,至多有2的3次方减个节点(7个)
证明过程根据性质(1),前n项求和(首项为1公比为2的前n项求和a1*(1-q∧n)/(1-q))
(3)对于任意一颗二叉树T,如果其终端节点数为n0,度为2的节点数为n2,则n0=n2+1;(终端节点=叶 子节点=度
为0的节点数)总节点数:n ,终端节点数 n0,度为2的节点数n2,假设度为1的节点数为n1,二叉树中的分支
(下图中的箭头个数)个数为branch;
证明
已知:n=n0+n1+n2①
因为:出root(A)节点外,其余节点均由一个分支进入故,n=branch+1②
又因为:所有分支均有由度为1或度为2的节点发出故,branch=n1+2n2③
由②③得 n=n1+2n2+1④
由①④得n0=n2+1;
(4) 具有n个节点的二叉树深度为log以2为底的n,向下取整然后减1;
证明:由前面的性质可得2^(k-1) <= n < (2^k)
因为三个数均为正数 ,同取log以2为底的对数 k-1 <= log以2为底的n < k ,因为k是正数,且关
系为小于等于 所以log以2为底的n 向下取整;
(5)对于一颗节点为n的完全二叉树,对于任意节点i(1<=1<=n)有(i为元素的顺序下标)
<1>如果i=1,则节点i是二叉树的根,无双亲;如果 i>1 则其双亲节点是(i/2)向下取整
<2>如果2*i > n,则节点i无左孩子,要么其左孩子是节点2i
<3>如果2i+1 > n,则节点i无右孩子,否则其右孩子是节点(2*i+1)
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
public class BinaryTree {
//定义一个数组
static char [] letter={'a','b','c','d','e','f','g','h'};
//定义一个集合将二叉树的元素存起来
static List <Node> nodeList = null;
//定义一个内部类
private static class Node{
char data; //当前节点的值
Node leftChild; //当前节点的左孩子的指向
Node rightChild;//当前节点右孩子的指向
//内部类的构造方法
Node(char newData){
data = newData; //初始化各结点的数值部分
leftChild = null;
rightChild = null;
}
}
/**
* 创建一棵二叉树
* 一个有n个节点的二叉树,其非叶子节点既父节点的个数为(n/2)向下取整个
*/
public static void creatBinTree(){
nodeList = new ArrayList<Node>();
//用数组的每一个值创建一个Node对象并把并添加到集合中
for (int arryPointer = 0; arryPointer < letter.length; arryPointer++) {
nodeList.add(new Node(letter[arryPointer]));
}
/**初始化每个根节点对应的左孩子和右孩子
*/
for (int fatherNode = 0; fatherNode < letter.length/2-1; fatherNode++) {
nodeList.get(fatherNode).leftChild = nodeList.get(2*fatherNode+1);
nodeList.get(fatherNode).rightChild = nodeList.get(2*fatherNode+2);
}
//单独处理最后一个根节点
int lastFatherNode = letter.length/2-1;
Node lastNode = nodeList.get(lastFatherNode);
lastNode.leftChild = nodeList.get(2*lastFatherNode+1);
/**判断确定最后一个节点是否有右孩子
* 如果n是奇数则最后一个节点有右孩子,如果n为偶数,最后一个节点没有右孩子
*/
int Remainder = (letter.length % 2);
if(Remainder == 1){//当数组的长度为奇数时,说明最后这个节点有右孩子
lastNode.leftChild = nodeList.get(2*lastFatherNode+2);
}
}
/**
* 后序遍历,采用递归实现
* 前序和中序遍历与后序类似,未做赘述
* @param node 根节点
*/
public static void lastOrderPreview(Node node){
if(node==null){
return;
}
lastOrderPreview(node.leftChild);
lastOrderPreview(node.rightChild);
System.out.print(node.data+" ");
}
/**
*
* @param args
* 测试
*/
public static void main(String[] args) {
creatBinTree();//构建一颗二叉树
Node root = nodeList.get(0); //拿到二叉树的根节点
byLayerOrder2(root); //按层遍历
lastOrderPreview(root);//后序遍历
}
/**
* 按层遍历二叉树
*
*/
public static void byLayerOrder2(Node root){
Node last = root; //每行最后一个结点
Node nLast = root;
Node tempNode;
Queue<Node> queue = new LinkedList<Node>();//先进后出
queue.add(nodeList.get(0));
while (!queue.isEmpty()) {
tempNode = queue.poll();
if (tempNode == null)
continue;
System.out.print(tempNode.data+" ");
if(tempNode.leftChild != null){
queue.add(tempNode.leftChild);
nLast = tempNode.leftChild;
}
if(tempNode.rightChild != null){
queue.add(tempNode.rightChild);
nLast = tempNode.rightChild;
}
if(last == tempNode){
//输出换行
System.out.println();
last = nLast;
}
}
}
/**
* 非递归实现的二叉树遍历
* 前序遍历
* @param
*/
public static void preOrder2(Node node) {
Stack<Node> s = new Stack<Node>(); //先进后出
while (node != null || !s.empty()) {
//输出节点及右孩子的值并压入栈中
while (node != null) {
System.out.print(node.data+" ");
s.push(node);
node = node.leftChild;
}
//改变node的值,使node指向节点的左孩子
if (!s.empty()) {
node = s.pop();
node = node.rightChild;
}
}
}
}