二叉树及其实现

// 此处为"bin_tree.h"
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<queue>
#include<stdbool.h>
// stature : 身高,高度
#define stature(p) ((p)?(p)->height:-1)               // p 为null 时空树的高度-1,最好还是全部括起来
#pragma once
using namespace std;
template<typename T>struct Visit
{
	Visit(){}
	void visit(T elem) { cout << elem << " "; }
	void operator()(T elem) { visit(elem); }
};
/******************************************BinNode模板类*******************************************/
// 01 BinNode模板类的基本实现框架
template <typename T> struct bin_node;
template <typename T> using bin_node_posi = bin_node<T>*; //节点位置  // 这里using的使用还不懂的见笔记
template <typename T> struct bin_node {

	T data;   bin_node_posi<T> parent, lchild, rchild;  int height;	 int visited;

	// 构造函数,默认叶子节点的高度为0,此构造函数将叶子结点视为孤立节点
	bin_node(T da, bin_node_posi<T> pa = NULL, bin_node_posi<T> lc = NULL, 
			 bin_node_posi<T> rc = NULL, int h = 0, int v=0)
	{
		data = da; parent = pa; lchild = lc; rchild = rc; height = h; visited = 0;
	}
	// 先注释一下看看没有这个默认构造函数是什么反应
	/*bin_node()
	{
		parent = NULL; lchild = NULL; rchild = NULL; height = 0;
	}*/

	int get_size();  // 返回包括自己在内的所有子代结点数目
	bin_node_posi<T> insert_as_left_child(const T& elem);
	bin_node_posi<T> insert_as_right_child(const T& elem);
	bin_node_posi<T> success();              // 中序遍历意义下的当前节点的后继
	template<typename VST>void tra_preorder(VST&);   // 函数对象进行visit , 遍历的统一接口
	template<typename VST>void tra_inorder(VST&);
	template<typename VST>void tra_postorder(VST&);
	template<typename VST>void tra_levelorder(VST&);
};
template<typename T> int bin_node<T>::get_size()
{
	if (this == NULL)
		return 0;
	return lchild->get_size() + rchild->get_size() + 1;
}
template<typename T> bin_node_posi<T> bin_node<T>::insert_as_left_child(const T& elem)
{
	// bin_node<T> temp(elem, this, NULL, NULL, 0); 不要这么写   // temp.parent-->this
	bin_node<T> temp(elem, this);
	lchild = temp;
	// 由于要返回结点位置
	return lchild;
}
template<typename T> bin_node_posi<T> bin_node<T>::insert_as_right_child(const T& elem)
{
	bin_node<T> temp(elem, this);    // temp.parent-->this
	rchild = temp;
	return rchild;
}
template<typename T> bin_node_posi<T> bin_node<T>::success()          // 中序遍历意义下的结点后继
{
	bin_node_posi<T> node_s = this;
	if (node_s->rchild)                 // 如果有右孩子,往下走
	{
		bin_node_posi<T> temp = node_s->rchild;
		while (temp->lchild)
			temp = temp->lchild;
		return temp;
	}
	else                                    // 没有右孩子,往上走
		/*return node_s->parent;*/         // 这样分析实在是让人大跌眼镜,没有站在一种抽象的角度
	{
		//if (node_s->parent)
		//{
		//	bin_node_posi<T> parnt = node_s->parent;
		//	while (parnt->lchild != node_s) {
		//		node_s = node_s->parent;
		//		parnt = node_s->parent;
		//	}
		//	return parnt;
		//}
		//return NULL;                       // 孤立结点,没有双亲
		bin_node_posi<T> parnt = node_s->parent;
		while (parnt != NULL && parnt->lchild != node_s) {
			node_s = node_s->parent;
			parnt = node_s->parent;
		}
		return parnt;
	}

}
// 02_1遍历算法的实现接口
template<typename T> template<typename VST>
void bin_node<T>::tra_preorder(VST& visit)
{
	pre_order_tra(this, visit);
	cout << endl;
}
template<typename T> template<typename VST>
void bin_node<T>::tra_inorder(VST& visit)
{
	in_order_tra(this, visit);
	cout << endl;
}
template<typename T> template<typename VST>
void bin_node<T>::tra_postorder(VST& visit)
{
	post_order_tra(this, visit);
	cout << endl;
}
template<typename T> template<typename VST>
void bin_node<T>::tra_levelorder(VST& visit)
{
	level_order_tra(this, visit);
	cout << endl;
}

// 02_2遍历算法
// i 先序
template<typename T, typename VST>           // TMD 直接用STL标准模板库
void visit_along_left_vine(bin_node_posi<T> node_pos, VST& visit, stack< bin_node_posi<T>>& stk)
{
	while (node_pos) {
		visit(node_pos->data);
		if (node_pos->rchild) stk.push(node_pos->rchild);   // 如果有右节点,入栈
		node_pos = node_pos->lchild;
	}
}
template<typename T, typename VST> void pre_order_tra(bin_node_posi<T> node_pos, VST& visit)
{
	stack<bin_node_posi<T>> stk;
	do {
		visit_along_left_vine(node_pos, visit, stk);
		if (stk.empty())
			break;
		node_pos = stk.top();
		stk.pop();
	} while (1);
}
// ii 中序
template<typename T> void go_along_left_vine(bin_node_posi<T> node_pos, stack<bin_node_posi<T>>& stk)
{
	while (node_pos)
	{
		stk.push(node_pos);
		node_pos = node_pos->lchild;
	}
}
template<typename T, typename VST>
void in_order_tra(bin_node_posi<T> node_pos, VST& visit)
{
	stack<bin_node_posi<T>> stk;
	do {
		go_along_left_vine(node_pos, stk);
		if (stk.empty())
			break;
		bin_node_posi<T> temp = stk.top();          // 此时栈的最顶端已经是中序遍历的第一个结点
		stk.pop();
		visit(temp->data);
		node_pos = temp->rchild;
	} while (1);
}
// iii 后序
template<typename T>
void go_left_most_leaf(bin_node_posi<T> node_pos, stack<bin_node_posi<T> >& stk)   // 栈的元素是指向树节点的指针
{
	while (node_pos)
	{
		stk.push(node_pos);
		if (node_pos->lchild) node_pos = node_pos->lchild;
		else if (node_pos->rchild) node_pos = node_pos->rchild;
		else break;                // 既没有左孩子,又没有右孩子,直接退出
	}
}
template<typename T, typename VST>
void post_order_tra(bin_node_posi<T> node_pos, VST& visit)
{
	stack<bin_node_posi<T>> stk;
	go_left_most_leaf(node_pos, stk);
	//printf("%d",stk.size());
	while (!stk.empty())
	{
		/*BTree* node_temp = stk.pop();*/      // STL 的pop 返回的是void,只能用top和pop 两个操作去弥补了
		bin_node_posi<T> node_temp = stk.top();
		visit(node_temp->data);
		//printf("%c ", node_temp->data);        // 由go_left_most_leaf接口实现的  栈顶元素为第一个要访问的结点 
		node_temp->visited = 1;
		stk.pop();
		if (stk.empty())break;                 // 如果栈为空,这里得提前退出
		if (stk.top()->rchild != NULL && stk.top()->rchild->visited != 1)  // 如果此时栈顶元素还有右孩子,且右孩子未访问
		{
			go_left_most_leaf(stk.top()->rchild, stk);         // 把控制权交给右孩子
		}
	}
}
// iv 层序
template<typename T, typename VST>
void level_order_tra(bin_node_posi<T> node_pos, VST& visit)
{
	queue<bin_node_posi<T>> Queue;
	Queue.push(node_pos);
	while (!Queue.empty())
	{
		bin_node_posi<T> temp = Queue.front();
		visit(temp->data);
		Queue.pop();
		if (temp->lchild) Queue.push(temp->lchild);
		if (temp->rchild) Queue.push(temp->rchild);
	}
}
/******************************************************************************************************/
									  /*BinTree模板类*/
/******************************************************************************************************/
template<typename T>class bin_tree {
private:
	int size; bin_node_posi<T> root;
public:
	// constructor
	bin_tree(int sz = 0, bin_node_posi<T> rt = NULL) :size(sz), root(rt) {}
	// destructor
	/*~bin_tree()
	{
		size = 0;
		remove_at(root);
	}*/
	// 你上面写的destructor 把我给看蒙了
	~bin_tree()
	{
		if (size > 0)
			remove(root);
	}
	int get_size() { return size; }           // 像这种返回属性的直接写在里面
	bin_node_posi<T> get_root() { return root; }
	bool empty() { return !root; }
	virtual int update_height(bin_node_posi<T> node_pos); //更新某个结点的高度,返回更新后的高度,
															//后面子类可进行适当重写
	void update_height_above(bin_node_posi<T> node_pos);    // 包括当前结点的高度更新
	bin_node_posi<T> insert_as_root(const T&);                     // 插入根节点
	bin_node_posi<T> insert_as_lc(const T&, bin_node_posi<T> node_pos);
	bin_node_posi<T> insert_as_rc(bin_node_posi<T> node_pos, const T&);
	bin_node_posi<T> attached_as_lc(bin_tree<T>*& subtree, bin_node_posi<T> node_pos);// 引用类型的指针
																				  // 为release操作做准备
	bin_node_posi<T> attached_as_rc(bin_node_posi<T> node_pos, bin_tree<T>*& subtree);
	int remove(bin_node_posi<T> node_pos);        // 返回删除结点的个数
	bin_tree<T>* secede(bin_node_posi<T> node);

	// 遍历接口
	template<typename VST> void preorder_tra(VST& visit) { if(root) root->tra_preorder; }
	template<typename VST> void inorder_tra(VST& visit) { if (root) root->tra_inorder; }
	template<typename VST> void postorder_tra(VST& visit) { if (root) root->tra_postorder; }
	template<typename VST> void levelorder_tra(VST& visit) { if (root) root->tra_levelorder; }
};

// 这样写应用太狭窄了
//template<typename T>
//void release(bin_node<T>* tree)
//{
//	if (tree)
//		delete tree;
//}
template<typename T>struct Release;                // 加上一句声明,就可以进行模板偏特化了
template<typename T>struct Release<T*>
{
	static void _release(T* elem)                  // elem 为指针类型
	{
		if (elem)
			delete elem;        // 把结构体指针干掉
	}
};
template<typename T>struct Release
{
	static void _release(T elem) {}                 // elem 为普通类型
};
template<typename T>void release(T elem)           // 函数模板,可以进行类型推导
{
	Release<T>::_release(elem);
}
template<typename T> static int remove_at(bin_node_posi<T> node_pos)   // 返回删除结点的个数,删除方法与二叉树的销毁一样
{
	//if (node_pos)             // node_pos is not null
	//{
	//	// 这个就麻烦了,不能用static,否则size就根本不是真正的size(有关static 数据存储方式)
	//	// 还有一点要值得批评的是要善用之前写的函数呀,不然就白写了
	//	static int size = 1 + remove_at(node_pos->lchild) + remove_at(node_pos->rchild);
	//	delete node_pos;
	//	return size;
	//}
	//return 0;
	if (!node_pos) return 0;
	int size = 1 + remove_at(node_pos->lchild) + remove_at(node_pos->rchild);
	release(node_pos->data); release(node_pos);
	return size;
}
template<typename T> int bin_tree<T>::update_height(bin_node_posi<T> node_pos)
{
	//return max(node_pos->lchild->height, node_pos->rchild->height) + 1;  // 这样写stature就白写了
	return max(stature(node_pos->lchild), stature(node_pos->rchild)) + 1;
}
// 在类外实现虚函数时,不可加virtual关键字
template<typename T> void bin_tree<T>::update_height_above(bin_node_posi<T> node_pos)
{
	// 沿着这个改变的结点一直往上走
	while (node_pos) {
		update_height(node_pos);
		node_pos = node_pos->parent;                // 可优化,怎么优化?
	}
}
template<typename T> bin_node_posi<T> bin_tree<T>::insert_as_root(const T& elem)
{
	++size;
	root = new bin_node<T>(elem);
	return root;
}
template<typename T> bin_node_posi<T> bin_tree<T>::insert_as_lc(const T& elem, bin_node_posi<T> node_pos)
{
	node_pos->insert_as_left_child(elem);
	size++;
	update_height_above(node_pos);
	return node_pos->lchild;
}
template<typename T> bin_node_posi<T> bin_tree<T>::insert_as_rc(bin_node_posi<T> node_pos, const T& elem)
{
	node_pos->insert_as_right_child(elem);
	size++;
	update_height_above(node_pos);
	return node_pos->rchild;
}
template<typename T> bin_node_posi<T> bin_tree<T>::attached_as_lc(bin_tree<T>*& subtree, bin_node_posi<T> node_pos)
{
	/* 考虑到subtree可能是空树               // 这里存在很大的问题:subtree空与否应该是判断root是不是空,而不是判断subtree
	if (subtree)                            // 指针是不是空
	{
		node_pos->lchild = subtree->root;
		subtree->root->parent = node_pos;
	}*/
	if (subtree->root = node_pos)
		node_pos->lchild = subtree->root;
	size += subtree->size;
	update_height_above(node_pos);
	// *********************              /**************这里有点蒙***************/  书签ctrl+K
	subtree->root = NULL;
	subtree->size = 0;                    // 这两句话不要也罢?
	release(subtree);                     // 不要死磕语法
	subtree = NULL;
	return node_pos->lchild;
}
template<typename T> bin_node_posi<T> bin_tree<T>::attached_as_rc(bin_node_posi<T> node_pos, bin_tree<T>*& subtree)
{
	if (subtree->root = node_pos)
		node_pos->rchild = subtree->root;
	size += subtree->size;
	update_height_above(node_pos);
	subtree->root = NULL;
	subtree->size = 0;
	release(subtree);
	subtree = NULL;
	return node_pos->rchild;
}
template<typename T> int bin_tree<T>::remove(bin_node_posi<T> node_pos)
{
	int sub_size = 0;
	// 返回删除结点的个数,包括结点本身
	if (bin_node_posi<T> parent = node_pos->parent)    // 假定parent不是null 即node_pos不是root结点
	{
		// 1.解除父结点对node_pos的引用
		if (parent->lchild == node_pos)
			parent->lchild = NULL;
		else
			parent->rchild = NULL;
		// 不要急呀,还有高度没有更新!!!
		update_height_above(parent);
		// 2.将分离的子树删除
		sub_size = remove_at(node_pos);
		size -= sub_size;
	}
	return sub_size;
}
template<typename T> bin_tree<T>* bin_tree<T>::secede(bin_node_posi<T> node)    // 子树的分离
{
	if (bin_node_posi<T> parent = node->parent)
	{
		// 仍然是先解除父节点对自己的引用
		if (parent->lchild == node)
			parent->lchild = NULL;
		else
			parent->rchild = NULL;
		int sz = node->get_size();
		// 原树信息的更改
		size -= sz;
		update_hight_above(parent);
		// 分离出子树的包装
		//bin_tree<T> subtree(sz, node);        // Attention! 此函数返回的是指针,所以不能用构造函数
		bin_tree<T>* subtree_ptr = new bin_tree<T>;
		subtree_ptr->size = sz;
		subtree_ptr->root = node;
		/* 未考虑到的 */ subtree_ptr->root = NULL;
		return subtree_ptr;
	}
	else {   // 子树恰好是其本身
		return this;
	}
}
#include"bin_tree.h"
FILE* fp;
template<typename T> void preorder_create(bin_node_posi<T>& root,FILE* fp)
{
	T elem;
	int size = 0;
	fscanf(fp, "%c", &elem);
	if (elem == '#')
		return;
	root = new bin_node<T>(elem);
	preorder_create(root->lchild,fp);
	preorder_create(root->rchild,fp);
}
int main()
{
	bin_node_posi<char> root = NULL;
	// printf("请输入序列:先序构造树,#表示无孩子结点:\n");  // tree.txt : eg1: abd#ef####cg#h###
	fp = fopen("tree.txt", "r");
	preorder_create(root,fp);                               // eg2: ab#df##g##c#eh##i##
	Visit<char> visit;             // 定义一个函数对象  这是cpp_DSA
	cout << "层序遍历" << endl;
	root->tra_levelorder(visit);
	cout << "先序遍历" << endl;
	root->tra_preorder(visit);
	cout << "中序遍历" << endl;
	root->tra_inorder(visit);
	cout << "后序遍历" << endl;
	root->tra_postorder(visit);
	// 据此构造一棵树
	int size = root->get_size();
	bin_tree<char>* btree = new bin_tree<char>(size, root);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值