一,树的基本知识
树是一种数据结构,它是由n(n>=1)个有限节点组成的一个具有层次关系的集合,如下图所示:
<1>树的基本术语:
1,父节点和子节点:一个节点若干分支下的节点都称为该节点的子节点,该节点称为子节点的父节点。如上图中B、C是A的子节点,A是B、C的父节点。
2,兄弟节点:同一父节点的所有子节点互为兄弟节点。如上图中B、C互为兄弟节点。
3,节点的度:该节点拥有子树的数目。上图中A的度为2,B的度为1,C的度为3.
4,叶子节点:没有子树的节点即度为0的节点。上图中D、E、F、G为叶子节点。
5,分支节点:拥有子树的节点即度不为0的节点,显然除了叶子节点外的节点都为分支节点。上图中A、B、C为分支节点
6,树的度:树中节点的最大的度。A的度为2,B的度为1,C的度为3,D、E、F、G的度为0,则树的度为3.
7,层次:根节点的层次为1,其余节点的层次为该节点父节点的层次+1.
8,树的高度:树中节点最大的层次。上图中树的高度为3.
<2>树具有的特点:
1,每个节点有零个或者多个子节点。
2,没有父节点的节点称为根节点。
3,除根节点外,每个节点有且仅有一个父节点。
4,除了叶子节点外,每个节点可以分为多个不相交的子树。
二,二叉树的基本知识
二叉树是每个节点最多有两个子树的树结构,它有5中基本形态:空集,左、右子树都为空,左子树或者右子树为空,左、右子树都有。
三,二叉树的构建
1,节点属性
由上述知识可得,二叉树是由一个一个节点构成,由节点的构成关系我们可以设置节点的属性有:父节点、左子节点、右子节点、节点数据。
class Node {
Node paren;//父节点
Node left;//左子节点
Node right;//右子节点
String value;//节点值
//构造方法 只要有新节点实例化就必需赋值
public Node(String value) {
this.value=value;
}
}
2,创建6个节点
//创造节点
public Node createNode() {
//实例化节点
Node root = new Node("A");
Node left = new Node("B");
Node right = new Node("C");
Node left_left = new Node("D");
Node left_right = new Node("E");
Node right_left = new Node("F");
Node right_right = new Node("G");
return root;
}
3,建立连接关系
这里的连接关系即要从上往下由父节点指向子节点,又要从下往上由子节点指向父节点。这是因为打个比方,父亲带孩子出去,如果只有父亲认识孩子而孩子不认识父亲,那孩子一个人就找不到父亲。
//从上往下建立连接关系 父->子
root.left=left;
root.right=right;
left.left=left_left;
left.right=left_right;
right.left=right_left;
right.right=right_right;
//从下往上建立连接关系 子->父
left_left.paren=left;
left_right.paren=left;
right_left.paren=right;
right_right.paren=right;
left.paren=root;
right.paren=root;
root.paren=null;//根节点的父节点为空
建立的二叉树如下:
四,二叉树的遍历
二叉树的遍历是指按照某种顺序访问二叉树中的每个节点,每个节点被访问一次且仅被访问一次。通过一次完整的遍历可使二叉树中的节点由非线性排列变成某种意义上的线性排列。
由二叉树的定义可知,一棵二叉树由根节点、左子树、右子树组成,因此只需要遍历这三个部分就能遍历二叉树,二叉树的遍历方式有以下6种:
1,先序遍历:
父->左子->右子
父->右子->左子
2,中序遍历:
左子->父->右子
右子->父->坐子
3,后序遍历:
左子->右子->父
右子->左子->父
之后的举例中均规定从左->右的访问。
<1>先序遍历
先序遍历的递归过程为:若二叉树为空,则遍历结束;否则先访问根节点,再先序遍历根节点的左子树,最后先序遍历根节点的右子树。
//先序遍历 传入根节点找到此棵树 递归调用
public void preOrder(Node n) {
//当所有节点访问完后就退出递归
if(n==null) {
return;
}
String value = n.value;
System.out.println(value);//1,先访问父节点
preOrder(n.left);//2,再访问左子节点
preOrder(n.right);//3,最后访问右子节点
}
遍历上述构建的二叉树结果为:
<2>中序遍历
中序遍历的递归过程为:若二叉树为空,则遍历结束;否则先先序遍历根节点左子树,再访问根节点,最后先序遍历根节点右子树。
//中序遍历 传入根节点找到此棵树 递归调用
public void midOrder(Node n) {
//当所有节点访问完后就退出递归
if(n==null) {
return;
}
midOrder(n.left);//1,先访问左子节点
System.out.println(n.value);//2,再访问父节点
midOrder(n.right);//最后访问右子节点
}
遍历上述构建的二叉树结果为:
<3>后序遍历
后序遍历的递归过程为:若二叉树为空,则递归结束;否则先后续遍历根节点左子树,再后续遍历根节点右子树,最后访问根节点。
//后序遍历 传入根节点找到此棵树 递归调用
public void postOrder(Node n) {
//当所有节点访问完后就退出递归
if(n==null) {
return;
}
postOrder(n.left);//1,先访问左子节点
postOrder(n.right);//2,再访问右子节点
System.out.println(n.value);//3,最后访问父节点
}
遍历上述构建的二叉树结果为:
<4>层次遍历
层次遍历顾名思义就是一层一层从上往下遍历,遍历完了第一层再遍历第二层,以此类推。
层次遍历的方法与先序遍历、中序遍历、后序遍历不同,它不采用递归的方式,而采用了队列,因为队列的存取顺序是先进先出。在进行层次遍历时,设置一个队列,将根节点引用入队,当队列非空时,循环执行以下三步:
1,从队列中取出一个节点的引用,并访问该节点;
2,若该节点的左子树非空,将该节点的左子树引用入队;
3,若该节点的右子树非空,将该节点的右子树引用入队。
//层次遍历 非递归调用
public void levelOrder(Node n) {
//根节点为空
if(n==null) {
return;
}
//设置一个队列保存层序遍历的节点 队列先进先出 方便调用add方法和poll方法 对队的操作并不会影响数的结构
Queue<Node> q = new LinkedList<Node>();
//根节点入队
q.add(n);
//队列非空 节点没有处理完
while(!q.isEmpty()) {
//队列头节点出队
Node temp = q.poll();
System.out.println(temp.value);//将出队的节点打印出来
//当前出队节点的左子节点入队
if(temp.left!=null) {
q.add(temp.left);
}
//当前出队节点的右子节点入队
if(temp.right!=null) {
q.add(temp.right);
}
}
}
这里有两个方法:
1,add()方法:将指定元素添加到队尾。
2,poll()方法:获取并移除此队列的头。
根据上述代码层次遍历上述二叉树时,每次进入while循环前,队中的元素如下:
箭头指向为队头元素,即进入while循环后取出并打印的节点。
输出结果如下:
整篇博客的完整代码如下:
百度网盘提取码:ijxy