【剑指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.效果截图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
二叉树是一种常用的数据结构,它由一个根节点和最多两个子树构成,其中左子树和右子树也是二叉树。下面是一个基于C++二叉树数据结构实现。 ```c++ #include <iostream> using namespace std; // 二叉树节点结构体 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; // 二叉树类 class BinaryTree { private: TreeNode* root; // 根节点 public: BinaryTree() : root(nullptr) {} // 构造函数 // 插入节点 void insert(int val) { if (root == nullptr) { // 如果根节点为空,插入根节点 root = new TreeNode(val); return; } TreeNode* cur = root; while (true) { // 找到插入位置 if (val < cur->val) { // 如果小于当前节点,往左子树找 if (cur->left == nullptr) { // 如果左子树为空,插入左子树 cur->left = new TreeNode(val); return; } cur = cur->left; } else { // 如果大于等于当前节点,往右子树找 if (cur->right == nullptr) { // 如果右子树为空,插入右子树 cur->right = new TreeNode(val); return; } cur = cur->right; } } } // 中序遍历 void inorder(TreeNode* cur) { if (cur != nullptr) { inorder(cur->left); cout << cur->val << " "; inorder(cur->right); } } void inorderTraversal() { cout << "中序遍历结果:"; inorder(root); cout << endl; } }; int main() { BinaryTree bt; bt.insert(5); bt.insert(7); bt.insert(2); bt.insert(8); bt.insert(1); bt.inorderTraversal(); // 中序遍历结果:1 2 5 7 8 return 0; } ``` 在这个实现中,我们定义了一个二叉树节点结构体,其中包括节点的值,左子树针和右子树针。我们还定义了一个二叉树类,其中包括根节点针和插入节点、中序遍历等方法。在插入节点时,我们从根节点开始遍历找到插入位置。在中序遍历时,我们先递归遍历左子树,输出当前节点的值,再递归遍历右子树。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

方寸间沧海桑田

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

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

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

打赏作者

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

抵扣说明:

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

余额充值