二叉树的遍历方式
什么是树的遍历
树的遍历是图的遍历的一种,指的是按照某种规则,** 不重复地访问 **某种树的所有节点的过程。
遍历的种类
由于从给定的某个节点出发,有多个可以前往的下一个节点(树不是线性数据结构),所以在顺序计算(即非并行计算)的情况下, 只能推迟对某些节点的访问 ——即以某种方式保存起来以便稍后再访问。常见的做法是采用栈(LIFO)或队列(FIFO)。
由于树本身是一种自我引用(即递归定义)的数据结构,因此很自然也可以用递归方式来实现延迟节点的保存。
深度优先
深度优先搜索算法(Depth-First-Search,DFS)沿着树的深度遍历树的节点**,尽可能深的搜索树的分支**。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索
深度优先可进一步按照根节点相对于左右子节点的访问先后来划分。如果把左节点和右节点的位置固定不动,那么根节点放在左节点的左边,称为前序(pre-order)、根节点放在左节点和右节点的中间,称为中序(in-order)、根节点放在右节点的右边,称为后序(post-order)。
广度优先
广度优先搜索算法(Breadth-First-Search,BFS),又译作宽度优先搜索,或横向优先搜索,是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。给定一组已排序的子节点,其“广度优先”的遍历 只有一种唯一 的结果。
代码实现
深度优先
二叉树如下:
前序遍历:1->2->4->5->3->6
中序遍历:4->2->5->1->3->6
后序遍历:4->5->2->6->3->1
生成二叉树
public class Test5 {
//创建节点类
public class TreeNode{
private int data;
private TreeNode leftNode;
private TreeNode rightNode;
public TreeNode(int data, TreeNode leftNode, TreeNode rightNode) {
this.data = data;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public TreeNode getLeftNode() {
return leftNode;
}
public void setLeftNode(TreeNode leftNode) {
this.leftNode = leftNode;
}
public TreeNode getRightNode() {
return rightNode;
}
public void setRightNode(TreeNode rightNode) {
this.rightNode = rightNode;
}
}
/**
* 二叉树的初始化时需要注意从下面的子节点开始创建
* @return 返回根节点
*/
public TreeNode init(){
TreeNode D = new TreeNode(4, null, null);
TreeNode E = new TreeNode(5, null, null);
TreeNode H = new TreeNode(6, null, null);
TreeNode B = new TreeNode(2, D, E);
TreeNode C = new TreeNode(3, null, H);
TreeNode A = new TreeNode(1, B, C);//A为根节点
return A;
}
}
前序遍历
/**
* 先序遍历:root->left->right
* @param root
* @return
*/
ArrayList<Integer> preOrderlist = new ArrayList<>();//要注意将这个数组放在方法的外部,因为这是一个全局变量
public ArrayList<Integer> preOrder(TreeNode root){
if(root == null) return null;
preOrderlist.add(root.getData());
if(root.getLeftNode() != null) preOrder(root.getLeftNode());
if(root.getRightNode() != null) preOrder(root.getRightNode());
return preOrderlist;
}
public static void main(String[] args){
Test5 test5 = new Test5();
TreeNode root = test5.init();
ArrayList<Integer> list = test5.preOrder(root);
System.out.println("preOrder");
for(int i = 0; i < list.size(); i++){
System.out.print(list.get(i)+"->");
}
}
/**
* preOrder
1->2->4->5->3->6
*/
贴上错误代码予以警示😓
public ArrayList<Integer> preOrder(TreeNode root){
while (root != null){//这里事实上是个死循环啊😭,如果是最后一个节点,它虽然没有孩子,但是它本身永远都不会为null呀
preOrderlist.add(root.getData());
if(root.getLeftNode() != null) preOrder(root.getLeftNode());
if(root.getRightNode() != null) preOrder(root.getRightNode());
}
return preOrderlist;
}
中序遍历
/**
* 中序遍历:left->root->right
* @param root
* @return
*/
ArrayList<Integer> inOrderlist = new ArrayList<>();//要注意将这个数组放在方法的外部,因为这是一个全局变量
public ArrayList<Integer> InOrder(TreeNode root) {
if(root.leftNode != null){
InOrder(root.getLeftNode());
}
inOrderlist.add(root.getData());
if(root.rightNode != null){
InOrder(root.getRightNode());
}
return inOrderlist;
}
同样贴上一个错误代码予以警示😂
public ArrayList<Integer> InOrder(TreeNode root) {
if(root.leftNode != null){
InOrder(root.getLeftNode());
}else {//第一次写的时候这里加了else,真的是智障,难道不知道这样的话就是返回所有左节点为空的节点了吗
inOrderlist.add(root.getData());
}
if(root.rightNode != null){
InOrder(root.getRightNode());
}
return inOrderlist;
}
后序遍历
/**
* 后序遍历left->right->root
* @param root
* @return
*/
ArrayList<Integer> postOrderList = new ArrayList<Integer>();
public ArrayList<Integer> postOrder(TreeNode root){
if(root.getLeftNode() != null){
postOrder(root.getLeftNode());
}
if(root.getRightNode() != null){
postOrder(root.getRightNode());
}
postOrderList.add(root.getData());
return postOrderList;
}
广度优先
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
ArrayList<TreeNode> leverTraversalList = new ArrayList<TreeNode>();
/**
*广度优先遍历(层次遍历)
* @param root
* @return
*/
public ArrayList<TreeNode> leverTraversal(TreeNode root){
//创建一个队列用于存储当前节点的左右节点
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while (!queue.isEmpty()){//注意终止条件
//如果queue不为空就弹出第一个节点
TreeNode currentNode = queue.pollFirst();
leverTraversalList.add(currentNode);
if(currentNode.getLeftNode() != null){
queue.addLast(currentNode.getLeftNode());
}
if(currentNode.getRightNode() != null){
queue.addLast(currentNode.getRightNode());
}
}
return leverTraversalList;
}