[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);
}

问题解决

#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);
    }
}

搜索二叉树

关于搜索二叉树的具体知识点分析见:

搜索二叉树

#ifndef BinarySearchTree_hpp
#define BinarySearchTree_hpp

#include <queue>
#include <vector>

class BinarySearchTree {
 public:
  struct Node {
    int val;
    Node* left;
    Node* right;
    Node(int v, Node* l = NULL, Node* r = NULL) : val(v), left(l), right(r) {}
  };

  BinarySearchTree();
  BinarySearchTree(const std::vector<int>&);
  ~BinarySearchTree();

  bool insertNode(int);
  bool searchNode(int);
  bool deleteNode(int);
  void clear();

  Node* getRoot() const;

 private:
  Node* root;
};

#endif /* BinarySearchTree_hpp */
#include "BinarySearchTree.hpp"
BinarySearchTree::BinarySearchTree() { root = NULL; }
void delete_node(BinarySearchTree::Node* root) {
  if (root != NULL) {
    delete_node(root->left);
    delete_node(root->right);
    delete root;
  }
}
BinarySearchTree::~BinarySearchTree() { clear(); }
void BinarySearchTree::clear() { delete_node(root); }
BinarySearchTree::BinarySearchTree(const std::vector<int>& orig) {
  root = new Node(orig[0]);
  for (int i = 1; i < orig.size(); i++) {
    insertNode(orig[i]);
  }
}
void insert(BinarySearchTree::Node** root, int value) {
  if (*root == NULL) {
    *root = new BinarySearchTree::Node(value);
    return;
  }
  if (value < (*root)->val) {
    insert(&(*root)->left, value);
  }
  if (value > (*root)->val) {
    insert(&(*root)->right, value);
  }
}

bool BinarySearchTree::insertNode(int value) {
  if (searchNode(value)) {
    return false;
  }
  insert(&root, value);
  return true;
}
bool BinarySearchTree::searchNode(int value) {
  Node* temp = root;
  while (temp != NULL) {
    if (temp->val == value) {
      return true;
    } else if (temp->val > value) {
      temp = temp->left;
    } else if (temp->val < value) {
      temp = temp->right;
    }
  }
  return false;
}
BinarySearchTree::Node* BinarySearchTree::getRoot() const { return root; }
/**
 *  find the max value in the left tree
 *
 *  @param t Node (which will be deleted later)
 *
 *  @return Max Node
 */
BinarySearchTree::Node* findMax(BinarySearchTree::Node* t) {
  if (t == NULL) {
    return NULL;
  } else {
    while (t->right != NULL) t = t->right;
    return t;
  }
}
BinarySearchTree::Node* findMin(BinarySearchTree::Node* t) {
  if (t == NULL) {
    return NULL;
  } else {
    while (t->left != NULL) {
      t = t->left;
    }
    return t;
  }
}
//  there is two kinds of way to delete Node
void remove_Left(const int& x, BinarySearchTree::Node*& t) {
  if (t == NULL) return;
  if (x < t->val)
    remove_Left(x, t->left);
  else if (x > t->val)
    remove_Left(x, t->right);
  else if (t->left != NULL && t->right != NULL) {
    t->val = findMax(t->left)->val;
    remove_Left(t->val, t->left);
  } else {
    BinarySearchTree::Node* oldNode = t;
    t = (t->right != NULL) ? t->right : t->left;
    delete oldNode;
  }
}
void remove_Right(const int& x, BinarySearchTree::Node*& t) {
  if (t == NULL) return;
  if (x < t->val)
    remove_Right(x, t->left);
  else if (x > t->val)
    remove_Right(x, t->right);
  else if (t->left != NULL && t->right != NULL) {
    t->val = findMin(t->right)->val;
    remove_Right(t->val, t->right);
  } else {
    BinarySearchTree::Node* oldNode = t;
    t = (t->left != NULL) ? t->left : t->right;
    delete oldNode;
  }
}
bool BinarySearchTree::deleteNode(int value) {
  if (searchNode(value)) {
    remove_Left(value, root);
    return true;
  }
  return false;
}

测试文件

#include <iostream>
#include <vector>
#include "BinarySearchTree.hpp"

using std::cout;
using std::cin;
using std::endl;

void preorder(BinarySearchTree::Node* node) {
  if (node == NULL) {
    return;
  } else {
    cout << node->val << " ";
    preorder(node->left);
    preorder(node->right);
  }
}

void inorder(BinarySearchTree::Node* node) {
  if (node == NULL) {
    return;
  } else {
    inorder(node->left);
    cout << node->val << " ";
    inorder(node->right);
  }
}

void displayTree(const BinarySearchTree& tree) {
  cout << "pre: ";
  preorder(tree.getRoot());
  cout << endl;

  cout << "in: ";
  inorder(tree.getRoot());
  cout << endl;
}

void testMinimalSpanningTrees() {
  cout << "testMinimalSpanningTrees" << endl;

  std::vector<int> elements;

  int n = 0;
  cin >> n;
  while (n--) {
    int temp = 0;
    cin >> temp;
    elements.push_back(temp);
  }

  BinarySearchTree tree(elements);
  displayTree(tree);

  cin >> n;
  cout << "insert : " << n << " -> " << tree.insertNode(n) << endl;
  displayTree(tree);

  cout << "search : " << n << " -> " << tree.searchNode(n) << endl;
  cout << "delete : " << n << " -> " << tree.deleteNode(n) << endl;

  cin >> n;
  cout << "delete : " << n << " -> " << tree.deleteNode(n) << endl;
  displayTree(tree);

  cin >> n;
  cout << "search : " << n << " -> " << tree.searchNode(n) << endl;

  cout << "insert : " << elements[0] << " -> " << tree.insertNode(elements[0])
       << endl;
  displayTree(tree);
}

int main() { testMinimalSpanningTrees(); }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值