二叉树的遍历
对于二叉树来讲最主要、最基本的运算是遍历。
遍历二叉树 是指以一定的次序访问二叉树中的每个结点。所谓 访问结点 是指对结点进行各种操作的简称。例如,查询结点数据域的内容,或输出它的值,或找出结点位置,或是执行对结点的其他操作。遍历二叉树的过程实质是把二叉树的结点进行线性排列的过程。假设遍历二叉树时访问结点的操作就是输出结点数据域的值,那么遍历的结果得到一个线性序列。
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
(1)访问结点本身(N),
(2)遍历该结点的左子树(L),
(3)遍历该结点的右子树(R)。
以上三种操作有六种执行次序:
NLR、LNR、LRN、NRL、RNL、RLN。
注意:
前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtlee)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
树执行查找、删除、插入的时间复杂度都是O(logN)
举例:
System.out.println("*******(前序遍历)[ABDECF]遍历*****************");
System.out.println("*******(中序遍历)[DBEACF]遍历*****************");
System.out.println("*******(后序遍历)[DEBFCA]遍历*****************");
- 先序遍历:
- 1 2 4 8 9 5 3 6 7
- 中序遍历:
- 8 4 9 2 5 1 6 3 7
- 后序遍历:
- 8 9 4 5 2 6 7 3 1
算法代码实现
定义一个节点类,使节点与二叉树操作分离
class Node {
int value;
Node leftChild;
Node rightChild;
Node(int value) {
this.value = value;
}
public void display() {
System.out.print(this.value + "\t");
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.valueOf(value);
}
}
需要实现的二叉树操作
class BinaryTree {
private Node root = null;
BinaryTree(int value) {
root = new Node(value);
root.leftChild = null;
root.rightChild = null;
}
public Node findKey(int value) {} //查找
public String insert(int value) {} //插入
public void inOrderTraverse() {} //中序遍历
public void preOrderTraverse() {} //前序遍历
public void postOrderTraverse() {} //后序遍历
public int getMinValue() {} //得到最小(大)值
public boolean delete(int value) {} //删除
}
查找数据:
public Node findKey(int value) {
Node current = root;
while (true) {
if (value == current.value) {
return current;
} else if (value < current.value) {
current = current.leftChild;
} else if (value > current.value) {
current = current.rightChild;
}
if (current == null) {
return null;
}
}
}
插入数据:与查找数据类似,不同点在于当节点为空时,不是返回而是插入
public String insert(int value) {
String error = null;
Node node = new Node(value);
if (root == null) {
root = node;
root.leftChild = null;
root.rightChild = null;
} else {
Node current = root;
Node parent = null;
while (true) {
if (value < current.value) {
parent = current;
current = current.leftChild;
if (current == null) {
parent.leftChild = node;
break;
}
} else if (value > current.value) {
parent = current;
current = current.rightChild;
if (current == null) {
parent.rightChild = node;
break;
}
} else {
error = "having same value in binary tree";
}
} // end of while
}
return error;
}
遍历数据:
1)中序遍历:最常用的一种遍历方法
/**
* //中序遍历(递归):
* 1、调用自身来遍历节点的左子树
* 2、访问这个节点
* 3、调用自身来遍历节点的右子树
*/
public void inOrderTraverse() {
System.out.print("中序遍历:");
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(Node node) {
if (node == null)
return ;
inOrderTraverse(node.leftChild);
node.display();
inOrderTraverse(node.rightChild);
}
2)前序遍历:
/**
* //前序遍历(递归):
* 1、访问这个节点
* 2、调用自身来遍历节点的左子树
* 3、调用自身来遍历节点的右子树
*/
public void preOrderTraverse() {
System.out.print("前序遍历:");
preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(Node node) {
if (node == null)
return ;
node.display();
preOrderTraverse(node.leftChild);
preOrderTraverse(node.rightChild);
}
3)后序遍历:
**
* //后序遍历(递归):
* 1、调用自身来遍历节点的左子树
* 2、调用自身来遍历节点的右子树
* 3、访问这个节点
*/
public void postOrderTraverse() {
System.out.print("后序遍历:");
postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(Node node) {
if (node == null)
return ;
postOrderTraverse(node.leftChild);
postOrderTraverse(node.rightChild);
node.display();
}
得到最小(大)值:依次向左(右)直到空为之
public int getMinValue() {
Node current = root;
while (true) {
if (current.leftChild == null)
return current.value;
current = current.leftChild;
}
}
参考文章:http://ocaicai.iteye.com/blog/1047397
http://blog.youkuaiyun.com/wuwenxiang91322/article/details/12231657
http://www.2cto.com/kf/201608/541695.html
面试参考:http://blog.youkuaiyun.com/luckyxiaoqiang/article/details/7518888/