• 二叉树基本概念


    基本概念


    • Binary Tree

    CLRS

          We define binary trees recursively. A binary tree T is a structure defined on a finite set of nodes that either contains no nodes or is composed of three disjoint sets of nodes: a root node, a binary tree called its left subtree, and a binary tree called its right subtree.

          我们可以递归地来定义二叉树二叉树是一个定义在有限结点集上的数据结构,它要么不包含任何结点,要么包含三个不相交的结点集合 - 一个结点,一棵称为左子树二叉树,以及一棵称为右子树二叉树

    Wikipedia

          In computer science, a binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child. A recursive definition using just set theory notions is that a (non-empty) binary tree is a triple (L, S, R), where L and R are binary trees or the empty set and S is a singleton set. Some authors allow the binary tree to be the empty set as well.

          在计算机科学中,二叉树是一种树形的数据结构,它的每个结点最多拥有两个孩子,这两个孩子一般被称为左子树右子树。一种使用集合理论观点的递归定义是:一棵(非空)二叉树是一个三元集合(L,S,R),其中L和R要么是二叉树结点集合,要么是空结点集和;S为单元素结点集和。一些著作中允许一棵二叉树为一个空结点集。

    • Full Binary Tree 

     CLRS

          The tree that results is a full binary tree: each node is either a leaf or has degree exactly 2.

          这样得到的树是"full binary tree":每个结点要么是叶节点,要么度为2。

     Wikipedia

           full binary tree (sometimes proper binary tree or 2-tree or strictly binary tree) is a tree in which every node other than the leaves has two children.

           一棵"full binary tree"是每个非叶结点均拥有2个孩子的二叉树。

     注意点

           这里定义的"full binary tree"并不能翻译成满二叉树,它的定义与国内约定俗成的满二叉树是不一致的。国内所谓的满二叉树其实与"perfect binary tree"的定义是一致的。

    • Perfect Binary Tree 

      CLRS

          A complete k-ary tree is a k-ary tree in which all leaves have the same depth and all internal nodes have degree k.

          满k叉树(这里的complete应该翻译为“完整的”)是一棵所有叶节点深度相同且所有内部结点度为k的k叉树。

     Wikipedia

          A perfect binary tree is a full binary tree in which all leaves are at the same depth or same level, and in which every parent has two children. 

          满二叉树是一棵"full binary tree",它的所有叶子结点深度相同,并且每个父亲结点度均为2。

     注意点

          《算法导论》中的"complete binary tree"和维基百科中的"perfect binary tree"与国内满二叉树的定义是一致的。

    • Complete Binary Tree 

     Wikipedia

          A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.

          完全二叉树是一棵这样的二叉树:除最后一层外,每一层上的节点数均达到最大值,并且最后一层的叶子结点尽可能地朝左排列。

    二叉树的遍历


          从二叉树递归定义可知:一棵非空的二叉树由结点和右子树三个基本部分组成。在任一给定结点上,可以按某种次序执行这三个操作:

          访问该结点本身(N)

          遍历该结点的左子树(L)

          遍历该结点的右子树(R)

            我们将二叉树中的结点定义为如下结构类型:

    struct KBTreeNode
    {
        int         m_nData;
        KBTreeNode *m_pLeft;
        KBTreeNode *m_pRight;
    
        KBTreeNode()          : m_nData(0),     m_pLeft(0), m_pRight(0) {}
        KBTreeNode(int nData) : m_nData(nData), m_pLeft(0), m_pRight(0) {}
    };

    • NLR(先序遍历)

          先序遍历:访问结点的操作发生在遍历其左右子树之前。先序遍历首先访问结点,然后遍历左子树,最后遍历右子树。在遍历右子树时,仍然遵循先访问结点,然后遍历左子树,最后遍历右子树的规则。

     递归算法

    void g_PreorderTraversal(KBTreeNode *pNode)
    {
        if (!pNode)
            return;
    
        std::cout << pNode->m_nData << std::endl;
        g_PreorderTraversal(pNode->m_pLeft);
        g_PreorderTraversal(pNode->m_pRight);
    }

     非递归算法

    void g_PreorderTraversal(KBTreeNode *pNode)
    {
        std::stack<KBTreeNode *> s;
    
        if (!pNode)
            return;
    
        s.push(pNode);
    
        while (!s.empty())
        {
            KBTreeNode *p = s.top(); s.pop();
    
            std::cout << p->m_nData << std::endl;
    
            if (p->m_pRight) s.push(p->m_pRight);
            if (p->m_pLeft ) s.push(p->m_pLeft );
        }
    }

    LNR(中序遍历)

          中序遍历:访问结点的操作发生在遍历其左右子树之中。中序遍历首先遍历左子树,然后访问结点,最后遍历右子树。在遍历右子树时,仍然遵循先遍历左子树,然后访问结点,最后遍历右子树的规则。

     递归算法

    void g_InorderTraversal(KBTreeNode *pNode)
    {
        if (!pNode)
            return;
    
        g_InorderTraversal(pNode->m_pLeft);
        std::cout << pNode->m_nData << std::endl;
        g_InorderTraversal(pNode->m_pRight);
    }

     非递归算法

    void g_InorderTraversal(KBTreeNode *pNode)
    {
        std::stack<KBTreeNode *> s;
    
        if (!pNode)
            return;
    
        s.push(pNode);
    
        while (!s.empty())
        {
            while (s.top()->m_pLeft)
            {
                s.push(s.top()->m_pLeft);
            }
    
            while (!s.empty())
            {
                KBTreeNode *p = s.top(); s.pop();
                std::cout << p->m_nData << std::endl;
    
                if (p->m_pRight)
                {
                    s.push(p->m_pRight);
                    break;
                }
            }
        }
    }

    LRN(后序遍历)

          后序遍历:访问结点的操作发生在遍历其左右子树之后。后序遍历首先遍历左子树,然后遍历右子树,最后访问结点。在遍历右子树时,仍然遵循先遍历左子树,然后遍历右子树,最后访问结点的规则。

     递归算法

    void g_PostorderTraversal(KBTreeNode *pNode)
    {
        if (!pNode)
            return;
    
        g_PostorderTraversal(pNode->m_pLeft);
        g_PostorderTraversal(pNode->m_pRight);
        std::cout << pNode->m_nData << std::endl;
    }

      非递归算法

    void g_PostorderTraversal(KBTreeNode *pNode)
    {
        std::stack<KBTreeNode *> s;
        KBTreeNode *pCurNode = NULL;                                        // 当前访问的结点
        KBTreeNode *pPreNode = NULL;                                        // 上次访问的结点
    
        if (!pNode)
            return;
    
        s.push(pNode);
    
        while (!s.empty())
        {
            pCurNode = s.top();
    
            if ((!pCurNode->m_pLeft && !pCurNode->m_pRight) ||
                (pPreNode && (pPreNode == pCurNode->m_pLeft || pPreNode == pCurNode->m_pRight)))
            { // 如果当前结点没有孩子结点或者孩子节点都已被访问过
                std::cout << pCurNode->m_nData << std::endl;
                s.pop();
                pPreNode = pCurNode;
                continue;
            }
    
            if (pCurNode->m_pRight)
            {
                s.push(pCurNode->m_pRight);
            }
    
            if (pCurNode->m_pLeft)
            {
                s.push(pCurNode->m_pLeft);
            }
        }
    }
  • 相关阅读:
    CI框架(Codeigniter)总结
    ssh自动下载SFTP文件
    数据库设计原则
    Java代码性能优化的 39个细节
    quartz定时任务时间设置
    Myeclipse 反编译工具插件
    Maven -- 使用Myeclipse创建Maven项目
    详解Java Web项目启动执行顺序
    java web项目下的lib和build path 中jar包问题解惑
    java读取存在src目录下和存在同级目录下的配置文件
  • 原文地址:https://www.cnblogs.com/heartchord/p/4680588.html
Copyright © 2020-2023  润新知