层序遍历一棵树在工程化的实践中有着广泛的应用,比如我们遍历一个json,如下的json我们看到有两层。首先遍历第一层,遍历完成后再遍历第二层author节点下的内容,遍历html树的时候也会存在这种情况。

{
	"product": "fileup跨平台局域网文件分享",
	"website": "http://fileup.marsdl.com",
	"author": {
		"username": "chenrui",
		"age": "250"
	}
}
分步查看层序遍历算法的实现

对如下的一棵树进行层序遍历,根据树的根节点存入队列中,然后从队列中获取队列的第一个节点并且访问,并将其左右节点和右节点存放至队列中。依次进行下去。

JavaScript n层遍历二叉树 java层序遍历二叉树_初始化


如下图,开始访问一棵树的初始化操作,队列的第一个节点就是树的第一个节点根节点

JavaScript n层遍历二叉树 java层序遍历二叉树_初始化_02


遍历完html节点节点后从队列移除,将html节点左子节点右子节点放入队列中。

进行下一个节点的访问,下一个节点的访问就是访问队列中第一个节点;当前队列的第一个节点是head节点,访问head节点并从队列的移除,然后将head节点左子节点右子节点放入队列中。

而后再次下一个节点访问,查看队列中的第一个节点,此时第一个节点为body节点。访问body节点并将其左子节点右子节点放入队列中。依次这种方式进行下去,直到队列为空即为遍历完成。

JavaScript n层遍历二叉树 java层序遍历二叉树_JavaScript n层遍历二叉树_03

总的来说层序遍历分为三个步骤

  • 初始化将树的根节点放入初始化的队列;
  • 依次获取队列中第一个节点来进行二叉树的遍历,并把访问节点的左子节点与右子节点放入队列中;
  • 队列中没有数据时,这标志着这棵树遍历完成。

层序遍历的代码

public static void sequenceTraverse(Node node) {
    //初始化将树的根节点放入初始化的队列
    Queue<Node> nodeQueue = new LinkedList<>();
    nodeQueue.offer(node);
    //队列中没有数据时,这标志着这棵树遍历完成
    while (!CollectionUtils.isEmpty(nodeQueue)) {
    	//依次获取队列中第一个节点来进行二叉树的遍历
        Node currentNode = nodeQueue.poll();
        System.out.println(currentNode.value);
        //把访问节点的`左子节点与右子节点`放入队列中
        if (currentNode.leftChild != null) {
            nodeQueue.offer(currentNode.leftChild);
        }
        if (currentNode.rightChild != null) {
            nodeQueue.offer(currentNode.rightChild);
        }
    }
}
生产实践中的多叉树层序遍历

在生产实践中我们会遇到多叉树,像实际的html内容与实际的json文件产生的树都是多叉树。没法像二叉树那种判断是否有左孩子,右孩子,如下的代码有直接对应的左孩子与右孩子将不适用。

if (currentNode.leftChild != null) {
   nodeQueue.offer(currentNode.leftChild);
}
if (currentNode.rightChild != null) {
    nodeQueue.offer(currentNode.rightChild);
}

改用如下的伪代码方式,比如访问某一个节点时,需要将其所有的孩子节点放入到队列中去。isChildrenNotNull()是伪代码判断当前节点是否有孩子节点,children()所有的孩子节点。

if (currentNode.isChildrenNotNull()) {
   nodeQueue.offer(currentNode.children());
}

总结:发现到如果理解了层序遍历的本质,对工程中的多叉树只是判断条件稍微改变,其层序遍历的思想没有改变。层序访问多叉树的伪代码。

public static void sequenceTraverse(Node node) {
    //初始化将树的根节点放入初始化的队列
    Queue<Node> nodeQueue = new LinkedList<>();
    nodeQueue.offer(node);
    //队列中没有数据时,这标志着这棵树遍历完成
    while (!CollectionUtils.isEmpty(nodeQueue)) {
    
    	//依次获取队列中第一个节点来进行二叉树的遍历
        Node currentNode = nodeQueue.poll();
        System.out.println(currentNode.value);
        
        //判断当前节点是否存在孩子节点,如果存在全部加入到队列中
        if (currentNode.isChildrenNotNull()) {
		   nodeQueue.offer(currentNode.children());
		}
    }
}