【剑指offer】面试题7前置 二叉树的数据结构实现

本文介绍了一种二叉树的实现方法,包括二叉树节点类与二叉树类的设计,并详细展示了前序、中序、后序遍历的递归与迭代实现过程。此外,还提供了节点高度更新的算法。

这几天尬在二叉表的实现了,发现删除节点是真的写的头疼,最后还是没有实现。迭代遍历也是,但是掌握了思想之后也还是能实现,大概就这样吧

1.二叉树类与二叉树节点类

template<typename T> class BinaryTreeNode
{
public:
	T m_value;
	int m_height;
	BinaryTreeNode() {}
	BinaryTreeNode(T value) : m_value(value) {}
	BinaryTreeNode<T> *m_leftchild;
	BinaryTreeNode<T> *m_rightchild;
	BinaryTreeNode<T> *m_parent;
};

template<typename T> class BinaryTree
{
public:
	BinaryTreeNode<T> *m_root;
	void visit(BinaryTreeNode<T>* node) { cout << node->m_value << " "; }
	//三种递归遍历方式,究极简单并且易于理解(均从根节点开始,按顺序递归即可)
	void travPre_Recursion(BinaryTreeNode<T>* node);
	void travMid_Recursion(BinaryTreeNode<T>* node);
	void travPos_Recursion(BinaryTreeNode<T>* node);
	void travPre_Circulate(BinaryTreeNode<T>* node);
	void travMid_Circulate(BinaryTreeNode<T>* node);
	void travPos_Circulate(BinaryTreeNode<T>* node);
	int m_size;
	void updateHeight(BinaryTreeNode<T>* node);
	BinaryTree() : m_size(0), m_root(NULL) {};
	BinaryTreeNode<T>* insertAsRoot(T const &value);
	int remove(BinaryTreeNode<T>* node);  //返回由于此节点被删除而导致删除的节点总数
	int removeAt(BinaryTreeNode<T>* node);
	BinaryTreeNode<T>* insertAsLeftChild(BinaryTreeNode<T>* parent, T const &value);
	BinaryTreeNode<T>* insertAsRightChild(BinaryTreeNode<T>* parent, T const &value);
};

2.相关函数的实现代码

2.1 前序中序后序递归遍历
  • 简单无脑,visit函数为数据处理函数
template<typename T> void BinaryTree<T>::travPre_Recursion(BinaryTreeNode<T>* node)
{
	if (node == NULL)
		return;
	visit(node);
	travPre_Recursion(node->m_leftchild);
	travPre_Recursion(node->m_rightchild);
}

template<typename T> void BinaryTree<T>::travMid_Recursion(BinaryTreeNode<T>* node)
{
	if (node == NULL)
		return;
	travMid_Recursion(node->m_leftchild);
	visit(node);
	travMid_Recursion(node->m_rightchild);
}

template<typename T> void BinaryTree<T>::travPos_Recursion(BinaryTreeNode<T>* node)
{
	if (node == NULL)
		return;
	travPos_Recursion(node->m_leftchild);
	travPos_Recursion(node->m_rightchild);
	visit(node);
}
2.2 前序中序后序迭代遍历
  • 迭代的实现主要是思想,本文中使用的为:确定起始点,根据起始点按照标准流程不断向前计算(核心思想是,对应不同顺序,对于栈中节点的操作,以及节点的存储方式均有所不同)
template<typename T> void BinaryTree<T>::travPre_Circulate(BinaryTreeNode<T>* node)
{
	stack<BinaryTreeNode<T>*> sss;
	list<BinaryTreeNode<T>*> slist;

	//1.先序遍历,灵魂的根—左—右,按照所经过的顺序直接进行遍历
	sss.push(node);
	while (!sss.empty())
	{
		node = sss.top(); sss.pop();
		slist.push_back(node);
		if (node->m_rightchild != NULL)
		{
			sss.push(node->m_rightchild);
		}
		if (node->m_leftchild != NULL)
		{
			sss.push(node->m_leftchild);
		}
	}

	for (auto &s : slist)
		cout << s->m_value << " ";
}

template<typename T> void BinaryTree<T>::travMid_Circulate(BinaryTreeNode<T>* node)
{
	stack<BinaryTreeNode<T>*> sss;
	list<BinaryTreeNode<T>*> slist;

	//2.中序遍历,独特的左—根—右,首先找到初始节点为最左边的值,然后根据左—根—右开始遍历
	//do while的原因在于最开始栈一直为空
	do 
	{
		while (node != NULL) 
		{
			sss.push(node);
			node = node->m_leftchild;
		}
		if (!sss.empty()) 
		{
			node = sss.top(); sss.pop();
			slist.push_back(node);
			node = node->m_rightchild;
		}
	} while (!sss.empty() || node != NULL);

	for (auto &s : slist)
		cout << s->m_value << " ";
}

template<typename T> void BinaryTree<T>::travPos_Circulate(BinaryTreeNode<T>* node)
{
	stack<BinaryTreeNode<T>*> sss;
	list<BinaryTreeNode<T>*> slist;

	//后序遍历为左—右—根,实现方式为反转后调整左右先后顺序
	sss.push(node);
	while (!sss.empty())
	{
		node = sss.top(); sss.pop();
		slist.push_front(node);
		if (node->m_leftchild != NULL)
		{
			sss.push(node->m_leftchild);
		}
		if (node->m_rightchild != NULL)
		{
			sss.push(node->m_rightchild);
		}
	}

	for (auto &s : slist)
		cout << s->m_value << " ";
}
2.3 节点高度更新函数
  • 每当有节点插入/退出二叉树中时,调用高度更新,更新其所有父节点的高度数值(核心思想在于,父树高度为子树高度+1,而没有子树的节点高度为0(-1+1))
template<typename T> void BinaryTree<T>::updateHeight(BinaryTreeNode<T>* node)
{
	if (node == NULL)
		return;
	int leftHeight = -1;
	if (node->m_leftchild != NULL)
		leftHeight = node->m_leftchild->m_height;
	int rightHeight = -1;
	if (node->m_rightchild != NULL)
		rightHeight = node->m_rightchild->m_height;
	node->m_height = 1 + ((leftHeight > rightHeight) ? (leftHeight) : (rightHeight));
	updateHeight(node->m_parent);
}
2.4 根节点左节点右节点的插入
  • 顾名思义的函数功能
template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsRoot(T const &value)
{
	BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
	node->m_value = value;
	if (m_root == NULL)
	{
		m_root = node;
	}
	else
	{
		m_root->m_parent = node;
		node->m_leftchild = m_root;
		m_root = node;
	}
	m_size++;
	return node;
}

template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsLeftChild(BinaryTreeNode<T>* parent, T const &value)
{
	BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
	node->m_value = value;
	node->m_parent = parent;
	parent->m_leftchild = node;
	m_size++;
	updateHeight(node->m_parent);
	return node;
}

template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsRightChild(BinaryTreeNode<T>* parent, T const &value)
{
	BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
	node->m_value = value;
	node->m_parent = parent;
	parent->m_rightchild = node;
	m_size++;
	updateHeight(node->m_parent);
	return node;
}
3.测试用主函数
  • remove函数终究还是没有实现,所以就只测试了插入、高度与遍历
int main()
{
	BinaryTree<int>* tree = new BinaryTree<int>;
	BinaryTreeNode<int>* node0 = tree->insertAsRoot(0);
	BinaryTreeNode<int>* node1 = tree->insertAsLeftChild(node0, 1);
	BinaryTreeNode<int>* node2 = tree->insertAsRightChild(node0, 2);
	BinaryTreeNode<int>* node3 = tree->insertAsLeftChild(node1, 3);
	BinaryTreeNode<int>* node4 = tree->insertAsRightChild(node1, 4);
	BinaryTreeNode<int>* node5 = tree->insertAsLeftChild(node2, 5);
	BinaryTreeNode<int>* node6 = tree->insertAsRightChild(node2, 6);

	cout << "迭代前序遍历:";
	tree->travPre_Recursion(tree->m_root);
	cout << endl;
	cout << "迭代中序遍历:";
	tree->travMid_Recursion(tree->m_root);
	cout << endl;
	cout << "迭代后序遍历:";
	tree->travPos_Recursion(tree->m_root);
	cout << endl; 
	cout << "循环前序遍历:";
	tree->travPre_Circulate(tree->m_root);
	cout << endl;
	cout << "循环中序遍历:";
	tree->travMid_Circulate(tree->m_root);
	cout << endl;
	cout << "循环后序遍历:";
	tree->travPos_Circulate(tree->m_root);
	cout << endl;
	
	cout << "node0 height:" << node0->m_height << endl;
	cout << "node1 height:" << node1->m_height << endl;
	cout << "node2 height:" << node2->m_height << endl;
	cout << "node3 height:" << node3->m_height << endl;
	//这里涉及到的delete,释放的时机应该是“谁申请,谁释放”;
	//cout << "tree->remove(node1):" << tree->remove(node1) << endl;
	//cout << "tree->remove(node2):" << tree->remove(node2) << endl;
	//cout << "tree->remove(node3):" << tree->remove(node3) << endl;
	//cout << "tree->remove(node0):" << tree->remove(node0) << endl;

	delete node3;
	delete node2;
	delete node1;
	delete node0;

	return 0;
}

4.效果截图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方寸间沧海桑田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值