c++实现二叉树的插入、删除、查询、遍历和树形打印

来源:互联网 发布:天干地支年月计算法 编辑:程序博客网 时间:2024/05/21 00:55

binary_tree.h

声明

#ifndef BINARY_TREE#define BINARY_TREE#include "util.h"template<typename T>class tree_node {public:tree_node(T key_):key(key_), parent(NULL), left_child(NULL), right_child(NULL) {};T get_key();tree_node* get_parent();tree_node* get_left_child();tree_node* get_right_child();void set_parent(tree_node* p);void set_left_child(tree_node* lc);void set_right_child(tree_node* rc);private:T key;tree_node* parent;tree_node* left_child;tree_node* right_child;};template<typename T>class binary_tree {public:binary_tree():root(NULL), size(0), max_key_length(0), change(false) {};void inorder_tree_walk(tree_node<T>* r) const;  //输出中序遍历void preorder_tree_walk(tree_node<T>* r) const; //输出前序遍历void postorder_tree_walk(tree_node<T>* r) const; //输出后序遍历tree_node<T>* search(tree_node<T>* x, T k) const; //查找键值为k的结点tree_node<T>* min_node(tree_node<T>* x) const; //返回键值最小的结点tree_node<T>* max_node(tree_node<T>* x) const; //返回键值最大的结点tree_node<T>* successor_node(tree_node<T>* x) const; //返回下一个结点,即最小的比当前结点键值大的结点tree_node<T>* get_root() const; //获取根节点void tree_insert(tree_node<T>* z); // 插入结点void tree_delete(tree_node<T>* z); // 删除结点void print_tree(); // 按树状打印二叉树int tree_size() const; // 结点个数int tree_height(tree_node<T>* r) const; //树高private:void transplant(tree_node<T>* u, tree_node<T>* v);  //用v为根的子树替换u为根的子树void find_nodes_indexes(tree_node<T>* r, int layer); //计算每个结点的横纵坐标,用于树形打印int get_max_key_length() const; //获取键的最大长度,用于打印int size; //节点个数int max_key_length; //键的最大长度tree_node<T>* root; //根结点指针map<tree_node<T>*, pair<int, int> > nodes_indexes; //结点指针与其横纵坐标的对应bool change; //与上次树形打印时相比,二叉树是否发生了变化};

实现

/*=================实现=====================*//*****tree_node*****/template<typename T>T tree_node<T>::get_key() {return key;}template<typename T>tree_node<T>* tree_node<T>::get_parent() {return parent;}template<typename T>tree_node<T>* tree_node<T>::get_left_child() {return left_child;}template<typename T>tree_node<T>* tree_node<T>::get_right_child() {return right_child;}template<typename T>void tree_node<T>::set_parent(tree_node* p) {parent = p;}template<typename T>void tree_node<T>::set_left_child(tree_node* lc) {left_child = lc;}template<typename T>void tree_node<T>::set_right_child(tree_node* rc) {right_child = rc;}/*****binary_tree*****/template<typename T>void binary_tree<T>::inorder_tree_walk(tree_node<T>* r) const {if (r != NULL) {inorder_tree_walk(r->get_left_child());cout << r->get_key() << " ";inorder_tree_walk(r->get_right_child());}}template<typename T>void binary_tree<T>::preorder_tree_walk(tree_node<T>* r) const {if (r != NULL) {cout << r->get_key() << " ";preorder_tree_walk(r->get_left_child());preorder_tree_walk(r->get_right_child());}}template<typename T>void binary_tree<T>::postorder_tree_walk(tree_node<T>* r) const {if (r != NULL) {postorder_tree_walk(r->get_left_child());postorder_tree_walk(r->get_right_child());cout << r->get_key() << " ";}}template<typename T>tree_node<T>* binary_tree<T>::search(tree_node<T>* x, T k) const {if (x == NULL || k == x->get_key()) return x;if (k < x->get_key()) return search(x->get_left_child(), k);return search(x->get_right_child(), k);}template<typename T>tree_node<T>* binary_tree<T>::min_node(tree_node<T>* x) const {while (x->get_left_child() != NULL) x = x->get_left_child();return x;}template<typename T>tree_node<T>* binary_tree<T>::max_node(tree_node<T>* x) const {while (x->get_right_child() != NULL) x = x->get_right_child();return x;}template<typename T>tree_node<T>* binary_tree<T>::successor_node(tree_node<T>* x) const {if (x->get_right_child() != NULL) return min_node(x->get_right_child());tree_node<T>* y = x->get_parent();while (y != NULL && x == y->get_right_child()) {x = y;y = y->get_parent();}return y;}template<typename T>void binary_tree<T>::tree_insert(tree_node<T>* z) {size++;change = true;if (z != NULL && T2string(z->get_key()).size() > max_key_length)max_key_length = T2string(z->get_key()).size();tree_node<T>* y = NULL;tree_node<T>* x = root;while (x != NULL) {y = x;if (z->get_key() < x->get_key()) {x = x->get_left_child();} else {x = x->get_right_child();}}z->set_parent(y);if (y == NULL) root = z; //tree is emptyelse if (z->get_key() < y->get_key()) y->set_left_child(z);else y->set_right_child(z);}//v为根的子树替换u为根的子树template<typename T>void binary_tree<T>::transplant(tree_node<T>* u, tree_node<T>* v) {if (u->get_parent() == NULL) root = v;else if (u == u->get_parent()->get_left_child()) {u->get_parent()->set_left_child(v);}else u->get_parent()->set_right_child(v);if (v != NULL) v->set_parent(u->get_parent());}//如果z没有左孩子,则用右孩子代替z//如果z有左孩子而没有右孩子,则用左孩子代替z//如果z既有左孩子又有右孩子,则先找z的后继结点y,则y一定没有左孩子  //如果y是z的右孩子,则用y替换z,y的左孩子是z的左孩子,y的右孩子保留  //如果y位于z右子树,但不是z的右孩子,先用y的右孩子替换y,然后领y的右孩子为z的右孩子,然后用y来替换z,再令y的左孩子为z的左孩子template<typename T>void binary_tree<T>::tree_delete(tree_node<T>* z) {size--;change = true;if (z->get_left_child() == NULL) {transplant(z, z->get_right_child());} else if (z->get_right_child() == NULL) {transplant(z, z->get_left_child());} else {tree_node<T>* y = min_node(z->get_right_child());if (y->get_parent() != z) {transplant(y, y->get_right_child());y->set_right_child(z->get_right_child());y->get_right_child()->set_parent(y);}transplant(z, y);y->set_left_child(z->get_left_child());y->get_left_child()->set_parent(y);}}template<typename T>tree_node<T>* binary_tree<T>::get_root() const {return root;}template<typename T>int binary_tree<T>::tree_size() const {return size;}template<typename T>int binary_tree<T>::tree_height(tree_node<T>* r) const {if (r == NULL) return 0;int left_depth = 0, right_depth = 0;if (r->get_left_child() != NULL) left_depth = tree_height(r->get_left_child());if (r->get_right_child() != NULL)right_depth = tree_height(r->get_right_child());return max(left_depth, right_depth) + 1;}//计算每个结点属于第几层(从0层开始)//并计算中序遍历时每个结点处于第几位(从0开始)//这两个值分别作为该结点的横纵坐标,用于树形打印template<typename T>void binary_tree<T>::find_nodes_indexes(tree_node<T>* r, int layer) {if (r != NULL) {static int col;if (layer == 0) col = 0;find_nodes_indexes(r->get_left_child(), layer + 1);nodes_indexes[r] = make_pair(layer, col++);find_nodes_indexes(r->get_right_child(), layer + 1);}}template<typename T>int binary_tree<T>::get_max_key_length() const {return max_key_length;}//树形打印二叉树template<typename T>void binary_tree<T>::print_tree() {int row = tree_height(root);int col = tree_size();int len = get_max_key_length();vector<vector<string> > chart(row, vector<string>(col));if (change) {nodes_indexes.clear();find_nodes_indexes(root, 0); change = false;}//每个位置用若干个空格占位,空格的个数等于键的最大长度for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {chart[i][j] = string(len, ' ');}}//对于每个结点,先找到其横纵坐标,然后用其键值替换该坐标位置的空格typename map<tree_node<T>*, pair<int, int> >::iterator i = nodes_indexes.begin();while (i != nodes_indexes.end()) {int curr_row = i->second.first;int curr_col = i->second.second;T curr_key = i->first->get_key();int blank_num = max_key_length - T2string(curr_key).size();string curr_str(blank_num, ' ');curr_str += T2string(curr_key);chart[curr_row][curr_col] = curr_str;i++;}for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {cout << chart[i][j];}cout << endl;}}#endif

main.cpp

测试

#include "binary_tree.h"int main(void) {binary_tree<char> tree;tree.tree_insert(new tree_node<char>('C'));tree.tree_insert(new tree_node<char>('D'));tree.tree_insert(new tree_node<char>('J'));tree.tree_insert(new tree_node<char>('E'));tree.tree_insert(new tree_node<char>('B'));tree.tree_insert(new tree_node<char>('A'));tree.tree_insert(new tree_node<char>('G'));tree.tree_insert(new tree_node<char>('H'));tree.tree_insert(new tree_node<char>('F'));tree.tree_insert(new tree_node<char>('I'));cout << "中序遍历:" << endl;tree.inorder_tree_walk(tree.get_root()); cout << endl;cout << "前序遍历:" << endl;tree.preorder_tree_walk(tree.get_root()); cout << endl;cout << "后序遍历:" << endl;tree.postorder_tree_walk(tree.get_root()); cout << endl;cout << "树形打印:" << endl;tree.print_tree();tree.tree_delete(tree.search(tree.get_root(), 'E'));cout << "删除E:" << endl;tree.print_tree();}


util.h

#include <iostream>#include <sstream>#include <string>#include <stack>#include <vector>#include <stack>#include <list>#include <queue>#include <map>#include <algorithm>using namespace std;// 类型转换template <typename T>T string2T(string str) {istringstream in(str);T out;in >> out;return out;}template <typename T>string T2string(T t) {ostringstream out;out << t;return out.str();}//初始化数组template<typename T, size_t N>void array_init(T (&arr)[N], T val) {for (size_t i = 0; i != N; ++i) {arr[i] = val;}}int max(int a, int b) {return a > b ? a : b;}int min(int a, int b) {return a < b ? a : b;}

运行结果:


注意:

模板类的声明和实现不能分开写,即不能分成binary_tree.h和binary_tree.cpp两个文件,分开写的结果是出现链接错误,原因可参考:

http://blog.csdn.net/pongba/article/details/19130



0 0