二叉树(BinaryTree)

myBinNode.h:节点头文件
#ifndef _BINODE_H_
#define _BINODE_H_

#pragma once
#define stature(p)	((p)?(p)->height:-1)
#define NULL 0

template<typename T> 
struct myBinNode
{
	// 成员变量
	T data;
	myBinNode<T> *parent, *lchild, *rchild;	// 指向父类,左孩子右孩子的指针
	int height;								// 高度
	//构造函数
	myBinNode() :data(NULL), lchild(nullptr), rchild(nullptr), height(0){}
	myBinNode(T e, myBinNode* p = nullptr, myBinNode* lc = nullptr, myBinNode* rc = nullptr, int h = 0) :
		data(e), parent(p), lchild(lc), rchild(rc), height(h){}
	//析构函数
	~myBinNode() {}

	// 成员函数
	myBinNode<T>* insertAsLChild(const T& e);	// 作为本节点的左孩子插入
	myBinNode<T>* insertAsRChild(const T& e);	// 作为本节点的右孩子插入
	int size();    //	返回以本节点为root的二叉树的规模
	// 重载运算符
	bool operator==(const myBinNode<T>& bn);  // 等于运算符
	bool operator<(const myBinNode<T>& bn);   // 小于运算符
	bool operator>(const myBinNode<T>& bn);   // 大于运算符
};

template<typename T>
myBinNode<T>* myBinNode<T>::insertAsLChild(const T& e)
{
	return new myBinNode<T>(e,this);// this为本节点(父节点)
}

template<typename T>
myBinNode<T>* myBinNode<T>::insertAsRChild(const T& e)
{
	return new myBinNode<T>(e, this);
}

template<typename T>
int myBinNode<T>::size()
{
	int n = 0;
	if (lchild && rchild)	// 左右子节点存在
		n = 1 + lchild->size() + rchild->size();// 1(当前节点) + 左节点数 + 右节点数
	else if (lchild && !rchild)
		n = 1 + lchild->size();
	else if (!lchild && rchild)
		n = 1 + rchild->size();
	else if (!lchild && !rchild)
		return 1;
	return n;
}

template<typename T>
bool myBinNode<T>::operator==(const myBinNode<T>& bn)
{
	return data == bn.data;
}

template<typename T>
bool myBinNode<T>::operator<(const myBinNode<T>& bn)
{
	return data < bn.data;
}

template<typename T>
bool myBinNode<T>::operator>(const myBinNode<T>& bn)
{
	return data > bn.data;
}

#endif // !_BINODE_H_




myBinTree.h:二叉树头文件
#ifndef _BINTREE_H_
#define _BINTREE_H_
#pragma once

#include "myBinNode.h"
#include <stack>
#include <queue>
using namespace std;
#define  Max(a,b) (((a)>=(b))?(a):(b))


template<typename T>
class myBinTree
{
protected:
	// 成员变量
	int m_size;				// 二叉树的规模
	myBinNode<T>* m_pRoot;	// 树的根节点指针
public:
	// 构造函数
	myBinTree();
	// 析构函数
	~myBinTree();
	// 成员函数
	int size();		// 返回二叉树的规模
	bool empty();	// 判断二叉树是否为空
	myBinNode<T>* getRoot();	// 返回根节点的指针
	myBinNode<T>* insertAsRoot(const T& e);	// 将指定元素插入作为根节点
	myBinNode<T>* insertAsLChild(myBinNode<T>* bn, const T& e);		// 将指定元素插入作为指定节点的左孩子
	myBinNode<T>* insertAsRChild(myBinNode<T>* bn, const T& e);		// 将指定元素插入作为指定节点的左孩子
	myBinNode<T>* attachAsLChild(myBinNode<T>* bn, myBinTree<T>* &bt);	// 将指定子树插入作为指定节点的左孩子
	myBinNode<T>* attachAsRChild(myBinNode<T>* bn, myBinTree<T>* &bt);	// 将指定子树插入作为指定节点的右孩子
	int updateHeight(myBinNode<T>* bn);			// 更新节点的高度
	void updateHeightAbove(myBinNode<T>* bn);		// 更新此节点祖先节点的高度(插入或删除节点要执行更新)
	int removeAt(myBinNode<T>* bn);       // 删除节点bn及其后代,并返回删掉的二叉树节点的总数
	int remove(myBinNode<T>* bn);			// 删除以bn为根节点的子树
	myBinTree<T>* secede(myBinNode<T>* bn);			// 子树分离,将节点bn及其后代从二叉树中分离出来,然后形成一个独立的二叉树

	void travPre_R(myBinNode<T>* bn_r, void(*func)(T& bn));		// 先序遍历(递归版本:简洁易懂)
	void travIn_R(myBinNode<T>* bn_r, void(*func)(T& bn));		// 中序遍历(递归版本:简洁易懂)
	void travPost_R(myBinNode<T>* bn_r, void(*func)(T& bn));		// 后序遍历(递归版本:简洁易懂)

	void visitAlongLeftBranch(myBinNode<T>* bn, void(*func)(T& bn), stack<myBinNode<T>*> &s);  // 沿着左轮廓线遍历
	void travPre_I(myBinNode<T>* bn_i, void(*func)(T& bn));			// 先序遍历(迭代版本:时间、空间复杂度低)
	void goAlongLeftBranch(myBinNode<T>* bn, stack<myBinNode<T>*> &s);	// 从当前节点开始,沿着左分支深入入栈
	void travIn_I(myBinNode<T>* bn_i, void(*func)(T& bn));			// 中序遍历(迭代版本:时间、空间复杂度低)
	void gotoHLVFL(stack<myBinNode<T>*> &s);							// 在以s栈顶节点为根的子树中,找到最高左侧可见节点
	void travPost_I(myBinNode<T>* bn_i, void(*func)(T& bn));			// 后序遍历(迭代版本:时间、空间复杂度低)
	void travLevel(myBinNode<T>* bn_i, void(*func)(T& bn));			// 层次遍历
};
#endif // !_BINTREE_H_




myBinTree.cpp:二叉树定义实现
/************************************************************************/
/* 
类模板的定义和实现分在两个函数里,在编译阶段就不通过
解决1:把定义和实现都放到头文件里
解决2:在实现的调用函数文件开头加上#include "myBinTree.cpp"(如在treeMain.cpp里加了#include "myBinTree.cpp",但这样写就另类了)
*/
/************************************************************************/

#include "myBinTree.h"
#include <iostream>

using namespace  std;
/*
func 为打印节点数据的函数
*/

// 构造函数
template<typename T>
myBinTree<T>::myBinTree() :m_size(0), m_pRoot(nullptr){}

//析构函数
template<typename T>
myBinTree<T>::~myBinTree()
{
	if (m_size)
		remove(m_pRoot);
}

// 返回二叉树的规模
template<typename T>
int myBinTree<T>::size()
{
	return m_size;
}

// 判断二叉树是否为空
template<typename T>
bool myBinTree<T>::empty()
{
	return !m_pRoot ? true : false;
}

// 返回根节点的指针
template<typename T>
myBinNode<T>* myBinTree<T>::getRoot()
{
	return m_pRoot;
}

// 将指定元素插入作为根节点
template<typename T>
myBinNode<T>* myBinTree<T>::insertAsRoot(const T& e)
{
	if (m_pRoot)
		return nullptr;
	m_size = 1;
	return m_pRoot = new myBinNode<T>(e);
}

// 将指定元素插入作为指定节点的左孩子
template<typename T>
myBinNode<T>* myBinTree<T>::insertAsLChild(myBinNode<T>* bn, const T& e)
{
	if (bn->lchild)		//若左孩子已经存在则返回
		return nullptr;
	bn->lchild = bn->insertAsLChild(e);
	//bn->lchild = new myBinNode<T>(e, bn);
	++m_size;
	updateHeightAbove(bn->lchild);
	return bn->lchild;
}

// 将指定元素插入作为指定节点的左孩子
template<typename T>
myBinNode<T>* myBinTree<T>::insertAsRChild(myBinNode<T>* bn, const T& e)
{
	if (bn->rchild)
		return nullptr;
	bn->rchild = bn->insertAsRChild(e);
	//bn->rchild = new myBinNode<T>(e, bn);
	++m_size;
	updateHeightAbove(bn->rchild);
	return bn->rchild;
}

// 将指定子树插入作为指定节点的左孩子
template<typename T>
myBinNode<T>* myBinTree<T>::attachAsLChild(myBinNode<T>* bn, myBinTree<T>* &bt)
{
	if (bn->lchild)
		return nullptr;
	bn->lchild = bt->getRoot();
	bt->getRoot()->parent = bn;
	updateHeightAbove(bn->lchild);
	m_size += bt->size();

	// 释放bt
	bt->m_pRoot = nullptr;
	bt->m_size = 0;
	bt = nullptr;
	return bn->lchild;
}

// 将指定子树插入作为指定节点的右孩子
template<typename T>
myBinNode<T>* myBinTree<T>::attachAsRChild(myBinNode<T>* bn, myBinTree<T>* &bt)
{
	if (bn->rchild)
		return nullptr;
	bn->rchild = bt->getRoot();
	bt->getRoot()->parent = bn;
	updateHeightAbove(bn->rchild);
	m_size += bt->size();

	// 释放bt
	bt->m_pRoot = nullptr;
	bt->m_size = 0;
	bt = nullptr;
	return bn->lchild;
}

// 更新节点的高度
template<typename T>
int myBinTree<T>::updateHeight(myBinNode<T>* bn)
{
	return bn->height = (1 + Max(stature(bn->lchild), stature(bn->rchild)));
}

// 更新此节点祖先节点的高度(插入或删除节点要执行更新)
template<typename T>
void myBinTree<T>::updateHeightAbove(myBinNode<T>* bn)
{
	while (bn)
	{
		updateHeight(bn);
		bn = bn->parent;
	}
}

// 删除节点bn及其后代,并返回删掉的二叉树节点的总数
template<typename T>
int myBinTree<T>::removeAt(myBinNode<T>* bn)
{
	int n = 0;
	if (bn == nullptr)
		return 0;
	n = 1 + removeAt(bn->lchild) + removeAt(bn->rchild);
	delete bn;
	return n;
}

// 删除以bn为根节点的子树
template<typename T>
int myBinTree<T>::remove(myBinNode<T>* bn)
{
	if (bn != m_pRoot)
	{
		((bn->parent->lchild) == bn) ? (bn->parent->lchild) = nullptr : (bn->parent->rchild) = nullptr;// 将父节点对应左\右孩子置空
	}
	myBinNode<T>* bp = bn->parent;
	int n = removeAt(bn);
	updateHeightAbove(bp);
	m_size -= n;
	return n;
}

// 子树分离,将节点bn及其后代从二叉树中分离出来,然后形成一个独立的二叉树
template<typename T>
myBinTree<T>* myBinTree<T>::secede(myBinNode<T>* bn)
{
	if (bn != m_pRoot)
	{
		((bn->parent->lchild) == bn) ? (bn->parent->lchild) = nullptr : (bn->parent->rchild) = nullptr;
	}
	// 更新height
	myBinNode<T>* bp = bn->parent;
	updateHeightAbove(bp);

	// 封装成新二叉树
	myBinTree<T>* bt = new myBinTree<T>();
	bt->m_pRoot = bn;
	bn->parent = nullptr;
	// 更新size
	bt->m_size = bn->size();
	m_size -= bt->m_size;

	// 特殊情况处理
	if (m_pRoot == bn)
		m_pRoot = nullptr;
	return bt;
}

// 先序遍历(递归版本:简洁易懂)
template<typename T>
void myBinTree<T>::travPre_R(myBinNode<T>* bn_r, void(*func)(T& bn))
{
	if (!bn_r) return;
	func(bn_r->data);
	travPre_R(bn_r->lchild, func);
	travPre_R(bn_r->rchild, func);
}

// 中序遍历(递归版本:简洁易懂)
template<typename T>
void myBinTree<T>::travIn_R(myBinNode<T>* bn_r, void(*func)(T& bn))
{
	if (!bn_r) return;
	travIn_R(bn_r->lchild, func);
	func(bn_r->data);
	travIn_R(bn_r->rchild, func);
}

// 后序遍历(递归版本:简洁易懂)        
template<typename T>
void myBinTree<T>::travPost_R(myBinNode<T>* bn_r, void(*func)(T& bn))
{
	if (!bn_r) return;
	travPost_R(bn_r->lchild, func);
	travPost_R(bn_r->rchild, func);
	func(bn_r->data);
}

// 沿着左轮廓线遍历
template<typename T>
void myBinTree<T>::visitAlongLeftBranch(myBinNode<T>* bn, void(*func)(T& bn), stack<myBinNode<T>*> &s)
{
	while (bn)
	{
		func(bn->data);
		s.push(bn->rchild);		// 右孩子入栈
		bn = bn->lchild;		// 沿着左边沿遍历
	}
}

// 先序遍历(迭代版本:时间、空间复杂度低)
template<typename T>
void myBinTree<T>::travPre_I(myBinNode<T>* bn_i, void(*func)(T& bn))
{
	stack<myBinNode<T>*> s;
	while (true)
	{
		visitAlongLeftBranch(bn_i, func, s);	// 遍历且入栈
		if (s.empty()) break;
		bn_i = s.top();
		s.pop();
	}
}

// 从当前节点开始,沿着左分支深入入栈
template<typename T>
void myBinTree<T>::goAlongLeftBranch(myBinNode<T>* bn, stack<myBinNode<T>*> &s)
{
	while (bn)
	{
		s.push(bn);
		bn = bn->lchild;
	}
}

// 中序遍历(迭代版本:时间、空间复杂度低)
template<typename T>
void myBinTree<T>::travIn_I(myBinNode<T>* bn_i, void(*func)(T& bn))
{
	stack<myBinNode<T>*> s;
	while (true)
	{
		goAlongLeftBranch(bn_i, s);
		if (s.empty()) break;
		bn_i = s.top();
		s.pop();
		func(bn_i->data);
		bn_i = bn_i->rchild;
	}
}

// 在以s栈顶节点为根的子树中,找到最高左侧可见节点
template<typename T>
void myBinTree<T>::gotoHLVFL(stack<myBinNode<T>*> &s)
{
	while (myBinNode<T>* bn_i = s.top())
	{
		if (bn_i->lchild)
		{
			if (bn_i->rchild)
				s.push(bn_i->rchild);
			s.push(bn_i->lchild);
		}
		else// if (bn_i->rchild) 不能判断,不然存在跳不出这个while语句
		{
			s.push(bn_i->rchild);
		}
	}
	s.pop();// 移除空指针
}

// 后序遍历(迭代版本:时间、空间复杂度低)
template<typename T>
void myBinTree<T>::travPost_I(myBinNode<T>* bn_i, void(*func)(T& bn))
{
	stack<myBinNode<T>*> s;
	if (bn_i)
		s.push(bn_i);
	while (!s.empty())
	{
		if (s.top() != bn_i->parent)// 防止再次遍历左右节点
			gotoHLVFL(s);
		bn_i = s.top();
		s.pop();
		func(bn_i->data);
	}
}

// 层次遍历
template<typename T>
void myBinTree<T>::travLevel(myBinNode<T>* bn_i, void(*func)(T& bn))
{
	queue<myBinNode<T>*> q;
	if (bn_i)
		q.push(bn_i);
	while (!q.empty())  // 队列非空
	{
		bn_i = q.front();
		q.pop();
		func(bn_i->data);
		if (bn_i->lchild)
			q.push(bn_i->lchild);
		if (bn_i->rchild)
			q.push(bn_i->rchild);
	}
}



treeMain.cpp:功能测试
#include "myBinTree.h"
#include "myBinTree.cpp"
#include <iostream>

template<typename T>
void printfFunc(T& data)
{
	cout << data << " ";
}
typedef void(*pFun)(int& data);


int main()
{
	/************************************************************************/
	/* 本案例中二叉树的结构体
					0
			1				2
		3		4				5
	6						7
	*/
	/************************************************************************/


	myBinTree<int>* tree = new myBinTree<int>();
	tree->insertAsRoot(0);
	myBinNode<int>* node1 = tree->insertAsLChild(tree->getRoot(), 1);
	myBinNode<int>* node4 = tree->insertAsRChild(node1, 4);
	myBinNode<int>* node3 = tree->insertAsLChild(node1, 3);
	myBinNode<int>* node6 = tree->insertAsLChild(node3, 6);

	myBinNode<int>* node2 = tree->insertAsRChild(tree->getRoot(), 2);
	myBinNode<int>* node5 = tree->insertAsRChild(node2, 5);
	myBinNode<int>* node7 = tree->insertAsLChild(node5, 7);

	pFun pfun = printfFunc;
	// 先序遍历01364257
	cout << "--------------先序遍历--------------" << endl;
	tree->travPre_R(tree->getRoot(), printfFunc);
	cout << endl;
	tree->travPre_I(tree->getRoot(), pfun);
	cout << endl;

	// 中序遍历63140275
	cout << "--------------中序遍历--------------" << endl;
	tree->travIn_R(tree->getRoot(), printfFunc);
	cout << endl;
	tree->travIn_I(tree->getRoot(), pfun);
	cout << endl;

	// 后序遍历63417520
	cout << "--------------后序遍历--------------" << endl;
	tree->travPost_R(tree->getRoot(), printfFunc);
	cout << endl;
	tree->travPost_I(tree->getRoot(), pfun);
	cout << endl;

	// 层次遍历01234567
	cout << "--------------层次遍历--------------" << endl;
	tree->travLevel(tree->getRoot(), printfFunc);

	getchar();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用以下方法来实现输出所有二叉树直径及其路径长度的功能: ```java import java.util.ArrayList; import java.util.List; public class BinaryTree<T> { private Node<T> root; // 其他方法省略... public static <T> void diameterAll(BinaryTree<T> bitree) { if (bitree.root == null) { System.out.println("二叉树为空!"); return; } List<Node<T>> path = new ArrayList<>(); int[] diameter = new int[1]; diameterAllHelper(bitree.root, path, diameter); System.out.println("直径:"); for (int i = 0; i < path.size(); i++) { Node<T> node = path.get(i); System.out.print(node.data + " "); if (i < path.size() - 1) { System.out.print("-> "); } } System.out.println(); System.out.println("路径长度:" + diameter[0]); } private static <T> int diameterAllHelper(Node<T> node, List<Node<T>> path, int[] diameter) { if (node == null) { return 0; } int leftHeight = diameterAllHelper(node.left, path, diameter); int rightHeight = diameterAllHelper(node.right, path, diameter); int currentDiameter = leftHeight + rightHeight + 1; if (currentDiameter > diameter[0]) { diameter[0] = currentDiameter; path.clear(); addPath(node.left, path); path.add(node); addPath(node.right, path); } return Math.max(leftHeight, rightHeight) + 1; } private static <T> void addPath(Node<T> node, List<Node<T>> path) { if (node == null) { return; } addPath(node.left, path); path.add(node); addPath(node.right, path); } private static class Node<T> { private T data; private Node<T> left; private Node<T> right; public Node(T data) { this.data = data; } } } ``` 您可以将上述代码保存为`BinaryTree.java`文件,并在您的程序中使用`BinaryTree.diameterAll(bitree)`来输出所有二叉树直径及其路径长度。请注意,上述代码假设您已经实现了其他必要的二叉树操作方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值