剑指offer 二叉搜索树的后序遍历序列(C++)(四种解法)

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解题思路

1、二叉搜索树 又叫 二叉排序树,是一个递归的树型结构:

如果根结点为空,返回false;

根结点的左孩子结点值小于根结点,根结点右孩子结点值大于根结点。

根结点的左右子树分别满足上述条件。

中序遍历二叉搜索树可得到递增的序列。

2、判断一个二叉树后序遍历序列是否为二叉搜索树,必须满足数组前半部分序列小于数组的最后一位数(根结点值),后半部分序列(除去最后一个结点)大于数组的最后一个元素,而且其每个部分的序列也要满足以上条件。

3、可用如下4种方法(实则2种 递归 非递归)解答此题。

代码实现

1、 由于需要标记数组序列中的左子树序列范围和右子树序列的范围,故需要重新定义函数将数组下标的参数加入到函数之中。

由于该函数为bool类型,定义两个bool变量来接收左子树序列和右子树序列的真假性,由于函数体中只给定了出现false的情况,没有直接对true的情况进行判断,所以两个变量的初始化为true,如果整个数组序列没有返回false并且左右子树也没有返回false的话,函数体便会返回两个bool变量的初试值——true,否则返回false。

由于二叉树不一定为完全二叉树或者是满二叉树,在递归的过程中,可能出现分枝树中为单支树的情况,必须对数组下标的越界问题进行判断,在出现单支树的情况下,是可以出现左子树或者是右子树为空的情况,此时若不进行判断,则会在下一轮进入递归函数中执行if (sequence.empty()) return false;直接返回false,导致误判。

class Solution
{
	//第一个函数为自定义函数
	bool VerifyVectorOfBST(vector<int> sequence, int start, int end)//int 为数组下标
	{
		int i = 0, j = 0;
		for (i = 0; i < end; i++)
		{
			if (sequence[i] > sequence[end])
			{
				break;
			}
		}
		for (j = i; j < end; j++)
		{
			if (sequence[j] < sequence[end])
			{
				return false;
			}
		}
		bool leftBST = true, rightBST = true; // 先定义好true类型
		if (i > start)
		{
			leftBST = VerifyVectorOfBST(sequence, start, i - 1); //判断数组下标是否越界
		}
		if (i < end - 1)
		{
			rightBST = VerifyVectorOfBST(sequence, i, end - 1);
		}
		
		return leftBST && rightBST;
	}
	
	bool VerifySquenceOfBST(vector<int> sequence) {
		if (sequence.empty())
		{
			return false;
		}
		return VerifyVectorOfBST(sequence, 0, sequence.size() - 1); // 数组下标
	}
}

2、 可以使用迭代器来标记动态数组中左子树和右子树边界的下标,进而实现函数的递归,思路和方法1一致。

bool VerifySquenceOfBST(vector<int> sequence) // 可以使用迭代器
{
	if (sequence.empty())
		return false;
	vector<int>::iterator itFirst = sequence.begin(), itLast;
	for (; itFirst < sequence.end() - 1; itFirst++)
	{
		if (*itFirst > *(sequence.end() - 1))
		{
			break;
		}
	}
	for (itLast = itFirst; itLast < sequence.end() - 1; itLast++)
	{
		if (*itLast < *(sequence.end() - 1))
		{
			return false;
		}
	}
	bool leftTree = true, rightTree = true;;
	if (itFirst > sequence.begin())
	{
		leftTree = VerifySquenceOfBST(vector<int>(sequence.begin(), itFirst)); // 这一个重要的语法知识
	}
	if (itLast < sequence.end() - 1)
	{
		rightTree = VerifySquenceOfBST(vector<int>(itFirst, sequence.end() - 1));
	}
	return leftTree && rightTree;
}

重要语法知识: 相当于动态数组下标范围

leftTree = VerifySquenceOfBST(vector<int>(sequence.begin(), itFirst));

3、 新建两个vector容器去存储数组中的左右子树,进入新的递归函数,思路与1、2一致。

bool VerifySquenceOfBST(vector<int> sequence) // 记得考虑数组下标不能越界
{
	if (sequence.empty())
	{
		return false;
	}
	int i = 0, j = 0;
	vector<int> preV, postV;
	for (; i < sequence.size() - 1; i++)
	{
		if (sequence[i] < sequence.back())
		{
			preV.push_back(sequence[i]);
		}
		else
		{
			break;
		}
	}
	for (j = i; j < sequence.size() - 1; j++)
	{
		if (sequence[j] > sequence.back())
		{
			postV.push_back(sequence[j]);
		}
		else
		{
			return false;
		}
	}
	bool leftTree = true, rightTree = true;
	if (i > 0)
	{
		leftTree = VerifySquenceOfBST(preV);
	}
	if (i < sequence.size() - 1)
	{
		rightTree = VerifySquenceOfBST(postV);
	}
	return leftTree && rightTree;
}

4、 非递归法

这个思路的构思就很巧妙了,首先将length等于数组的长度,在每次循环减1的过程中,如果保证了树的左子树小于根结点,右子树大于根结点,根结点不存在时,左子树小于右子树,符合二叉搜索树的定义。

bool VerifySquenceOfBST(vector<int> sequence)
{
	int i = 0;
	int length = sequence.size();
	if (length == 0)
	{
		return false;
	}
	while (--length)
	{
		while (sequence[i++] < sequence[length]);
		while (sequence[i++] > sequence[length]);
		if (i < length)
		{
			return false;
		}
		i = 0;
	}
	return true;
}

放上主函数,以便在自己电脑的IDE上运行。

void main()
{
	vector<int> sequence;
	sequence.push_back(4);
	sequence.push_back(6);
	sequence.push_back(7);
	sequence.push_back(5);

	cout << VerifySquenceOfBST(sequence) << endl; // 1

	system("pause");
 	return;
}

总结

涉及到bool类型的递归函数,有如下感想:

首先要对所给参数的合法性进行判断。

函数体中要对返回值为true和false进行明确的声明。

递归函数要么作为返回值,要么在判断语句中,要么指向bool类型的变量并最终返回该变量。

考虑问题要全面,比如二叉树类型,在递归中要求对参数是否合法进行判断,递归函数中参数的合法性有可能和主函数参数的合法性不同,视情况而定。

发布了54 篇原创文章 · 获赞 3 · 访问量 916
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览