在【Java】 大話數據結構(9) 樹(二叉樹、線索二叉樹)一文中,已經實現了采用遞歸方法的前、中、后序遍歷,本文補充了采用循環的實現方法、以及層序遍歷並進行了一個總結。
遞歸實現
/*
* 前序遍歷
*/
public void preOrder() {
preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
System.out.print(node.data);
preOrderTraverse(node.lchild);
preOrderTraverse(node.rchild);
}
/*
* 中序遍歷
*/
public void inOrder() {
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
inOrderTraverse(node.lchild);
System.out.print(node.data);
inOrderTraverse(node.rchild);
}
/*
* 后序遍歷
*/
public void postOrder() {
postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
postOrderTraverse(node.lchild);
postOrderTraverse(node.rchild);
System.out.print(node.data);
}
非遞歸實現(迭代)
非遞歸實現,需要先創建一個棧,利用其特性來進行儲存和輸出。
- 前序遍歷,先輸出當前點的值,一直沿着左子樹進行讀取,沒左子樹就在右子樹重復上述過程。
- 中序遍歷與前序遍歷基本一致,只是輸出值的代碼位置不同。
- 后序遍歷由於要左右子樹輸出完后才能輸出根結點,所以增加一個棧進行標記是否完成左右子樹的輸出,其余思想基本類似。
下面代碼中,要注意node的結點位置和stack.peek()的位置關系。
此外,在后序非遞歸遍歷的過程中,棧中保留的是當前結點的所有祖先。這是和先序及中序遍歷不同的。在某些和祖先有關的算法中,此算法很有價值。
/**
* 前序遍歷(非遞歸)
*/
public void preOrder2() {
preOrder2(root);
System.out.println();
}
private void preOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
while(node!=null||!stack.isEmpty()) {
while(node!=null) {
System.out.print(node.data);
stack.push(node);
node=node.lchild;
}
node=stack.pop().rchild;
}
}
/**
* 中序遍歷
*/
public void inOrder2() {
inOrder2(root);
System.out.println();
}
private void inOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
while(node!=null||!stack.isEmpty()) {
while(node!=null) {
stack.push(node);
node=node.lchild;
}
node=stack.pop();
System.out.print(node.data);
node=node.rchild;
}
}
/**
* 后序遍歷
*/
public void postOrder2() {
postOrder2(root);
System.out.println();
}
private void postOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
Stack<Integer> tag = new Stack<Integer>();
//下面這段注釋也能實現,與后面未注釋部分基本一致。代表了自己的思考過程,就不刪除了
// while(node!=null||!stack.isEmpty()) {
// while(node!=null){
// stack.push(node);
// tag.push(0);
// node=node.lchild;
// }
//注釋中的tag用於標記當前結點是否完成左右子結點遍歷(所以用0,1表示)
// while(!tag.isEmpty()&&tag.peek()==1) { //棧頂節點的左右子結點已完成遍歷
// System.out.print(stack.pop().data);
// tag.pop();
// }
// if(!tag.isEmpty()) { //上面和這里的 !flag.isEmpty() 不可省略,不然會出錯。
// tag.pop();
// tag.push(1);
// node=stack.peek().rchild;
// }
// }
/*后序遍歷時,分別從左子樹和右子樹共兩次返回根結點(用tag表示次數),
* 只有從右子樹返回時才訪問根結點,所以增加一個棧標記到達結點的次序。
*/
while(node!=null||!stack.isEmpty()) {
if(node!=null){
stack.push(node);
tag.push(1); //第一次訪問
node=node.lchild;
}else {
if(tag.peek()==2) {
System.out.print(stack.pop().data);
tag.pop();
}else {
tag.pop();
tag.push(2); //第二次訪問
node=stack.peek().rchild;
}
}
}
}
20191104:前序和后序的非遞歸遍歷還可以合理利用棧的性質來實現,與上面的稍有不同。
前序:
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode node = stk.pop();
if(node==null)
continue;
list.add(node.val);
stk.push(node.right);
stk.push(node.left);
}
return list;
}
后序:
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> list = new LinkedList<Integer>();
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode node = stk.pop();
if(node==null)
continue;
list.addFirst(node.val); //LinkedList's method. If using ArrayList here,then using 'Collections.reverse(list)'' in the end;
stk.push(node.left);
stk.push(node.right);
}
return list;
}
層序遍歷
合理利用隊列的性質即可。
public void levelOrder() {
BiTNode<E> node =root;
LinkedList<BiTNode<E>> list = new LinkedList<>();
list.add(node);
while(!list.isEmpty()) {
node=list.poll();
System.out.print(node.data);
if(node.lchild!=null)
list.offer(node.lchild);
if(node.rchild!=null)
list.offer(node.rchild);
}
}
完整代碼(含測試代碼)
package BiTree;
import java.util.LinkedList;
import java.util.Stack;
class BiTNode<E>{
E data;
BiTNode<E> lchild,rchild;
public BiTNode(E data) {
this.data=data;
this.lchild=null;
this.rchild=null;
}
}
public class BiTree<E> {
private BiTNode<E> root;
public BiTree() {
//root=new BiTNode(null, null, null);
root=null;
}
/*
* 前序遍歷
*/
public void preOrder() {
preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
System.out.print(node.data);
preOrderTraverse(node.lchild);
preOrderTraverse(node.rchild);
}
/*
* 中序遍歷
*/
public void inOrder() {
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
inOrderTraverse(node.lchild);
System.out.print(node.data);
inOrderTraverse(node.rchild);
}
/*
* 后序遍歷
*/
public void postOrder() {
postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
postOrderTraverse(node.lchild);
postOrderTraverse(node.rchild);
System.out.print(node.data);
}
//===============循環遍歷===============
/**
* 前序遍歷(非遞歸)
*/
public void preOrder2() {
preOrder2(root);
System.out.println();
}
private void preOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
while(node!=null||!stack.isEmpty()) {
while(node!=null) {
System.out.print(node.data);
stack.push(node);
node=node.lchild;
}
node=stack.pop().rchild;
}
}
/**
* 中序遍歷
*/
public void inOrder2() {
inOrder2(root);
System.out.println();
}
private void inOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
while(node!=null||!stack.isEmpty()) {
while(node!=null) {
stack.push(node);
node=node.lchild;
}
node=stack.pop();
System.out.print(node.data);
node=node.rchild;
}
}
/**
* 后序遍歷
*/
public void postOrder2() {
postOrder2(root);
System.out.println();
}
private void postOrder2(BiTNode node) {
Stack<BiTNode> stack = new Stack<BiTNode>();
Stack<Integer> tag = new Stack<Integer>();
// while(node!=null||!stack.isEmpty()) {
// while(node!=null){
// stack.push(node);
// tag.push(0);
// node=node.lchild;
// }
//這里的tag用於標記當前結點是否完成左右子結點遍歷(所以用0,1表示)
// while(!tag.isEmpty()&&tag.peek()==1) { //棧頂節點的左右子結點已完成遍歷
// System.out.print(stack.pop().data);
// tag.pop();
// }
// if(!tag.isEmpty()) { //上面和這里的 !flag.isEmpty() 不可省略,不然會出錯。
// tag.pop();
// tag.push(1);
// node=stack.peek().rchild;
// }
// }
/*后序遍歷時,分別從左子樹和右子樹共兩次返回根結點(用tag表示次數),
* 只有從右子樹返回時才訪問根結點,所以增加一個棧標記到達結點的次序。
*/
while(node!=null||!stack.isEmpty()) {
if(node!=null){
stack.push(node);
tag.push(1); //第一次訪問
node=node.lchild;
}else {
if(tag.peek()==2) {
System.out.print(stack.pop().data);
tag.pop();
}else {
tag.pop();
tag.push(2); //第二次訪問
node=stack.peek().rchild;
}
}
}
}
//=========層序遍歷============
public void levelOrder() {
BiTNode<E> node =root;
LinkedList<BiTNode<E>> list = new LinkedList<>();
list.add(node);
while(!list.isEmpty()) {
node=list.poll();
System.out.print(node.data);
if(node.lchild!=null)
list.offer(node.lchild);
if(node.rchild!=null)
list.offer(node.rchild);
}
}
public static void main(String[] args) {
BiTree<String> aBiTree = new BiTree<String>();
aBiTree.root=new BiTNode<String>("A");
aBiTree.root.lchild=new BiTNode<String>("B");
aBiTree.root.rchild=new BiTNode<String>("C");
aBiTree.root.lchild.rchild=new BiTNode<String>("D");
// BiTree<String> aBiTree = new BiTree<String>();
// aBiTree.root=new BiTNode("A");
// aBiTree.root.lchild=new BiTNode("B");
// aBiTree.root.lchild.lchild=new BiTNode("C");
// aBiTree.root.lchild.lchild.lchild=new BiTNode("D");
// aBiTree.root.lchild.rchild=new BiTNode("E");
// aBiTree.root.lchild.rchild.lchild=new BiTNode("F");
// aBiTree.root.lchild.rchild.lchild.rchild=new BiTNode("G");
// aBiTree.root.lchild.rchild.lchild.rchild.rchild=new BiTNode("H");
System.out.println("————前序————");
aBiTree.preOrder();
aBiTree.preOrder2();
System.out.println("————中序————");
aBiTree.inOrder();
aBiTree.inOrder2();
System.out.println("————后序————");
aBiTree.postOrder();
aBiTree.postOrder2();
System.out.println("————層序遍歷————");
aBiTree.levelOrder();
}
}
————前序————
ABDC
ABDC
————中序————
BDAC
BDAC
————后序————
DBCA
DBCA
————層序遍歷————
ABCD
