1. 程式人生 > >c++實現二叉樹的插入、刪除、查詢、遍歷和樹形列印

c++實現二叉樹的插入、刪除、查詢、遍歷和樹形列印

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兩個檔案,分開寫的結果是出現連結錯誤,原因可參考: