二叉树相关面试题

<pre name="code" class="html">/******************************************************************************************
Copyright (c) Inc.(2013), All rights reserved.

Purpose: 实现二叉树的基本面试题    

Author: MaJing

Reviser: yyy

Created Time: 2016-9-5
******************************************************************************************/


// ps:1-6题在在二叉树基础部分已经实现
//1. 前序/中序/后序遍历
//2. 层序遍历
//3. 求二叉树的高度
//4. 求叶子节点的个数
//5. 求二叉树第k层的节点个数
//6. 判断一个节点是否在一棵二叉树中
//7. 求两个节点的最近公共祖先
//8. 判断一棵二叉树是否是平衡二叉树
//9. 求二叉树中最远的两个节点的距离
//10. 由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 5 6)
//11. 判断一棵树是否是完全二叉树
//12. 求二叉树的镜像【y】
//13. 将二叉搜索树转换为双向链表


#pragma once

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

//
// 定义以下结构仅用于二叉树笔试面试题进行测试。
//
typedef int DataType;

struct BinaryTreeTopic
{
	struct BinaryTreeNode
	{
		DataType _data;				// 结点数据
		BinaryTreeNode* _left;		// 左子树
		BinaryTreeNode* _right;		// 右子树

		BinaryTreeNode(int data)
			:_data(data)
			,_left(0)
			,_right(0)
		{}
	};

	void CreateBinaryTree(BinaryTreeNode*& root, const vector<DataType>& vDatas, int& i)
	{
		// 前序遍历创建二叉树
		if(i < vDatas.size() && vDatas[i] !=  '#')
		{
			root = new BinaryTreeNode(vDatas[i]);
			CreateBinaryTree(root->_left, vDatas, ++i);
			CreateBinaryTree(root->_right, vDatas, ++i);
		}
	}

	BinaryTreeNode* Find(BinaryTreeNode* root, DataType x)
	{
		BinaryTreeNode* ret;
		if (root == NULL)
			return NULL;

		if (root->_data == x)
			return root;

		if (ret = Find(root->_left, x))
			return ret;

		if (ret = Find(root->_right, x))
			return ret;

		return NULL;
	}

	// 前序/中序/后序遍历
	void PrevOrder(BinaryTreeNode* root)
	{
		if (root)
		{
			cout<<root->_data<<" ";
			PrevOrder(root->_left);
			PrevOrder(root->_right);
		}
	}

	void InOrder(BinaryTreeNode* root)
	{
		if (root)
		{
			InOrder(root->_left);
			cout<<root->_data<<" ";
			InOrder(root->_right);
		}
	}

	void PostOrder(BinaryTreeNode* root)
	{
		if (root)
		{
			PostOrder(root->_left);
			PostOrder(root->_right);

			cout<<root->_data<<" ";
		}
	}

	// 判断一个节点是否在一棵树中
	bool IsInTree(BinaryTreeNode* root, BinaryTreeNode* node)
	{
		if (root == NULL)
			return false;

		if(node == root)
			return true;

		if (IsInTree(root->_left, node) || IsInTree(root->_right, node))
			return true;

		return false;
	}

	// 求两个节点的最近公共祖先 -- O(N^2)
	//
	// 1.如果一个节点为根结点,另一个节点在一个子树中,则根节点为祖先节点。
	// 2.如果一个节点在左子树,另一个节点在右子树,则当前根节点即为祖先节点。
	// 3.如果两个均在左子树或右子树,则转化为子问题,在子树使用递归求解。
	//
	BinaryTreeNode* GetCommontAncestor(BinaryTreeNode* root,
		BinaryTreeNode* x1, BinaryTreeNode* x2)
	{
		// 1.如果一个节点为根结点,另一个节点在一个子树中,则根节点为祖先节点。
		if(root == x1 && IsInTree(root, x2))
		{
			return root;
		}
		if (root == x2 && IsInTree(root, x1))
		{
			return root;
		}

		// 2.如果一个节点在左子树,另一个节点在右子树,则当前根节点即为祖先节点。
		bool x1InLeft = false, x2InLeft = false, x1InRight = false, x2InRight = false;
		x1InLeft = IsInTree(root->_left, x1);
		x2InRight = IsInTree(root->_right, x2);
		if (x1InLeft&&x2InRight)
		{
			return root;
		}

		x1InRight = IsInTree(root->_right, x1);
		x2InLeft = IsInTree(root->_left, x2);

		if (x1InLeft && x2InRight)
		{
			return root;
		}

		// 3.如果两个均在左子树或右子树,则转化为子问题,在子树使用递归求解。
		if (x1InLeft && x2InLeft)
		{
			return GetCommontAncestor(root->_left, x1, x2);
		}
		if (x1InRight && x2InRight)
		{
			return GetCommontAncestor(root->_right, x1, x2);
		}

		return NULL;
	}

	// 优化
	bool GetNodePath(BinaryTreeNode* root, 
					 vector<BinaryTreeNode*>& s,
					 BinaryTreeNode* x)
	{
		if (root)
		{
			// 节点入数据
			s.push_back(root);

			// 找到节点则返回true
			if (root == x)
				return true;

			// 分别查找左右子树
			if(GetNodePath(root->_left, s, x))
				return true;

			if (GetNodePath(root->_right, s, x))
				return true;

			// 左右子树均没有找到,则出数据。
			s.pop_back();
		}

		return false;
	}

	// 优化 -- 时间复杂度O(N)
	BinaryTreeNode* GetCommontAncestor_OP(BinaryTreeNode* root,
										  BinaryTreeNode* x1, BinaryTreeNode* x2)
	{
		// 获取两个节点的查找路径
		vector<BinaryTreeNode*> s1;
		vector<BinaryTreeNode*> s2;
		GetNodePath(root, s1, x1);
		GetNodePath(root, s2, x2);

		// stack这里不能遍历,所以使用list/vector.
		// 找顺序表中从开始最后一个相同的数据则是最近公共祖先
		size_t i = 0;
		while (i < s1.size() && i < s2.size())
		{
			if (s1[i] == s2[i])
				++i;
			else
				break;
		}

		--i;

		if (i != 0)
			return s1[i];
		else
			return NULL;
	}

	int GetHeight(BinaryTreeNode* root)
	{
		if (root == NULL)
			return 0;
		
		int left = GetHeight(root->_left);
		int right = GetHeight(root->_right);

		return left > right ? left+1 : right+1;
	}

	// O(N^2)
	// 判断一棵二叉树是否是平衡树(AVL树的规则)
	bool IsBalance(BinaryTreeNode* root)
	{
		if (root == NULL || (root->_left == NULL && root->_right == NULL))
		{
			return true;
		}

		// 1.判断当前树是否为平衡树
		int leftH = GetHeight(root->_left);
		int rightH = GetHeight(root->_right);

		int interval = leftH - rightH;
		if (interval > 1 || interval < -1)
		{
			return false;
		}

		// 2.判断左右子树是否为平衡树
		return IsBalance(root->_left) && IsBalance(root->_right);
	}

	// 优化 -- O(N)
	bool IsBalance_OP(BinaryTreeNode* root, int& height)
	{
		// 1.判断当前树是否是平衡树
		if (root == NULL)
		{
			height = 0;
			return true;
		}

		if (root->_left == NULL && root->_right == NULL)
		{
			height = 1;
			return true;
		}

		// 2.判断左右子树是否是平衡树,并算出左右子树的高度,通过高度判断当前树是否是平衡树
		int leftH = 0;
		int rightH = 0;
		if(IsBalance_OP(root->_right, rightH) && IsBalance_OP(root->_left, leftH))
		{
			int interval = leftH - rightH;
			if (interval <= 1 && interval >= -1)
			{
				height = leftH > rightH ? leftH : rightH;
				height += 1;
				return true;
			}
			else
			{
				return false;
			}
		}

		return false;
	}


	// 9.求一棵二叉树中最远节点的距离 O(N^2)
	void FindMaxLen(BinaryTreeNode* root, int& maxLen)
	{
		if (root == NULL)
		{
			maxLen = 0;
			return;
		}

		int l = GetHeight(root->_left); 
		int r = GetHeight(root->_right);

		if (maxLen < l + r)
		{
			maxLen = l + r;
		}

		FindMaxLen_OP(root->_left, maxLen);
		FindMaxLen_OP(root->_right, maxLen);
	}

	// 优化O(N)
	int FindMaxLen_OP(BinaryTreeNode* root, int& maxLen)
	{
		if (root == NULL)
		{
			maxLen = 0;
			return -1;
		}

		int l = FindMaxLen_OP(root->_left, maxLen) + 1; 
		int r = FindMaxLen_OP(root->_right, maxLen) + 1;

		if (maxLen < l + r)
		{
			maxLen = l + r;
		}

		return l > r ? l : r;
	}

	//10. 由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5)
	BinaryTreeNode* _RebulidTree(int prevOrder[], int& index, int prevSize,
								 int inOrder[], int po1, int po2)
	{
		BinaryTreeNode* root = NULL;
		if (index < prevSize && po1 <= po2)
		{
			// 前序确定根
			root = new BinaryTreeNode(prevOrder[index]);

			// 确定左右子树的区间
			if (po1 < po2)
			{
				int div = po1;
				while (inOrder[div] != prevOrder[index])
				{
					++div;
				}
				root->_left = _RebulidTree(prevOrder, ++index, prevSize, inOrder, po1, div-1);
				root->_right = _RebulidTree(prevOrder, ++index, prevSize, inOrder,div+1, po2);
			}
		}

		return root;
	}

	// 由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5)
	BinaryTreeNode* RebulidTree(int inOrder[], int inSize,
								 int prevOrder[], int prevSize)
	{
		assert(inOrder);
		assert(prevOrder);
		assert(inSize == prevSize);

		int index = 0;
		return _RebulidTree(prevOrder, index, prevSize, inOrder, 0, prevSize-1);
	}

	void TestRebulidTree()
	{
		int prevOrder[] = {1,2,3,4,5,6};
		int inOrder[] = {3,2,4,1,6,5};

		BinaryTreeNode* root = RebulidTree(inOrder, sizeof(inOrder)/sizeof(int),
			prevOrder, sizeof(prevOrder)/sizeof(int));

		PrevOrder(root);
		InOrder(root);
	}

	//11. 判断一棵树是否是完全二叉树
	bool IsCompleteTree(BinaryTreeNode* root)
	{
		queue<BinaryTreeNode*> q;
		if (root)
			q.push(root);

		bool isLast = false;

		while (!q.empty())
		{
			BinaryTreeNode* front = q.front();
			q.pop();
			if (front->_left)
			{
				if (isLast)
					return false;

				q.push(front->_left);
			}
			else
			{
				isLast = true;
			}

			if (front->_right)
			{
				if (isLast)
					return false;

				q.push(front->_right);
			}
			else
			{
				isLast = true;
			}
		}

		return true;
	}

	void TestIsCompleteTree()
	{
		BinaryTreeNode* root = 0;

		//	    1
		//    /   \
		//	 2	   5	
		//  / \	  /
		// 3   4  6
		//

		// 123##4##56
		vector<DataType> t;
		t.push_back(1);
		t.push_back(2);
		t.push_back(3);
		t.push_back('#');
		t.push_back('#');
		t.push_back(4);
		t.push_back('#');
		t.push_back('#');
		t.push_back(5);
		t.push_back(6);

		int index = 0;
		CreateBinaryTree(root, t, index);

		cout<<"IsCompleteTree?"<<IsCompleteTree(root)<<endl;

	}

	//12. 求二叉树的镜像【y】
	void ToTreeMirror(BinaryTreeNode* root)
	{
		if (root == NULL)
		{
			return;
		}

		swap(root->_left, root->_right);
		ToTreeMirror(root->_left);
		ToTreeMirror(root->_right);
	}

	void TestToTreeMirror()
	{
		BinaryTreeNode* root = 0;

		//	    1
		//    /   \
		//	 2	   5	
		//  / \	  /	\
		// 3   4  6  7
		//

		// 123##4##56##7
		vector<DataType> t;
		t.push_back(1);
		t.push_back(2);
		t.push_back(3);
		t.push_back('#');
		t.push_back('#');
		t.push_back(4);
		t.push_back('#');
		t.push_back('#');
		t.push_back(5);
		t.push_back(6);
		t.push_back('#');
		t.push_back('#');
		t.push_back(7);

		int index = 0;
		CreateBinaryTree(root, t, index);
		ToTreeMirror(root);

		PrevOrder(root);
		cout<<endl;
	}

	//13.将二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向
	// left表示双向链表的前驱指针,right代表双向链表的后继指针
	void _ToList(BinaryTreeNode* cur, BinaryTreeNode*& prev)
	{
		if (cur == NULL)
			return;
		
		_ToList(cur->_left, prev);

		cur->_left = prev;
		if (prev)
			prev->_right = cur;

		prev = cur;

		_ToList(cur->_right, prev);
	}

	BinaryTreeNode* ToList(BinaryTreeNode* root)
	{
		// 先找到最左节点作为链表的头
		BinaryTreeNode* head = root;
		while (head && head->_left)
		{
			head = head->_left;
		}

		BinaryTreeNode* prev = NULL;
		_ToList(root, prev);

		return head;
	}

	void TestToList()
	{
		// 531##4##76
		vector<DataType> t;
		t.push_back(5);
		t.push_back(3);
		t.push_back(1);
		t.push_back('#');
		t.push_back('#');
		t.push_back(4);
		t.push_back('#');
		t.push_back('#');
		t.push_back(7);
		t.push_back(6);

		int index = 0;
		BinaryTreeNode* root = 0;
		CreateBinaryTree(root, t, index);

		BinaryTreeNode* head = ToList(root);


		BinaryTreeNode* tail = NULL;
		while (head)
		{
			cout<<head->_data<<" ";
			tail = head;
			head = head->_right;
		}
		cout<<endl;

		while (tail)
		{
			cout<<tail->_data<<" ";
			tail = tail->_left;
		}
		cout<<endl;
	}

	// 测试二叉树编程题
	void TestBinaryTreeTopic()
	{
		cout<<endl;
		cout<<"TestBinaryTreeTopic:"<<endl;
		BinaryTreeNode* root = 0;

		//	    1
		//    /   \
		//	 2	   5	
		//  / \	  /	
		// 3   4  6
		//

		// 123##4##56
		vector<DataType> t;
		t.push_back(1);
		t.push_back(2);
		t.push_back(3);
		t.push_back('#');
		t.push_back('#');
		t.push_back(4);
		t.push_back('#');
		t.push_back('#');
		t.push_back(5);
		t.push_back(6);

		for (size_t i = 0; i < t.size(); ++i)
		{
			cout<<t[i]<<" ";
		}
		cout<<endl;

		int index = 0;
		CreateBinaryTree(root, t, index);

		cout<<"prev:";
		PrevOrder(root);
		cout<<endl;

		cout<<"In:";
		InOrder(root);
		cout<<endl;

		cout<<"Post:";
		PostOrder(root);
		cout<<endl;


		// 求两个节点的最近公共祖先
		BinaryTreeNode* x1 = Find(root, 4);
		BinaryTreeNode* x2 = Find(root, 5);
		BinaryTreeNode* ret = GetCommontAncestor_OP(root, x1, x2);
		if (ret)
			cout<<"3 & 6 Commont Ancestor Is:"<<ret->_data<<endl;
		else
			cout<<"Not Find Commont Ancestor"<<endl;

		int height = 0;
		cout<<"Tree Is Balance Tree ? : "<<IsBalance(root)<<endl;

		cout<<"OP Tree Is Balance Tree ? : "<<IsBalance_OP(root, height)<<endl;

		// 测试一棵树中的最远距离
		int maxLen = 0;
		FindMaxLen(root, maxLen);
		cout<<"Max Len:"<<maxLen<<endl;

		maxLen = 0;
		FindMaxLen_OP(root, maxLen);
		cout<<"OP2 Max Len:"<<maxLen<<endl;

		// 测试二叉树重建
		cout<<"TestRebulidTree:";
		TestRebulidTree();
		cout<<endl;

		// 测试搜索二叉树转换成双向链表
		cout<<"TestToList:";
		TestToList();

		// 测试求二叉树的镜像
		cout<<"TestToTreeMirror:";
		TestToTreeMirror();

		// 测试判断是否是完全二叉树
		cout<<"TestIsCompleteTree:";
		TestIsCompleteTree();
	};
};




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值