二叉树迭代器

博客介绍了迭代器概念,它能将算法和数据结构解耦,使通用算法用于不同数据结构。链表迭代器实现简单,二叉树则不然,因递归遍历由编译器在调用栈自动进行,程序员缺乏控制。还提及二叉树非递归遍历方法,并分别阐述先序、中序、后序遍历迭代器。

一. 简介

仅有遍历算法是不够的,在许多应用中,我们还需要对遍历本身进行抽象。假如有一个求和的函数sum,我们希望它能应用于链表,数组,二叉树等等不同的数据结构。这时,我们可以抽象出迭代器(Iterator)的概念,通过迭代器把算法和数据结构解耦了,使得通用算法能应用于不同类型的数据结构。

我们可以把sum函数定义成:

int sum(Iterator from, Iterator to)

链表作为一种线性结构,它的迭代器实现非常简单和直观,而二叉树的迭代器实现则不那么容易,我们不能直接将递归遍历转换为迭代器。究其原因,这是因为二叉树递归遍历过程是编译器在调用栈上自动进行的,程序员对这个过程缺乏足够的控制。既然如此,那么我们如果可以自己来控制整个调用栈的进栈和出栈不是就达到控制的目的了吗?

先看看二叉树的非递归遍历方法:

后序遍历:

 

void PostOrder_Nonrecursive(Node* T)
{    
    stack<Node*> s1 , s2;    
    Node* curr ;           // 指向当前要检查的节点  
    s1.push(T);  
    while(!s1.empty())  // 栈空时结束    
    {  
        curr = s1.top();  
        s1.pop();  
        s2.push(curr);  
        if(curr->lchild)  
            s1.push(curr->lchild);  
        if(curr->rchild)  
            s1.push(curr->rchild);  
    }  
    while(!s2.empty())  
    {  
        printf("%c ", s2.top()->data);  
        s2.pop();  
    }  
}

 

中序遍历:

 

void InOrderTraverse1(Node* T)   // 中序遍历的非递归  
{  
    if(!T)  
        return ;  
    Node* curr = T;    // 指向当前要检查的节点  
    stack<Node*> s;
    while(curr != NULL || !s.empty())
    {
        while(curr != NULL)
        {
            s.push(curr);
            curr = curr->lchild;
        }//while
        if(!s.empty())
        {
            curr = s.top();
            s.pop();
            cout<<curr->data<<"  ";
            curr = curr->rchild;
        }
    }
}

 

先序遍历

 

void PreOrder_Nonrecursive(Node* T)     //先序遍历的非递归    
{  
    if(!T)    
        return ;    
    
    stack<Node*> s;  
    s.push(T);  
  
    while(!s.empty())  
    {  
        Node* temp = s.top();  
        cout<<temp->data<<" ";  
        s.pop();  
        if(temp->rchild)  
            s.push(temp->rchild);  
        if(temp->lchild)  
            s.push(temp->lchild);  
    }  
}

 

二. 迭代器接口

 

typedef stack<AVLNode*> Stack;
typedef queue<AVLNode*> Queue;

extern class AVLTree;
class AVLIterator
{
protected:
    AVLNode* now;
    Stack s;
public:
    virtual AVLIterator& operator++() = 0;
    AVLIterator& operator++(int){ return operator++(); }
    AVLNode& operator*() { return *now; }
    const AVLNode& operator*() const { return *now; }
    virtual void dfs(AVLNode* root) = 0;
    bool operator==(const AVLIterator& src) const { return now == src.now; }
    bool operator!=(const AVLIterator& src) const { return now != src.now; }
};

 

虽然是给AVL树写的, 但是同样适用于所有二叉树

三. 先序遍历迭代器

 

class PreorderIterator :public AVLIterator
{
protected:
    void dfs(AVLNode* root) {/*什么也不做*/}
public:
    PreorderIterator(AVLNode* root) :AVLIterator()
    {
        s = Stack();
        s.push(root);
        operator++();
    }
    PreorderIterator() :AVLIterator(){ now = 0; }

    PreorderIterator& operator++()
    {
        if (s.empty())
            now = NULL;
        else
        {
            now = s.top();
            s.pop();
            // 注意入栈顺序
            if (now->right)
                s.push(now->right);
            if (now->left)
                s.push(now->left);
        }
        return *this;
    }
};

 

四. 中序遍历迭代器

 

class InorderIterator :public AVLIterator
{
protected:
    void dfs(AVLNode* v)
    {
        while (v)
        {
            s.push(v);
            v = v->left;
        }
    }
public:
    // 初始化中序迭代器. 迭代器的初始位置是树的最左结点.
    InorderIterator(AVLNode* root) :AVLIterator()
    {
        s = Stack();
        dfs(root);
        operator++();
    }
    InorderIterator():AVLIterator(){ now = 0; }

    //@Override
    InorderIterator& operator++()
    {
        if (s.empty())
        {
            now = 0;
        }
        else 
        {
            // 找到当前结点(栈顶)
            now = s.top();
            s.pop();
            // 为下一次移动做准备: 
            // 模拟中序遍历的入栈方式
            // 对右子树的左侧路径进行深搜, 并记录左侧路径
            if (now->right != 0)
                dfs(now->right);
        }
        return *this;
    }
};

五. 后序遍历迭代器

class PostorderIterator :public AVLIterator
{
protected:
    AVLNode* _right; //记忆已经访问过的右子树
    Stack s2;
    void dfs(AVLNode* n)
    {
        while (!s.empty())
        {
            AVLNode* curr = s.top();
            s.pop();
            s2.push(curr);
            if (curr->left)
                s.push(curr->left);
            if (curr->right)
                s.push(curr->right);
        }
    }
public:
    PostorderIterator(){ now = 0; }
    PostorderIterator(AVLNode* root)
    {
        s2 = Stack();
        s.push(root);
        dfs(0);
        operator++();
    }

    PostorderIterator& operator++()
    {
        if (s2.empty())
            now = 0;
        else {
            now = s2.top();
            s2.pop();
        }
        return *this;
    }
};

 

### 二叉树迭代可视化实现方法与工具 #### 1. 可视化的重要性 在学习数据结构的过程中,尤其是像二叉树这样的复杂结构,可视化技术能够显著提升理解和记忆效率[^1]。通过图形界面展示二叉树的构建过程、节点关系及其遍历路径,可以帮助开发者更清晰地掌握其实现细节。 #### 2. 基于Python的二叉树迭代可视化实现 对于二叉树的迭代操作,通常可以通过栈或者队列来模拟递归调用的过程。以下是基于Python的一个简单示例,用于演示如何结合matplotlib库完成二叉树的层次遍历并将其可视化: ```python import matplotlib.pyplot as plt from collections import deque, defaultdict class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def level_order_traversal(root): result = [] queue = deque([root]) while queue: node = queue.popleft() if node: result.append(node.val) queue.append(node.left) queue.append(node.right) return result def visualize_tree(root): levels = defaultdict(list) current_level = 0 queue = deque([(root, current_level)]) while queue: node, level = queue.popleft() if node: levels[level].append(str(node.val)) queue.append((node.left, level + 1)) queue.append((node.right, level + 1)) max_level = max(levels.keys()) fig, ax = plt.subplots(figsize=(8, (max_level + 1) * 2)) for i in range(max_level + 1): y = -(i ** 1.5) # Adjust spacing between levels x_spacing = 1 / (2 ** i) for j, value in enumerate(levels[i]): x = (j + 0.5) * x_spacing - 0.5 circle = plt.Circle((x, y), radius=0.1, color='blue') ax.add_artist(circle) ax.text(x, y, value, ha='center', va='center', color='white') ax.set_xlim(-1, 1) ax.axis('off') plt.show() # 构建一棵简单的二叉树 tree_root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)), TreeNode(3, None, TreeNode(7))) visualize_tree(tree_root) ``` 上述代码实现了二叉树的层次遍历,并利用`matplotlib`绘制出每一层的节点分布情况[^2]。这种方法不仅适用于基本的二叉树结构,还可以扩展到其他类型的树形结构上。 #### 3. 完全二叉树的特殊处理 当涉及到完全二叉树时,除了常规的层次遍历外,还需要注意一些特殊的性质。例如,在某些场景下可能需要将遍历结果转换为数组形式以便进一步分析或存储[^3]。这种情况下可以直接使用标准库中的`vector`或其他动态数组类的数据结构来进行管理。 #### 4. 推荐使用的工具 - **Graphviz**: 提供强大的图论支持功能,适合用来生成高质量的静态图片文件表示各种各样的网络拓扑结构。 - **D3.js**: 如果希望创建交互式的Web端应用,则可以选择JavaScript框架如D3.js来开发自定义UI组件。 - **Matplotlib/Seaborn**: 对于快速原型设计阶段来说非常方便实用;它们允许用户轻松调整参数从而获得满意的视觉效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值