[C++]封装二叉树(附例题)

[C++]封装二叉树

题目要求

(简单的说,就是把二叉树的功能封装起来)

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.

Three Constructor:

creat a tree by copy.

creat a tree by a array.(using BFS)

creat a tree by preorder and inorder.

Methods:

clear: clear the tree.

copyTree: input old tree root and new tree root, copy get a new tree.

Static Methods:

three way to search tree.

测试文件:

#include <iostream>
#include "BinaryTree.hpp"

using namespace std;

void print(BinaryTree::Node * temp) {
    cout << temp->val << " ";
}

std::vector<char> pre;
std::vector<char> in;

void getPreOrder(BinaryTree::Node * temp) {
    pre.push_back(temp->val);
}

void getInOrder(BinaryTree::Node * temp) {
    in.push_back(temp->val);
}

void testTree() {
    cout << "test Tree" << endl;
    int n = 1;
    std::vector<char> tree;
    cin >> n;
    while (n--) {
        char temp = ‘\0‘;
        cin >> temp;
        tree.push_back(temp);
    }

    BinaryTree x = BinaryTree(tree);

    BinaryTree::preOrder(print, x.getRoot());
    cout << endl;
    BinaryTree::inOrder(print, x.getRoot());
    cout << endl;
    BinaryTree::postOrder(print, x.getRoot());
    cout << endl;

    BinaryTree::preOrder(getPreOrder, x.getRoot());
    BinaryTree::inOrder(getInOrder, x.getRoot());

    BinaryTree t = BinaryTree(pre, in);
    BinaryTree::postOrder(print, t.getRoot());
    cout << endl;

    BinaryTree y = BinaryTree(t);

    BinaryTree::preOrder(print, y.getRoot());
    cout << endl;
    BinaryTree::inOrder(print, y.getRoot());
    cout << endl;
    BinaryTree::postOrder(print, y.getRoot());

    BinaryTree::preOrder(getPreOrder, y.getRoot());
    BinaryTree::inOrder(getInOrder, y.getRoot());
}

int main() {
    testTree();
}

接口文件:

//
//  BinaryTree.hpp
//  C++
//
//  Created by 李天培 on 16/5/4.
//  Copyright ? 2016年 lee. All rights reserved.
//

#ifndef BinaryTree_hpp
#define BinaryTree_hpp

#include <iostream>
#include <vector>
#include <queue>
#include <stack>

#define EMPTY_ELE ‘#‘

class BinaryTree {
public:
    struct Node {
        char val;
        Node* left;
        Node* right;
        Node(char v, Node* l = NULL, Node* r = NULL):
        val(v), left(l), right(r) {
        }
    };
    BinaryTree(const BinaryTree&);
    BinaryTree(std::vector<char>&);
    // created by preorder and inorder
    BinaryTree(const std::vector<char>& preOrder,
               const std::vector<char>& inOrder);
    ~BinaryTree();

    Node* getRoot() const;
    void clear();

    static void preOrder(void (*visite)(BinaryTree::Node*), Node*);
    static void inOrder(void (*visite)(BinaryTree::Node*), Node*);
    static void postOrder(void (*visite)(BinaryTree::Node*), Node*);

private:
    Node * copyNode(Node * oldNode, Node * newNode);

    Node * root;
};

#endif /* BinaryTree_hpp */

问题分析

先来讨论相对简单的访问二叉树问题。

遍历问题

前(先)序遍历

中序遍历

后序遍历

代码实现:

void BinaryTree::preOrder(void (*visite)(BinaryTree::Node *),
                          BinaryTree::Node * treeNode) {
    if (treeNode != NULL) {
        visite(treeNode);
        preOrder(visite, treeNode->left);
        preOrder(visite, treeNode->right);
    }
}
void BinaryTree::inOrder(void (*visite)(BinaryTree::Node *),
                         BinaryTree::Node * treeNode) {
    if (treeNode != NULL) {
        inOrder(visite, treeNode->left);
        visite(treeNode);
        inOrder(visite, treeNode->right);
    }
}
void BinaryTree::postOrder(void (*visite)(BinaryTree::Node *),
                           BinaryTree::Node * treeNode) {
    if (treeNode != NULL) {
        postOrder(visite, treeNode->left);
        postOrder(visite, treeNode->right);
        visite(treeNode);
    }
}

根据前序后序求中序

已知前序遍历为GDAFEMHZ,中序遍历为ADEFGHMZ,请画出这棵二叉树。

①根据前序遍历特征,我们知道根结点必在首位置,所以为G;

②根据中序遍历特征。其中根节点G左侧的ADEF必然是根节点的左子树,G右侧的HMZ必然是根节点的右子树;

③根据前序中序特征,重复以上步骤。递归找到子树根节点;

那么,我们可以画出这个二叉树:

由图可知,后序遍历顺序为:AEFDHZMG

代码实现

BinaryTree::Node* recursionBuild(const std::vector<char>& preorder,
                                 unsigned long preLeft,
                                 unsigned long preRight,
                                 const std::vector<char>& inorder,
                                 unsigned long inLeft,
                                 unsigned long inRight) {
    if (preLeft > preRight || preRight == preorder.size() ||
        inLeft > inRight || inRight == inorder.size())
        return NULL;

    unsigned long i = 0;

    BinaryTree::Node* node = new BinaryTree::Node(preorder[preLeft]);

    for (i = inLeft; i <= inRight; i++) {
        if (inorder[i] == node->val) {
            break;
        }
    }

    node->left =  recursionBuild(preorder,
                                 preLeft + 1, preLeft + i -inLeft,
                                 inorder,
                                 inLeft, i - 1);
    node->right = recursionBuild(preorder,
                                 preLeft + i - inLeft + 1, preRight,
                                 inorder,
                                 i + 1, inRight);

    return node;
}
BinaryTree::BinaryTree(const std::vector<char> & preorder,
                       const std::vector<char> & inorder) {
    root = NULL;
    unsigned long preSize = preorder.size();
    unsigned long inSize = inorder.size();
    if (preSize == 0 || preSize != inSize) {
        return;
    }

    root = recursionBuild(preorder, 0, preSize - 1,
                          inorder, 0, inSize - 1);
}

根据后序中序求前序

已知一棵二叉树的中序序列和后序序列分别是BDCEAFHG 和 DECBHGFA,请画出这棵二叉树。

分析:

  • ①由后序遍历特征,根结点必在后序序列尾部(即A);
  • ②由中序遍历特征,根结点必在其中间,而且其左部必全部是左子树的子孙(即BDCE),其右部必全部是右子树的子孙(即FHG);
  • ③递归找出子树根节点。

那么,我们可以画出这个二叉树:

注意事项:

左子树中序为BDCE,后序为DECB,说明B为A的左子树根节点,C为B的右子树(从BDCE看出)根节点(从DCE及DEC看出);

右子树中序为FHG,后序为HGF,说明F为A的右子树的根节点,H为G的左子树根节点。

构造过程

接下来讨论在构造过程中出现的难点。

用队列让vector构造二叉树

用队列可以实现FIFO,从而让每一个节点都依次赋值。但必须注意在queue中要存储_Node**,就是存储一个指向指针的指针。(因为在其内部应该实现了深复制。所以如果只用_Node*会就会复制指针所指向的对象(都为NULL),这与我们的算法就想违背了。)

BinaryTree::BinaryTree(std::vector<char>& orig) {
    std::queue<_Node**> queue_Node;
    if (!orig.empty() && orig[0] != EMPTY_ELE) {
        root = new _Node(orig[0]);
        queue_Node.push(&root->left);
        queue_Node.push(&root->right);
        int i = 1;
        while (!queue_Node.empty()) {
            _Node** temp = queue_Node.front();
            queue_Node.pop();
            if (i >= orig.size()) {
                temp = NULL;
                i++;
            } else if (orig[i] == EMPTY_ELE) {
                temp = NULL;
                i++;
            } else {
                *temp = new _Node(orig[i++]);
                queue_Node.push(&((*temp)->left));
                queue_Node.push(&((*temp)->right));
            }
        }
    } else {
        root = NULL;
    }
}

第二种方法:(更细致的实现方法。)

BinaryTree::BinaryTree(std::vector<char> & elements) {
    unsigned long size = elements.size();
    int index = 0;
    std::queue<Node*> queue;
    if (elements.empty() || elements[index] == EMPTY_ELE) {
        root = NULL;
    } else {
        root = new Node(elements[index]);
        queue.push(root);
        index += 1;
        while (index < size) {
            Node* temp = queue.front();
            queue.pop();
            if (elements[index] != EMPTY_ELE) {
                temp->left = new Node(elements[index]);
                queue.push(temp->left);
            }
            index += 1;
            if (index >= size) {
                break;
            }
            if (elements[index] != EMPTY_ELE) {
                temp->right = new Node(elements[index]);
                queue.push(temp->right);
            }
            index += 1;
        }
    }
}

copy构造函数(递归实现)

BinaryTree::Node* BinaryTree::copyNode(BinaryTree::Node *oldNode,
                                       BinaryTree::Node *newNode) {
    if (oldNode == NULL) {
        newNode = NULL;
        return newNode;
    }

    newNode = new Node(oldNode->val);
    newNode->left = copyNode(oldNode->left, newNode->left);
    newNode->right = copyNode(oldNode->right, oldNode->right);
    return newNode;
}
BinaryTree::BinaryTree(const BinaryTree &old) {
    root = NULL;
    root = copyNode(old.getRoot(), root);
}

问题解决


//
//  BinaryTree.cpp
//  C++
//
//  Created by 李天培 on 16/5/4.
//  Copyright ? 2016年 lee. All rights reserved.
//

#include "BinaryTree.hpp"
BinaryTree::Node* recursionBuild(const std::vector<char>& preorder,
                                 unsigned long preLeft,
                                 unsigned long preRight,
                                 const std::vector<char>& inorder,
                                 unsigned long inLeft,
                                 unsigned long inRight) {
    if (preLeft > preRight || preRight == preorder.size() ||
        inLeft > inRight || inRight == inorder.size())
        return NULL;

    unsigned long i = 0;

    BinaryTree::Node* node = new BinaryTree::Node(preorder[preLeft]);

    for (i = inLeft; i <= inRight; i++) {
        if (inorder[i] == node->val) {
            break;
        }
    }

    node->left =  recursionBuild(preorder,
                                 preLeft + 1, preLeft + i -inLeft,
                                 inorder,
                                 inLeft, i - 1);
    node->right = recursionBuild(preorder,
                                 preLeft + i - inLeft + 1, preRight,
                                 inorder,
                                 i + 1, inRight);

    return node;
}

BinaryTree::BinaryTree(const BinaryTree &old) {
    root = NULL;
    root = copyNode(old.getRoot(), root);
}

BinaryTree::BinaryTree(const std::vector<char> & preorder,
                       const std::vector<char> & inorder) {
    root = NULL;
    unsigned long preSize = preorder.size();
    unsigned long inSize = inorder.size();
    if (preSize == 0 || preSize != inSize) {
        return;
    }

    root = recursionBuild(preorder, 0, preSize - 1,
                          inorder, 0, inSize - 1);
}
BinaryTree::BinaryTree(std::vector<char> & elements) {
    unsigned long size = elements.size();
    int index = 0;
    std::queue<Node*> queue;
    if (elements.empty() || elements[index] == EMPTY_ELE) {
        root = NULL;
    } else {
        root = new Node(elements[index]);
        queue.push(root);
        index += 1;
        while (index < size) {
            Node* temp = queue.front();
            queue.pop();
            if (elements[index] != EMPTY_ELE) {
                temp->left = new Node(elements[index]);
                queue.push(temp->left);
            }
            index += 1;
            if (index >= size) {
                break;
            }
            if (elements[index] != EMPTY_ELE) {
                temp->right = new Node(elements[index]);
                queue.push(temp->right);
            }
            index += 1;
        }
    }
}

BinaryTree::Node* BinaryTree::copyNode(BinaryTree::Node *oldNode,
                                       BinaryTree::Node *newNode) {
    if (oldNode == NULL) {
        newNode = NULL;
        return newNode;
    }

    newNode = new Node(oldNode->val);
    newNode->left = copyNode(oldNode->left, newNode->left);
    newNode->right = copyNode(oldNode->right, oldNode->right);
    return newNode;
}

BinaryTree::Node* BinaryTree::getRoot() const {
    return root;
}

BinaryTree::~BinaryTree() {
    clear();
}
void BinaryTree::clear() {
    std::queue<Node*> queue;
    if (root != NULL) {
        queue.push(root);
    }
    while (!queue.empty()) {
        Node * temp = queue.front();
        queue.pop();
        if (temp->left != NULL)
            queue.push(temp->left);
        if (temp->right != NULL)
            queue.push(temp->right);
        delete temp;
    }
}

void BinaryTree::preOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
    Node *temp = r;
    if (temp == NULL) {
        return;
    } else {
        visite(temp);
        preOrder(visite, temp->left);
        preOrder(visite, temp->right);
    }
}

void BinaryTree::inOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
    Node *temp = r;
    if (temp == NULL) {
        return;
    } else {
        inOrder(visite, temp->left);
        visite(temp);
        inOrder(visite, temp->right);
    }
}

void BinaryTree::postOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
    Node *temp = r;
    if (temp == NULL) {
        return;
    } else {
        postOrder(visite, temp->left);
        postOrder(visite, temp->right);
        visite(temp);
    }
}
时间: 2024-10-07 05:46:24

[C++]封装二叉树(附例题)的相关文章

[C++]广度优先搜索(BFS)(附例题)

广度优先搜索(BFS)(附例题) 问题产生: Isenbaev是国外的一个大牛. 现在有许多人要参加ACM ICPC. 一共有n个组,每组3个人.同组的3个人都是队友. 大家都想知道自己与大牛的最小距离是多少. 大牛与自己的最小距离当然是0.大牛的队友和大牛的最小距离是1.大牛的队友的队友和大牛的最小距离是2--以此类推. 如果实在和大牛没有关系的只好输出undefined了. 第一行读入n.表示有n个组.1 ≤ n ≤ 100 接下来n行,每行有3个名字,名字之间用空格隔开.每个名字的开头都是

树形背包 附例题

目录 树形背包\(O(n^2)\)算法 P2014选课 题目描述 输入输出格式 题解 P3177 [HAOI2015]树上染色 题目描述 输入输出格式 题解 树形背包\(O(n^2)\)算法 P2014选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要

树的直径求法与性质(附例题)

树的直径指树上距离最远的两点间的距离,它在树上问题上有许多应用,往往通过树的直径的性质可以将一个高时间复杂度的解法变为线性求解.对于树上两点间距离通常有三种定义,我们根据这三种情况分别讨论一下它的性质 树的直径的求法: 树的直径有两种求法,时间复杂度都是O(n) ①贪心求法: 贪心求直径的方法是任意找一个点为根,dfs整棵树找到距离他最远的点xx,再以这个点x为根求出距离它最远的点y,(x,y)即为直径 ②DP求法: DP求直径的方法是对于每个点记录这个点子树中的最长链及与最长链处于不同子树中的

线段树或树状数组求逆序数(附例题)

学习了博主:MyZee   , shengweison 的文章 线段树或树状数组求逆序数 假设给你一个序列 6 1 2 7 3 4 8 5,  首先我们先手算逆序数, 设逆序数为 N; 6的前面没有比他大的数 N +=0 1的前面有一个比他大的数 N+=1 2的前面有一个比他大的数 N+=1 7的前面没有比他大的数 N+=0 ... 最后得到 N = 0 + 1 + 1 + 0 + 2 + 2 + 0 + 3 = 9 其实我们可用用线段树,或者树状数组模拟这个过程. 又因为线段树和树状数组的效率

数据结构与算法:二叉树

二叉树是一种非常常见并且实用的数据结构,它结合了有序数组与链表的优点.在二叉树中查找数据与在数组中查找数据一样快,在二叉树中添加.删除数据的速度也和在链表中一样高效,所以有关二叉树的相关技术一直是程序员面试笔试中必考的知识点. 基础知识 基本概念 性质 有关二叉树的例题 题目 解析 递归实现二叉树的遍历 已知先序遍历和中序遍历如何求后序遍历 引申已知中序遍历和后序遍历求先序遍历 非递归实现二叉树的后序遍历 如何使用非递归方法实现二叉树的先序遍历与中序遍历 使用非递归算法求二叉树的深度 霍夫曼编解

LeetCode---二叉树3-总结例题

二叉树-总结例题 1-从中序与后序遍历序列构造二叉树 给定二叉树的后序遍历和二叉树的中序遍历 想法: 先根据后序遍历的最后一个元素构造根节点 寻找根节点在中序遍历中的位置 递归构建根节点的左右子树 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), ri

[C++]那些年被虐的STL

首先很感谢P1135奇怪的电梯 [2.14补充:此题已被AC!然后将被我花式虐[From语]哈哈哈哈哈哈哈哈哈哈好嗨哟感觉人生已经到达了巅峰感觉人生已经到达了高潮]这道题了!在做这道题的我大致就是下图qwq: dfs->sp->bfs->stl 于是小蒟蒻准备写一篇博客整理一下STL库啦! 祭出大佬@From 廿八--初六每日更新 目录: vector 封装数组 #### 向量(vector) 连续存储的元素 set 封装二叉树[集合] 集合(set) 由节点组成的红黑树,每个节点都包含

为Node.js编写组件的几种方式

本文主要备忘为Node.js编写组件的三种实现:纯js实现.v8 API实现(同步&异步).借助swig框架实现. 关键字:Node.js.C++.v8.swig.异步.回调. 简介 首先介绍使用v8 API跟使用swig框架的不同: (1)v8 API方式为官方提供的原生方法,功能强大而完善,缺点是需要熟悉v8 API,编写起来比较麻烦,是js强相关的,不容易支持其它脚本语言. (2)swig为第三方支持,一个强大的组件开发工具,支持为python.lua.js等多种常见脚本语言生成C++组件

利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)

最近看老罗的视频,跟着完成了利用Java操作MySql数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查.其中查询这块,包括普通的查询和利用反射完成的查询,主要包括以下几个函数接口: 1.public Connection getConnection()   获得数据库的连接 2.public boolean updateByPreparedStatement(String sql, List<Object>params)throws SQLException  更新数据库