首先我们需要了解二叉树的基本性质:
1.每一个节点最多有两个孩子节点
2.左孩子<根节点<右孩子
四种遍历思路:
前序遍历:根结点 —> 左子树 —> 右子树
中序遍历:左子树—> 根结点 —> 右子树
后序遍历:左子树 —> 右子树 —> 根结点
层次遍历:仅仅需按层次遍历就可以义目录标题)
而刚好由于这种性质,我们利用递归可以很简单的完成遍历
前序遍历递归实现:
public void preOrder() {
System.out.print(“递归前序遍历:”);
preOrder(this.root);
System.out.println();
}
/**
* 前序遍历BST树的递归操作 VLR
*
* @param root
*/
private void preOrder(BSTNode<T> root) {
if (root != null) {
System.out.print(root.getData() + " ");
preOrder(root.getLeft());
preOrder(root.getRight());
}
}
中序遍历的递归实现:
public void inOrder() {
System.out.print(“递归中序遍历:”);
inOrder(this.root);
System.out.println();
}
/**
* 中序遍历BST树的递归操作 LVR
*
* @param root
*/
private void inOrder(BSTNode<T> root) {
if (root != null) {
inOrder(root.getLeft());
System.out.print(root.getData() + " ");
inOrder(root.getRight());
}
}
后序遍历的递归实现:
public void postOrder() {
System.out.print(“递归后序遍历:”);
postOrder(this.root);
System.out.println();
}
/**
* 中序遍历BST树的递归操作 LRV
*
* @param root
*/
private void postOrder(BSTNode<T> root) {
if (root != null) {
postOrder(root.getLeft());
postOrder(root.getRight());
System.out.print(root.getData() + " ");
}
}
层序遍历的递归实现:
public void levelOrder() {
System.out.print(“递归层序遍历:”);
int hight = level();
for (int i = 0; i < hight; i++) {
levelOrder(this.root, i);
}
System.out.println();
}
/**
* 层序遍历的递归实现
*
* @param root
* @param i
*/
private void levelOrder(BSTNode<T> root, int i) {
if (root != null) {
if (i == 0) {
System.out.print(root.getData() + " ");
return;
}
levelOrder(root.getLeft(), i - 1);
levelOrder(root.getRight(), i - 1);
}
}
这里也使用了非递归实现方式:
前序遍历的非递归实现:
public void preOrderTraverse2(TreeNode root) {
Stack stack = new Stack<>();
TreeNode pNode = root;
while (pNode != null || !stack.isEmpty()) {
if (pNode != null) {
System.out.print(pNode.val+" “);
stack.push(pNode);
pNode = pNode.left;
} else { //pNode == null && !stack.isEmpty()
TreeNode node = stack.pop();
pNode = node.right;
}
}
}
中序遍历的非递归实现:
public void inOrderTraverse2(TreeNode root) {
Stack stack = new Stack<>();
TreeNode pNode = root;
while (pNode != null || !stack.isEmpty()) {
if (pNode != null) {
stack.push(pNode);
pNode = pNode.left;
} else { //pNode == null && !stack.isEmpty()
TreeNode node = stack.pop();
System.out.print(node.val+” “);
pNode = node.right;
}
}
}
后序遍历的非递归实现:
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索。直到搜索到没有左孩子的结点,
此时该结点出如今栈顶,可是此时不能将其出栈并訪问,因此其右孩子还为被訪问。
void postOrder2(BinTree root) //非递归后序遍历
{
stack<BTNode> s;
BinTree *p=root;
BTNode *temp;
while(p!=NULL||!s.empty())
{
while(p!=NULL) //沿左子树一直往下搜索。直至出现没有左子树的结点
{
BTNode *btn=(BTNode *)malloc(sizeof(BTNode));
btn->btnode=p;
btn->isFirst=true;
s.push(btn);
p=p->lchild;
}
if(!s.empty())
{
temp=s.top();
s.pop();
if(temp->isFirst==true) //表示是第一次出如今栈顶
{
temp->isFirst=false;
s.push(temp);
p=temp->btnode->rchild;
}
else //第二次出如今栈顶
{
cout<btnode->data<<” ";
p=NULL;
}
}
}
}
所以接下来依照同样的规则对其右子树进行同样的处理,当訪问完其右孩子时。该结点又出如今栈顶
,此时能够将其出栈并訪问。这样就保证了正确的訪问顺序。能够看出,在这个过程中,每一个结点都两次出如今栈顶,
仅仅有在第二次出如今栈顶时,才干訪问它。因此须要多设置一个变量标识该结点是否是第一次出如今栈顶。
第二种思路:要保证根结点在左孩子和右孩子訪问之后才干訪问,因此对于任一结点P。先将其入栈。假设P不存在左孩子和右孩子。
则能够直接訪问它;或者P存在左孩子或者右孩子。可是其左孩子和右孩子都已被訪问过了。则相同能够直接訪问该结点。
若非上述两种情况。则将P的右孩子和左孩子依次入栈。这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被訪问。左孩子和右孩子都在根结点前面被訪问。
void postOrder3(BinTree root) //非递归后序遍历
{
stack<BinTree> s;
BinTree *cur; //当前结点
BinTree *pre=NULL; //前一次訪问的结点
s.push(root);
while(!s.empty())
{
cur=s.top();
if((cur->lchildNULL&&cur->rchildNULL)||
(pre!=NULL&&(precur->lchild||precur->rchild)))
{
cout<data<<" “; //假设当前结点没有孩子结点或者孩子节点都已被訪问过
s.pop();
pre=cur;
}
else
{
if(cur->rchild!=NULL)
s.push(cur->rchild);
if(cur->lchild!=NULL)
s.push(cur->lchild);
}
}
}
层序遍历的非递归实现:层次遍历的代码比較简单。仅仅须要一个队列就可以。先在队列中增加根结点。之后对于随意一个结点来说。
在其出队列的时候,訪问之。同一时候假设左孩子和右孩子有不为空的。入队列。
public void levelTraverse(TreeNode root) {
if (root == null) {
return;
}
LinkedList queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.val+” ");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}