c++實現二叉樹的插入、刪除、查詢、遍歷和樹形列印
阿新 • • 發佈:2018-12-25
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 empty else 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兩個檔案,分開寫的結果是出現連結錯誤,原因可參考: