二叉树

一个100行的代码调试都可能会让程序员遇到很多挫折,所以,面对挫折,我们永远不能低头。

这段时间在代码随想录里学习了二叉树相关知识,并整理成c++代码(采用类的方式定义二叉树)

想掌握二叉树概念,可参考青岛大学王卓老师的课程、51CTO学院的鲍老师课程、代码随想录以及其他博客,建议详细阅读代码随想录,五星推荐

本次学习的内容包含如下功能,算是对二叉树学习的一个功能总结,对自己学习过程的一个交代

阅读前必知必会:

 

本程序命名方式定义如下:
1、类名:以大写字母开头,每个单词首字母大写,无下划线
2、函数名:以小写字母开头,每个单词首字母大写,无下划线
3、变量名:
        普通变量:变量名一律小写,单词间以下划线相连
        类的成员变量:以m_开头,变量名一律小写,单词间以下划线相连
        全局变量:没有特殊要求,尽量少用,可以加上前缀g_以与局部变量区分

二叉树部分代码未来需要重构,将部分遍历方式整合在一个函数里,通过形参指定执行某个遍历方式,减少代码的重复性

 

功能:

 *     递归中序遍历
 *          递归后序遍历
 *          迭代前序遍历
 *          迭代中序遍历
 *          迭代后续遍历
 *          层序遍历
 *          递归反转二叉树
 *          层序遍历反转二叉树
 *          深度遍历反转二叉树
 *          判断是否对称二叉树
未来计划:  
*   追加测试用例
*   继续追加二叉树的功能函数
*      将代码封装成静态库和动态库
*   
代码如下:
 
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
enum SelectTravesal
{
    PreRecur,
    InRecur,
    PostRecur,
    PreIter,
    InIter,
    PostIter,
    levelIter
};

/**
 * @brief   定义树的节点
 * @param   m_val     vector
 * @param   m_left    该节点的左指针域,用来指向其左孩子节点 
 * @param   m_right   该节点的右指针域,用来指向其右孩子节点
 * @note    为编写代码方便,成员变量的访问权限都设置为public,严格来说应该设置为private
 *          当声明为private时,需要声明相应的友元类或友元方法,并提供相应的get set方法, 读者可自行修改锻炼c++基本功
 * @author  weihf
 */
class TreeNode
{
public:
    int m_val;
    TreeNode* m_left;
    TreeNode* m_right;
public:
    TreeNode(int x) : m_val(x), m_left(NULL), m_right(NULL)
    {}
};

/**
 * @brief   定义一颗二叉树树,其构造函数用来初始化一颗二叉树(使用数组来构造二棵树)
 * @param   m_root     二叉树的根节点
 * @note    为编写代码方便,成员变量的访问权限都设置为public,严格来说应该设置为private
 *          当声明为private时,需要声明相应的友元类或友元方法,并提供相应的get set方法, 读者可自行修改锻炼c++基本功
 * @method  
 *          recurPreTraversal   递归前序遍历
 *          递归中序遍历
 *          递归后序遍历
 *          迭代前序遍历
 *          迭代中序遍历
 *          迭代后续遍历
 *          层序遍历
 *          递归反转二叉树
 *          层序遍历反转二叉树
 *          深度遍历反转二叉树
 *          判断是否对称二叉树
 * @author weihf
 */
class Tree
{
public:
    TreeNode* m_root;
public:
    Tree(const vector<int> &vec);
   // ~Tree();
public:
    void recurPreTraversal(TreeNode* node, vector<int> &result);    // 递归前序遍历
    void recurInTraversal(TreeNode* node, vector<int> &result);     // 递归中序遍历
    void recurPostTraversal(TreeNode* node, vector<int> &result);   // 递归后序遍历
    void preorderTraversal(TreeNode* node, vector<int> &result);    // 迭代前序遍历
    void inorderTraversal(TreeNode* node, vector<int> &result);     // 迭代中序遍历
    void postorderTraversal(TreeNode* node, vector<int> &result);   // 迭代后续遍历
    void uniTravesal(TreeNode* node, vector<int> &result);          // 统一迭代遍历 包含三种写法:中左右 左中右 左右中
    void levelTravesal(TreeNode* node, vector<int> &result);        // 迭代层序遍历
public:
    void recurReverseTree(TreeNode* node);                          // 递归反转二叉树,包含三种写法:中左右 左中右 左右中。这里采用的是左右中,也可以采用中左右,但不能采用左中右遍历,否则会导致原本的左孩子节点反转两次(可以改写成左中左)
    void levelReverseTree(TreeNode* node);                          // 层序遍历反转二叉树
    void depthReverseTree(TreeNode* node);                          // 深度遍历反转二叉树 采用的方法是普通前序遍历,也可以采用统一迭代遍历:中左右 左中右 左右中(后续再补充 todo)
public:
    bool isSymmetricalTree(TreeNode* node);                         // 递归判断是否对称二叉树
    bool isSymmetricalTreeQueue(TreeNode* node);                    // 使用队列判断是否是对称二叉树
    bool isSymmetricalTreeStack(TreeNode* node);                    // 使用栈判断是否是对称二叉树
    bool isSameTree(TreeNode* p, TreeNode* q);                      // 判断两个树是不是相同
    bool isSubtree(TreeNode* root, TreeNode* subRoot);              // 判断subroot是不是子树
public:
    int getTreeDepth();                                             // 迭代求本二叉树的深度
    int recurGetTreeDepth();                                        // 递归求本二叉树的深度 二叉树深度:到根节点的最大距离 中左右
    int recurGetTreeHeight();                                       // 递归求本二叉树的高度 二叉树高度:到最远叶子节点的最大距离 左右中
    
};

/**
 * @brief Construct a new Tree:: Tree object
 * @param vec 用来构造二叉树的数组
 * @note 如果父节点的数组下标是i,那么它的左孩子下标就是i * 2 + 1,右孩子下标就是 i * 2 + 2。
 */
Tree::Tree(const vector<int> &vec)
{   
    vector<TreeNode*> vecTree (vec.size(), NULL);
    
    // 把输入数值数组,先转化为二叉树节点数组
    for (int i = 0; i < vec.size(); i++) {
        TreeNode* node = NULL;
        if (vec[i] != -1) node = new TreeNode(vec[i]); // 用 -1 表示null
        vecTree[i] = node;
        if (i == 0) m_root = node;
    }
    // 遍历一遍,根据规则左右孩子赋值就可以了
    // 注意这里 结束规则是 i * 2 + 2 < vec.size(),避免空指针
    for (int i = 0; i * 2 + 1 < vec.size(); i++) {
        if (vecTree[i] != NULL) {
            // 线性存储转连式存储关键逻辑
            vecTree[i]->m_left = vecTree[i * 2 + 1];
            if(i * 2 + 2 < vec.size())
                vecTree[i]->m_right = vecTree[i * 2 + 2];
        }
    }

}

void Tree::recurPreTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    result.push_back(node->m_val);
    recurPreTraversal(node->m_left, result);
    recurPreTraversal(node->m_right, result);
}

void Tree::recurInTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    recurInTraversal(node->m_left, result);
    result.push_back(node->m_val);
    recurInTraversal(node->m_right, result);
}

void Tree::recurPostTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    recurPostTraversal(node->m_left, result);
    recurPostTraversal(node->m_right, result);
    result.push_back(node->m_val);
}

void Tree::preorderTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    stack<TreeNode*> st;
    st.push(node);
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        result.push_back(cur->m_val);
        if(cur->m_right)
        {
            st.push(cur->m_right);
        }
        if(cur->m_left)
        {
            st.push(cur->m_left);
        }
    }
}

void Tree::inorderTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    stack<TreeNode*> st;
    TreeNode* cur = node;
    while(cur != NULL || !st.empty())
    {
        if(cur != NULL)
        {
            st.push(cur);
            cur = cur->m_left;
        }
        else
        {
            cur = st.top();
            result.push_back(cur->m_val);
            st.pop();
            cur = cur->m_right;
        }
    }
}

void Tree::postorderTraversal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    stack<TreeNode*> st;
    st.push(node);
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        result.push_back(cur->m_val);
        if(cur->m_left)
            st.push(cur->m_left);
        if(cur->m_right)
            st.push(cur->m_right);
    }
    reverse(result.begin(), result.end());
}

void Tree::uniTravesal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    stack<TreeNode*> st;
    st.push(node);
    // 前序遍历
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        if(cur != NULL)
        {
            if(cur->m_right)
                st.push(cur->m_right);      // 右
            if(cur->m_left)
                st.push(cur->m_left);       // 左
            st.push(cur);                   // 中
            st.push(NULL);
        }
        else
        {
            result.push_back(st.top()->m_val);
            st.pop();
        }
    }
    /*
    // 中序遍历
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        if(cur != NULL)
        {
            if(cur->m_right)
                st.push(cur->m_right);      // 右
            st.push(cur);                   // 中
            st.push(NULL);
            if(cur->m_left)
                st.push(cur->m_left);       // 左
            
        }
        else
        {
            result.push_back(st.top()->m_val);
            st.pop();
        }
    }
    */

    /*
    // 后序遍历
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        if(cur != NULL)
        {
            st.push(cur);                   // 中
            st.push(NULL);
            if(cur->m_right)
                st.push(cur->m_right);      // 右
            if(cur->m_left)
                st.push(cur->m_left);       // 左
            
        }
        else
        {
            result.push_back(st.top()->m_val);
            st.pop();
        }
    }
    */
}

void Tree::levelTravesal(TreeNode* node, vector<int> &result)
{
    if(node == NULL)
        return;
    queue<TreeNode*> que;
    que.push(node);
    while(!que.empty())
    {
        TreeNode* cur = que.front();
        que.pop();
        result.push_back(cur->m_val);
        if(cur->m_left)
            que.push(cur->m_left);
        if(cur->m_right)
            que.push(cur->m_right);
    }
}

void Tree::recurReverseTree(TreeNode* node)
{
    if(node == NULL)
        return;
    recurReverseTree(node->m_left);        // 左
    recurReverseTree(node->m_right);       // 右
    swap(node->m_left, node->m_right);     // 中
    
    /*
    swap(node->m_left, node->m_right);     // 中
    recurReverseTree(node->m_left);        // 左
    recurReverseTree(node->m_right);       // 右
        
    */

    /*

    recurReverseTree(node->m_left);        // 左
    swap(node->m_left, node->m_right);     // 中
    recurReverseTree(node->m_left);        // 右,其实是左,因为先递归当前节点左子树导致左子树节点全部反转,再swap当前节点的左右子树,
                                           // 导致当前节点已经经过反转的左子树反转成右子树了,当前节点还没反转的右子树变成当前节点的左子树了
                                           // 若此时还反转当前节点的右子树,相当于把原来的左子树又递归反转了一遍,而原来的右子树反而得不到反转

    */
}

void Tree::levelReverseTree(TreeNode* node)
{
    if(node == NULL)
        return;
    queue<TreeNode*> que;
    que.push(node);
    while(!que.empty())
    {
        TreeNode* cur = que.front();
        que.pop();
        swap(cur->m_left, cur->m_right);
        if(cur->m_left)
            que.push(cur->m_left);
        if(cur->m_right)
            que.push(cur->m_right);
    }
}

void Tree::depthReverseTree(TreeNode* node)
{
    if(node == NULL)
        return;
    stack<TreeNode*> st;
    st.push(node);
    while(!st.empty())
    {
        TreeNode* cur = st.top();
        st.pop();
        swap(cur->m_left, cur->m_right);
        if(cur->m_right)
            st.push(cur->m_right);
        if(cur->m_left)
            st.push(cur->m_left);
    }
}

bool recurIsSymmetricalTree(TreeNode* left, TreeNode* right)
{
    if(left == NULL && right == NULL)
        return true;
    if(left == NULL && right != NULL)
        return false;
    if(left != NULL && right == NULL)
        return true;
    if(left->m_val != right->m_val)
        return false;
    bool outside = recurIsSymmetricalTree(left->m_left, right->m_right);
    bool inside = recurIsSymmetricalTree(left->m_right, right->m_left);
    return outside && inside;
}
//左节点的左孩子 = 右节点的右孩子
//左节点的右孩子 = 右节点的左孩子
bool Tree::isSymmetricalTree(TreeNode* node)
{
    if(node == NULL)
    {
        return true;
    }
    return recurIsSymmetricalTree(node->m_left, node->m_right);
       
}

bool Tree::isSymmetricalTreeQueue(TreeNode* node)
{
    if(node == NULL)
    {
        return true;
    }
    queue<TreeNode*> que;
    que.push(node->m_left);
    que.push(node->m_right);
    while(!que.empty())
    {
        TreeNode* left = que.front();
        que.pop();
        TreeNode* right = que.front();
        que.pop();
        if(left == NULL && right == NULL)
        {
            continue;
        }
        else if(left == NULL && right != NULL)
        {
            return false;
        }          
        else if(left != NULL && right == NULL)
        {
            return false;
        }
        else if(left->m_val != right->m_val)
        {
            return false;
        }
        que.push(left->m_left);
        que.push(right->m_right);
    
        que.push(left->m_right);
        que.push(right->m_left);  
    }
    return true;
}

bool Tree::isSymmetricalTreeStack(TreeNode* node)
{
    if(node == NULL)
    {
        return true;
    }
    stack<TreeNode*> st;
    st.push(node->m_right);
    st.push(node->m_left);
    while(!st.empty())
    {
        TreeNode* left = st.top();
        st.pop();
        TreeNode* right = st.top();
        st.pop();
        if(left == NULL && right == NULL)
        {
            continue;
        }
        else if(left == NULL && right != NULL)
        {
           return false;
        }          
        else if(left != NULL && right == NULL)
        {
            return false;
        }
        else if(left->m_val != right->m_val)
        {
            return false;
        }
         
        st.push(right->m_right);
        st.push(left->m_left);
    
        st.push(right->m_left);
        st.push(left->m_right);
    }
    return true;
}

bool Tree::isSameTree(TreeNode* p, TreeNode* q)
{
    stack<TreeNode*> que;
    que.push(p);
    que.push(q);
    while(!que.empty())
    {
        TreeNode* left = que.top();
        que.pop();
        TreeNode* right = que.top();
        que.pop();
        if(left == NULL && right == NULL)
            continue;
        if(left == NULL && right != NULL)
            return false;
        if(left != NULL && right == NULL)
            return false;
        if(left->m_val != right->m_val)
            return false;
        que.push(left->m_left);
        que.push(right->m_left);
        que.push(left->m_right);
        que.push(right->m_right);
    }
    return true;
}

bool Tree::isSubtree(TreeNode* root, TreeNode* subRoot) 
{
    if(root == NULL)
    {
        if(isSameTree(root, subRoot) == true)
            return true;
        return false;
    }
    queue<TreeNode*> que;
    que.push(root);
    while(!que.empty())
    {
        TreeNode* node = que.front();
        que.pop();
        if(isSameTree(node, subRoot) == true)
            return true;
        if(node->m_left)
        {
            que.push(node->m_left);
        }
        if(node->m_right)
        {
            que.push(node->m_right);
        }


    }
    return false;
}

int Tree::getTreeDepth()
{
    if(m_root == NULL)
        return 0;
    queue<TreeNode*> que;
    int result = 0;
    que.push(m_root);
    while(!que.empty())
    {
        int size = que.size();
        for(int i=0; i<size; i++)
        {
            TreeNode* node = que.front();
            que.pop();
            if(node->m_left)
                que.push(node->m_left);
            if(node->m_right)
                que.push(node->m_right);
        }
        
        result++;

    }
    return result;
}

void GetTreeDepthByRecur(TreeNode* node, int &result, int depth)
{
    result = depth > result ? depth : result;
    if(node->m_left == NULL && node->m_right == NULL)
        return;
    if(node->m_left)
    {
        GetTreeDepthByRecur(node->m_left, result, depth++);
    }
    if(node->m_right)
    {
        GetTreeDepthByRecur(node->m_right, result, depth++);
    }
}

int Tree::recurGetTreeDepth()
{
    int result = 0;
    if(m_root == NULL)
        return result;
    GetTreeDepthByRecur(m_root, result, 1);
    return result;
}

int GetTreeHeightByRecur(TreeNode* node)
{
    if(node == NULL)
        return 0;
    int left = GetTreeHeightByRecur(node->m_left);       // 左
    int right = GetTreeHeightByRecur(node->m_right);     // 右
    int height = max(left, right) + 1;                  // 中
    return height;
}

int Tree::recurGetTreeHeight()
{
    return GetTreeHeightByRecur(m_root);
}

void printTravesalTree(vector<int> &vec, const string &s)
{
    cout << s << endl;
    for(auto v : vec)
    {
        cout << v << " ";
    }
    cout << endl;
    vec.clear();
}

void isSymmetricalTreePrint(bool flag)
{
    if(flag)
        cout << "这是一颗对称二叉树"<<endl;
    else
        cout<< "这不是一颗对称树" <<endl;
}

void isSubTreePrint(bool flag)
{
    if(flag)
        cout << "这是父子树关系"<<endl;
    else
        cout<< "这不是父子树关系" <<endl;
}

int main()
{
   // vector<int> vec = {30,36,21,36,35,26,15,-1, -1, -1, 33, -1, -1, -1, 8};
   // vector<int> vec1 = {4, 2, 7, 1, 3, 6, 9};
    vector<int> vec = {1, 2, 2, 3, 4, 4, 3, 5, 6, -1, -1, -1, -1, 6, 5};
    vector<int> result;
    Tree tree(vec);
    Tree tree1(vec);
    tree.recurPreTraversal(tree.m_root, result);
    printTravesalTree(result, "递归前序遍历结果");
   
    tree.recurInTraversal(tree.m_root, result);
    printTravesalTree(result, "递归中序遍历结果");

    tree.recurPostTraversal(tree.m_root, result);
    printTravesalTree(result, "递归后序遍历结果");

    tree.preorderTraversal(tree.m_root, result);
    printTravesalTree(result, "迭代前序遍历结果");

    tree.inorderTraversal(tree.m_root, result);
    printTravesalTree(result, "迭代中序遍历结果");

    tree.postorderTraversal(tree.m_root, result);
    printTravesalTree(result, "迭代后序遍历结果");

    tree.uniTravesal(tree.m_root, result);
    printTravesalTree(result, "统一迭代遍历结果");

    tree.levelTravesal(tree.m_root, result);
    printTravesalTree(result, "层序遍历结果");

    tree.recurReverseTree(tree.m_root);
    tree.levelTravesal(tree.m_root, result);
    printTravesalTree(result, "递归反转二叉树结果");

    tree.levelReverseTree(tree.m_root);
    tree.levelTravesal(tree.m_root, result);
    printTravesalTree(result, "层序遍历反转二叉树结果");

    tree.depthReverseTree(tree.m_root);
    tree.levelTravesal(tree.m_root, result);
    printTravesalTree(result, "深度遍历反转二叉树结果");

    isSymmetricalTreePrint(tree.isSymmetricalTree(tree.m_root));
    isSymmetricalTreePrint(tree.isSymmetricalTreeQueue(tree.m_root));
    isSymmetricalTreePrint(tree.isSymmetricalTreeStack(tree.m_root));

    isSubTreePrint(tree.isSameTree(tree.m_root, tree1.m_root));
    isSubTreePrint(tree.isSameTree(tree.m_root, tree1.m_root));

    cout << tree.getTreeDepth() <<endl;
    cout << tree.recurGetTreeDepth() <<endl;

    cout << tree.recurGetTreeHeight() <<endl;
    return 0;
}

  

posted @ 2022-01-11 22:05  念经似的zzz  阅读(44)  评论(0编辑  收藏  举报