二叉树系列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/83626725

 涉及到二叉树的题,大部分是利用递归求解,因为二叉树这种结构看不见、摸不着,只能交给程序一层一层跑,而且主要是因为结构相同。

剑指Offer(7)--重建二叉树

由前序遍历和中序遍历得整棵二叉树

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
BinaryTreeNode *construct(int *preorder, int *inorder, int length)
{
	if (preorder == nullptr || inorder == nullptr || length < 1)
		return nullptr;
	return constructCore(preorder, preorder + length - 1, inorder, inorder + length - 1);
}
BinaryTreeNode *constructCore(int *startPreorder, int *endPreorder,
	int *startInorder, int *endInorder)
{
	int rootValue = startInorder[0];
	BinaryTreeNode *rootNode = new BinaryTreeNode();
	rootNode->m_Value = rootValue;
	rootNode->m_Left = rootNode->m_Right = nullptr;
	if (startPreorder == endPreorder)
	{
		if (startInorder == endInorder && *startPreorder == *startInorder)
			return rootNode;
		else
			return nullptr;
	}
	int *rootInorder = startInorder;
	//在中序遍历中找到根结点rootInorder
	while (rootInorder <= endInorder && *rootInorder == rootValue)
		++rootInorder;
	int length = rootInorder - startInorder;
	int *leftPreorder = startPreorder + length;
	if (length > 0)
	{
		//构建左子树
		rootNode->m_Left = constructCore(startPreorder + 1, leftPreorder, startInorder, rootInorder-1);
	}
	if (length < endPreorder - startPreorder)
	{
		//构建右子树
		rootNode->m_Right = constructCore(leftPreorder + 1, endPreorder, rootInorder + 1, endInorder);
	}
	return rootNode;
}

  剑指Offer(8)--二叉树的下一个节点

给定一棵二叉树和其中的一个节点,找出中序遍历序列的下一个节点。

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
	BinaryTreeNode *m_parent;
};
//辅助函数,找右子树的最左节点
BinaryTreeNode *mostLeftNode(BinaryTreeNode *node)
{
	if (node->m_Right == nullptr)
		return nullptr;
	else
	{
		BinaryTreeNode *leftNode = node->m_Right;
		while (leftNode->m_Left != nullptr)
			leftNode = leftNode->m_Left;
		return leftNode;
	}
}
BinaryTreeNode *findNextNode(BinaryTreeNode *node)
{
	if (node == nullptr)
		return nullptr;
	//该节点的右子树不为空的情况
	if (node->m_Right != nullptr)
		return mostLeftNode(node);
	//该节点的右子树为空
	else
	{
		BinaryTreeNode *parentNode = node->m_parent;
		while (parentNode != nullptr)
		{
			if (parentNode->m_Left == node)
				return parentNode;
			else
			{
				node = parentNode;
				parentNode = node->m_parent;
			}
		}
		return nullptr;
	}
}

剑指Offer(26)--树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构

#include<iostream>
#include<queue>
using namespace std;
struct BinaryTreeNode
{
	double m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
bool Equal(double num1, double num2);
bool isSubTreeCore(BinaryTreeNode *node1, BinaryTreeNode *node2);
bool isSubTree(BinaryTreeNode *head1, BinaryTreeNode *head2)
{
	bool result = false;
	if (head1 != nullptr && head2 != nullptr)
	{
		if (head1->m_Value == head2->m_Value)
			result = isSubTreeCore(head1, head2);
		if (!result)
			result = isSubTree(head1->m_Left, head2);
		if(!result)
			result = isSubTree(head1->m_Right, head2);
	}
	return result;
}
bool isSubTreeCore(BinaryTreeNode *node1, BinaryTreeNode *node2)
{
	if (node2 == nullptr)
		return true;
	if (node1 == nullptr)
		return false;
	bool result = false;
	if (!Equal(node1->m_Value, node2->m_Value))
		return false;
	return isSubTreeCore(node1->m_Left, node2->m_Left) && isSubTreeCore(node2->m_Right, node2->m_Right);
}
/*
不能直接用等号判断两个小数是否相等,因为计算机表示小数(float,double)会有误差
*/
bool Equal(double num1, double num2)
{
	if ((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
		return true;
	else
		return false;
}

 剑指Offer(27)--二叉树的镜像

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
void mirrorTree(BinaryTreeNode *head)
{
	if (head == nullptr)
		return;
	if (head->m_Left == nullptr && head->m_Right == nullptr)
		return;
	BinaryTreeNode *tempNode = head->m_Left;
	head->m_Left = head->m_Right;
	head->m_Right = tempNode;
	if (head->m_Left != nullptr)
		mirrorTree(head->m_Left);
	if (head->m_Right != nullptr)
		mirrorTree(head->m_Right);
}

 剑指Offer(28)--对称的二叉树

如果一棵二叉树和它的镜像一样,那么它是对称的。

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
bool isSymmrtryCore(BinaryTreeNode *node1, BinaryTreeNode *node2);
bool isSymmrtry(BinaryTreeNode *head)
{
	return isSymmrtryCore(head, head);
}
bool isSymmrtryCore(BinaryTreeNode *node1, BinaryTreeNode *node2)
{
	if (node1 == nullptr && node2 == nullptr)
		return true;
	if (node1 == nullptr || node2 == nullptr)
		return false;
	if (node1->m_Value != node2->m_Value)
		return false;
	return (isSymmrtryCore(node1->m_Left, node2->m_Right) &&
		isSymmrtryCore(node1->m_Right, node2->m_Left));
}

 剑指Offer(32)--从上到下打印二叉树和之字形打印二叉树

从上到下打印二叉树其实就是层次遍历二叉树

#include<iostream>
#include<queue>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
void PrintTree(BinaryTreeNode *head)
{
	if (head == nullptr)
		return;
	queue<BinaryTreeNode*> q;
	q.push(head);
	while (!q.empty())
	{
		BinaryTreeNode *node = q.front();
		cout << node->m_Value << " ";
		q.pop();
		if (node->m_Left != nullptr)
			q.push(node->m_Left);
		if (node->m_Right != nullptr)
			q.push(node->m_Right);
	}
}

之字形打印二叉树思路:定义两个栈,在打印一个栈里的节点时,它的子节点保存到另一个栈里。当一层所有的节点打印完毕时,开始打印另一个栈里的元素。

如果打印的是奇数层,则先保存左子节点再保存右子节点到另一个栈里;如果当前打印的是偶数层,则先保存右子节点再保存左子节点到另一个栈里。 

#include<iostream>
#include<stack>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
void PrintTree(BinaryTreeNode *head)
{
	if (head == nullptr)
		return;
	stack<BinaryTreeNode*> s[2];
	int current = 0;
	int next = 1;
	s[0].push(head);
	while (!s[0].empty() || !s[1].empty())
	{
		BinaryTreeNode *node = s[current].top();
		s[current].pop();
		cout << node->m_Value << " ";
		if (current == 0)
		{
			if (node->m_Left != nullptr)
				s[next].push(node->m_Left);
			if (node->m_Right != nullptr)
				s[next].push(node->m_Right);
		}
		else
		{
			if (node->m_Right != nullptr)
				s[next].push(node->m_Right);
			if (node->m_Left != nullptr)
				s[next].push(node->m_Left);
		}
		if (s[current].empty())
		{
			cout << endl;
			current = 1 - current;
			next = 1 - next;
		}
	}
}

剑指Offer(34)--二叉树中和为某一值的路径

输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

#include<iostream>
#include<vector>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
void FindPath(BinaryTreeNode *head, int sum)
{
	if (head == nullptr)
		return;
	vector<int> path;
	int currentSum = 0;
	FindPathCore(head, sum, path, currentSum);
}
void FindPathCore(BinaryTreeNode *node, int sum, vector<int>& path, int currentSum)
{
	if (node == nullptr)
		return;
	currentSum += node->m_Value;
	path.push_back(node->m_Value);
	if (node->m_Left == nullptr && node->m_Right == nullptr && currentSum == sum)
	{
		vector<int>::iterator iter = path.begin();
		for (; iter != path.end(); ++iter)
			cout << *iter << "	";
		cout << endl;
	}
	//如果不是叶结点,则遍历它的子节点
	if (node->m_Left != nullptr)
		FindPathCore(node->m_Left, sum, path, currentSum);
	if (node->m_Right != nullptr)
		FindPathCore(node->m_Right, sum, path, currentSum);
	//在返回父节点之前,在路径上删除这个节点
	path.pop_back();
}

剑指Offer(37)--序列化二叉树

#include<iostream>
#include<queue>
#include<string>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
//先序序列化二叉树
string serialByPre(BinaryTreeNode *head)
{
	if (head == NULL)
		return "#_";
	string res = to_string(head->m_Value).append("_");
	res += serialByPre(head->m_Left);
	res += serialByPre(head->m_Right);
	return res;
}
//先序遍历的反序列化
BinaryTreeNode *reconPre(queue<string>& qNode)
{
	string value = qNode.front();
	qNode.pop();
	if (value == "#_")
		return NULL;
	//stoi:将n进制的字符串转化为十进制
	BinaryTreeNode *head = new BinaryTreeNode();
	head->m_Value = stoi(value);
	head->m_Left = reconPre(qNode);
	head->m_Right = reconPre(qNode);
	return head;
}

 剑指Offer(55)--二叉树的深度和平衡二叉树

二叉树的深度

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
int max(int a, int b)
{
	if (a > b)
		return a;
	else
		return b;
}
int DepthTree(BinaryTreeNode *head)
{
	if (head == nullptr)
		return 0;
	return max(DepthTree(head->m_Left), DepthTree(head->m_Right)) + 1;
}

平衡二叉树

第一种方法是:对二叉树中的每一个节点从根到叶,依次进行判断,但这样效率不高,会有重复计算。

第二种方法如下所示:用后序遍历的方式遍历二叉树的每个节点,那么在遍历到一个节点之前就直到它的左右子树是否为平衡二叉树。

#include<iostream>
#include<stack>
using namespace std;
struct BinaryTreeNode
{
	int m_Value;
	BinaryTreeNode *m_Left;
	BinaryTreeNode *m_Right;
};
int max(int a, int b)
{
	if (a > b)
		return a;
	else
		return b;
}
bool IsBance(BinaryTreeNode *head)
{
	int depth = 0;
	return IsBanlanceCore(head, &depth);
}
bool IsBanlanceCore(BinaryTreeNode *head, int *depth)
{
	if (head == nullptr)
	{
		*depth = 0;
		return true;
	}
	int left, right;
	if (IsBanlanceCore(head->m_Left, &left) && IsBanlanceCore(head->m_Right, &right))
	{
		int distance = left - right;
		if (distance <= 1 && distance >= -1)
		{
			*depth = 1 + max(left, right);
			return true;
		}
	}
	return false;
}

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/83626725