zoukankan      html  css  js  c++  java
  • 遍历二叉树

    之前学过利用递归实现BFS二叉树搜索(http://www.cnblogs.com/webor2006/p/7262773.html),这次学习利用队列(Queue)来实现,关于什么时BFS这里不多说了,先贴张图来直观回忆下:

    实现一个队列【采用数组实现】:

    这时同样采用模版技术可以往队列中去放任何类型的数据,而这个队列同样是声明在头文件中,以便在需要用到队列的地方去随时包含它,下面先来定个初步框架:

    /**
    * 利用数组来实现队列 
    */
    
    template <typename T>
    
    class queue
    {
        T* data;//用数组来实现队列
        int head/* 头指向的位置 */, tail/* 尾指向的位置 */, size/* 当前队列存放的元素个数 */, data_length/* 总队列的大小 */;
    public:
        queue(int length):head(0), tail(0), size(0), data_length(length) {
            data = new T[length];
        }
        
        //入队列
        void push(T value) {
    
        }
    
        //出队列
        void pop() {
    
        }
    
        //取出队列最早的元素
        T top() {
    
        }
    
        //判断队列是否为空
        bool isEmpty() {
    
        }
    };

    具体实现如下:

    /**
    * 利用数组来实现队列 
    */
    
    template <typename T>
    
    class queue
    {
        T* data;//用数组来实现队列
        int head/* 头指向的位置 */, tail/* 尾指向的位置 */, size/* 当前队列存放的元素个数 */, data_length/* 总队列的大小 */;
    public:
        queue(int length):head(0), tail(0), size(0), data_length(length) {
            data = new T[length];
        }
        
        //入队列
        void push(T value) {
            if(size == data_length) {
                throw "queue is full";//如果队列已经满了则直接抛异常,实际可以去将数组扩容,这里简单处理,重在学习数据结构
            }
            data[head] = value;
            head = (head + 1) % data_length;//这是为了循环利用,如果队列还有空间的话
            size++;
        }
    
        //出队列
        void pop() {
            if(isEmpty()) {
                throw "queue is empty";
            }
            tail = (tail + 1) % data_length;//这是为了循环利用
            size--;
        }
    
        //取出队列最早的元素
        T top() {
            if(isEmpty())
                throw "You cannot get the top element from an empty queue";
            return data[tail];
        }
    
        //判断队列是否为空
        bool isEmpty() {
            return size == 0;
        }
    };

    这里先来使用一下它,看入队跟出队的结果是否如预期:

    编译运行:

    对于上面的写法下面用图来将其整个过程画出来:

    ①、

    创建一个大小为3的队列,其中head、tail指向数组0的位置,其中目前是一个size=0空数组

    ②、

    往队列中插入元素1: 

    ③、

    往队列中插入元素2:

    ④、

    往队列中插入元素3,这里需要注意啦!!!head会循环利用,指向数组0的位置:

    ⑤、

    根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:

    ⑥、

    根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:

    ⑦、

    根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:

    这时注意啦!!!tail跟head一样也会循环利用,又回到index=0的位置了:

    ⑧、

    由于此时size=0了,所以会打印出"queue is empty"。

    ⑨、

    ⑩、

    ⑪、

    由于此时size=0了,所以会打印出"queue is empty"。
    总结

    1、添加元素放到head处,添加完成之后将head+1以便下次进行存放。

    2、拿元素时是从tail处拿,拿完之后也是将tail+1以便拿下一个元素,因为是先进先出原则。 

    基于上节的实现来利用队列实现二叉树的BFS遍历:

    先贴一下上节的代码,基于这个二叉树利用队列去实现:

    #include <iostream>
    #include "stack.h"
    #include "queue.h"
    
    //用来表示二叉树
    struct treenode{
        int data;
        treenode* left;//左结点
        treenode* right;//右结点
        treenode(int value):data(value), left(nullptr), right(nullptr){}
    };
    
    //前序遍历
    void pre_order(treenode* root){
        Stack<treenode*> stack;//声明一个栈
        treenode* current_node = root;
        while(current_node) {
            //1、首先打印当前结点,因为是前序遍历
            std::cout << current_node->data << std::endl;
            //2、如果存在右结点则将其入栈暂存,待左结点输出完之后再去处理这些右结点
            if(current_node->right) stack.push(current_node->right);
            //3、不断去处理左结点,直到左结点处理完了,则从栈中拿右点进行处理
            if(current_node->left)//如果有左结点,则将它做为当前处理的结点不断输出
                current_node = current_node->left;
            else {
                //这时左结点已经处理完了
                if(stack.isEmpty())//如果缓存栈已经为空了则说明整个二叉树的遍历结束了
                    current_node = nullptr;
                else {
                    //则取出栈顶的右结点进行处理,由于是后进先出,所以拿出来的永远是最新插入的右结点
                    current_node = stack.top();
                    stack.pop();//将其元素从栈顶弹出
                }
    
            }
        }
    }
    
    //利用队列实现BFS
    void level_order(treenode* root){
        //TODO
    }
    
    int main(void) {
    
        //构建二叉树:
        //1、第一层根结点
        treenode* root = new treenode(5);
        //2、第二层结点
        root->left = new treenode(3);
        root->right = new treenode(8);
        //3、第三层结点
        root->left->left = new treenode(1);
        root->left->right = new treenode(4);
        root->right->left = new treenode(7);
        //4、第四层结点
        root->right->left->left = new treenode(6);
    
        pre_order(root);
    
        std::cout << "##################" << std::endl;
    
        level_order(root);
    
        return 0;
    }

    其二叉树为:

    下面具体来实现level_order:

    只要理解的队列的先进先出的特点上面的实现比较容易理解,不多解释,编译运行:

    下面看一下它的时间复杂度:由于队列中有多少元素就会遍历多次次,所以很明显是O(n)。

  • 相关阅读:
    null in ABAP and nullpointer in Java
    SAP ABAP SM50事务码和Hybris Commerce的线程管理器
    Hybris service layer和SAP CRM WebClient UI架构的横向比较
    SAP ABAP和Linux系统里如何检查网络传输的数据量
    SAP CRM WebClient UI和Hybris的controller是如何被调用的
    SAP CRM和Cloud for Customer订单中的业务伙伴的自动决定机制
    SAP CRM WebClient UI和Hybris CommerceUI tag的渲染逻辑
    SAP BSP和JSP页面里UI元素的ID生成逻辑
    微信jsapi支付
    微信jsapi退款操作
  • 原文地址:https://www.cnblogs.com/webor2006/p/7444197.html
Copyright © 2011-2022 走看看