樹的三種遍歷方式原始碼(遞迴與非遞迴)
阿新 • • 發佈:2019-02-20
在面試的時候,我們會經常被問到樹的三種遍歷,也就是前序遍歷、中序遍歷和後序遍歷。
所謂前序遍歷,就是先訪問根節點,再左,再右。命名方式就是根據根節點是在哪訪問的去定義的。下面我們先用Java實現三種遍歷的遞迴,是非常的簡單。
樹的前序遍歷:
public void recursiveProOrder(Node root) {
if (root != null) {
System.out.print(root.value);
if (root.left != null) {
recursivePostOrder(root.left);
}
if (root.right != null) {
recursivePostOrder(root.right);
}
}
}
樹的中序遍歷:
public void recursiveInOrder(Node root) {
if (root != null) {
if (root.left != null) {
recursiveInOrder(root.left);
}
System.out.print(root.value);
if (root.right != null ) {
recursiveInOrder(root.right);
}
}
}
樹的後序遍歷:
public void recursivePostOrder(Node root) {
if (root != null) {
if (root.left != null) {
recursivePostOrder(root.left);
}
if (root.right != null) {
recursivePostOrder(root.right);
}
System.out .print(root.value);
}
}
下面介紹如何用非遞迴的方式進行遍歷。所謂遞迴,其實在語言的底層層面上來講,也是用棧來實現的,因此,要把遞迴的演算法改為非遞迴,我們都可以考慮用棧來實現怎麼操作。其中,前序和中序的非遞迴實現都比較容易,需要重點理解的是樹的後序遍歷的非遞迴實現。下面直接給出程式碼。
樹的前序遍歷(非遞迴):
public void preOrder(Node node)
{
Stack<Node> stack = new Stack<>();
while(node != null || !stack.empty())
{
while(node != null)
{
System.out.print(node.element + " ");
stack.push(node);
node = node.left;
} //while迴圈負責掃描所有當前結點,並判斷有沒有左子樹
if(!stack.empty()) //當stack為空的時候,說明沒有左子樹了
{
node = stack.pop();
node = node.right;
}
}
}
樹的中序遍歷(非遞迴):
public void midOrder1(Node node)
{
Stack<Node> stack = new Stack<>();
while(node != null || !stack.empty())
{
while (node != null)
{
stack.push(node);
node = node.left;
} //先壓到樹的最左下角的左子樹
if(!stack.empty())
{
node = stack.pop();
System.out.print(node.element + " ");
node = node.right;
}
}
}
樹的後序遍歷(非遞迴):
public void postOrder(Node node){
if(node==null)
return;
Stack<Node> s = new Stack<Node>();
Node curNode; //當前訪問的結點
Node lastVisitNode; //上次訪問的結點
curNode = node;
lastVisitNode = null;
//把currentNode移到左子樹的最下邊
while(curNode!=null){
s.push(curNode);
curNode = curNode.getLchild();
}
while(!s.empty()){
curNode = s.pop(); //彈出棧頂元素
//一個根節點被訪問的前提是:無右子樹或右子樹已被訪問過
if(curNode.getRchild() != null
&& curNode.getRchild() != lastVisitNode){
//根節點再次入棧
s.push(curNode);
//進入右子樹,且可肯定右子樹一定不為空
curNode = curNode.getRchild();
while(curNode != null){
//再走到右子樹的最左邊
s.push(curNode);
curNode = curNode.getLchild();
}
}else{
//訪問
System.out.println(curNode.getData());
//修改最近被訪問的節點
lastVisitNode = curNode;
}
} //while
}
對於後序遍歷的非遞迴實現,需要好好理解。