二叉树的面试题

20 篇文章 0 订阅
2 篇文章 0 订阅

二叉树的面试题


1.递归创建二叉树;
2.由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5);
3.前、中、后三种遍历的递归;
4.层次遍历-队列应用;
5.前、中、后三种遍历的非递归-用桟实现非递归;
6.求结点的个数;
7.求二叉树的高度;
8.求叶子结点的个数;
9.查找一个数据;
10.求第k层结点的个数;
11.求二叉树的镜像;
12.判断二叉树是不是完全二叉树;

<span style="font-size:18px;">#pragma once

#include<iostream>
using namespace std;
#include<assert.h>
#include<queue>
#include<stack>

template <class T>
struct BinaryTreeNode
{
	BinaryTreeNode<T>* _left;
	BinaryTreeNode<T>* _right;
	T _data;

	BinaryTreeNode(T data)
		:_left(NULL)
		, _right(NULL)
		, _data(data)
	{}
};

template <class T>
class BinaryTree
{
	typedef BinaryTreeNode<T> Node;
public:
	BinaryTree()
		:_root(NULL)
	{}

	/递归创建二叉树//
	BinaryTree(const T* arr, int len, const T& invalid)
	{
		assert(arr);
		int index = 0;
		_CreateBinaryTree(_root, arr, len, index, invalid);
	}

	//由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5)
	BinaryTree(T* Prev,T* InOrder,int len)
	{
		assert(Prev);
		assert(InOrder);
		_ReBuildCreateBinaryTree(_root,Prev,InOrder,len);
	}
	
	//前、中、后三种遍历的递归
	void PreOrder()
	{
		_PreOrder(_root);
		cout << endl;
	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	void PostOrder()
	{
		_PostOrder(_root);
		cout << endl;
	}

	/层次遍历-队列应用/
	void LevelTraverse()
	{
		queue<Node*> q;
		if (_root)
			q.push(_root);
		while (!q.empty())
		{
			Node* front = q.front();
			cout << front->_data << " ";
			q.pop();
			if (front->_left)
				q.push(front->_left);
			if (front->_right)
				q.push(front->_right);
		}
		cout << endl;
	}

	//前、中、后三种遍历的非递归-用桟实现非递归
	//前序非递归:访问当前结点,利用栈的特性后进先出,将右结点先
	//入桟,再将左结点入桟,这样先访问左,再访问右

	void PreOrder_Non()
	{
		stack<Node*> s;
		if (_root)
			s.push(_root);
		while (!s.empty())
		{
			Node* top = s.top();
			cout << top->_data << " ";
			s.pop();
			if (top->_right)
				s.push(top->_right);
			if (top->_left)
				s.push(top->_left);
		}
		cout << endl;
	}

	//中序遍历:先将左子树入桟,再访问,再将右子树入桟/
	void InOrder_Non()
	{
		stack<Node*> s;
		Node* cur = _root;
		while (cur || !s.empty())
		{
			while (cur)
			{
				s.push(cur);
				cur = cur->_left;
			}
			cur = s.top();
			s.pop();
			cout << cur->_data << " ";
			cur = cur->_right;
		}
		cout << endl;
	}

	//后续遍历,prev法/
	void PostOrder_Non()
	{
		stack<Node*> s;
		Node* cur = _root;
		Node* prev = NULL;
		while (cur || !s.empty())
		{
			//左子树入桟
			while (cur)
			{
				s.push(cur);
				cur = cur->_left;
			}
			cur = s.top();
			//prev指向前一个被访问过的结点,右子树入桟
			if (cur->_right && prev != cur->_right)
			{
				cur = cur->_right;
			}
			//当右子树为空且该结点没有被访问过,则去访问该结点
			else
			{
				cout << cur->_data << " ";
				prev = cur;
				s.pop();
				cur = NULL;
			}
		}
		cout << endl;
	}

	///后续遍历,双桟法
	void PostOrder_Non_Two_Stack()
	{
		if (_root == NULL)
			return;

		stack<Node*> s1, s2;
		s1.push(_root);

		while (!s1.empty())
		{
			Node* top = s1.top();
			s1.pop();
			s2.push(top);
			if (top->_left)
				s1.push(top->_left);
			if (top->_right)
				s1.push(top->_right);
		}

		while (!s2.empty())
		{
			Node* top = s2.top();
			cout << top->_data << " ";
			s2.pop();
		}
		cout << endl;
	}

	求结点的个数/
	//递归
	size_t Size()
	{
		size_t _size = _Size(_root);
		return _size;
	}

	//加在一个静态变量上引入多线程安全问题///
	size_t Size1()
	{
		size_t _size1 = _Size1(_root);
		return _size1;
	}

	///引用解决了多线程安全问题/
	size_t Size2()
	{
		int index = 0;
		size_t _size2 = _Size2(_root, index);
		return _size2;
	}
	
	///求二叉树的高度/
	size_t Height()
	{
		size_t height = _Height(_root);
		return height;
	}

	///求叶子结点的个数//
	size_t LeafNum()
	{
		size_t leaf = _LeafNum(_root);
		return leaf;
	}

	///查找一个数据///
	bool Find(const T& x)
	{
		return _Find(_root, x);
		
	}

	求第k层结点的个数
	size_t KLayerOfNodeNum(int k)
	{
		size_t num = 0;
		num = _KLayerOfNodeNum(_root,k);
		return num;
	}

	///求二叉树的镜像
	void GetMirror()
	{
		_root = _GetMirror(_root);
	}

#include<queue>

	//判断二叉树是不是完全二叉树
	///方法一:广度优先遍历二叉树

	bool IsCompleteBinaryTree()
	{
		if (_root == NULL)
			return true;

		//bool isCompleteTree = false;
		bool HasLeftNoRight = false;
		queue<Node*> q;
		q.push(_root);
		while (!q.empty())
		{
			Node* front = q.front();
			q.pop();

			//第二次遇到只有左子树的结点
			if (front->_left && front->_right == NULL && HasLeftNoRight)
			{
				return false;
			}

			if (front->_left && front->_right)
			{
				//在遇到只有左子树的情况之后,必定不能往进去压结点
				if (HasLeftNoRight)
				{
					return false;
				}
				q.push(front->_left);
				q.push(front->_right);
			}
			else if (front->_left && front->_right == NULL && !HasLeftNoRight)
			{
				q.push(front->_left);

				//HasLeftNoRight为true时表示已经遇到只有左子树的情况
				HasLeftNoRight = true;
			}
			else if (front->_left == NULL && front->_right)
			{
				return false;
			}
			else
			{
				//isCompleteTree = true;
			}
		}
		 //return isCompleteTree;
		return true;
	}

	方法二:按照完全二叉树的定义,左树的深度大于等于右树的深度/
	///一棵树一棵树的递归,前序遍历的过程//
	bool IsCompleteBinaryTree2()
	{
		return _IsCompleteBinaryTree2(_root);
	}

protected:
	void _CreateBinaryTree(Node*& root, const T* arr, int len, int& index, const T& invalid)
	{
		if (root == NULL && index < len && arr[index] != invalid)
		{
			root = new Node(arr[index]);
			_CreateBinaryTree(root->_left, arr, len, ++index, invalid);
			_CreateBinaryTree(root->_right, arr, len, ++index, invalid);
		}
	}

	void _ReBuildCreateBinaryTree(Node*& root, T* Prev, T* InOrder, \
		int len)
	{
		if (Prev == NULL && InOrder == NULL && len <= 0)
			return;

		return _ReBuildTree(root, Prev, Prev + len - 1, InOrder, InOrder + len - 1);
	}

	void _ReBuildTree(Node*& root,T* StartPre,T* EndPre, \
		T* StartIn, T* EndIn)
	{
		//1.前序确定根结点
		int rootValue = StartPre[0];
		root = new Node(rootValue);

		//2.(1).只有一个结点
		if (StartPre == EndPre)
		{
			if (StartIn == EndIn && *StartPre == *StartIn)
			{
				return;
			}
			else
			{
				cout << "Prev and InOrder is not Catching!" << endl;
				return;
			}
		}

		//2.(2).有多个结点,通过在中序中找到根结点
		T* rootIn = StartIn;
		while (rootIn < EndIn && *rootIn != root->_data)
		{
			++rootIn;
		}

		if (rootIn == EndIn && *rootIn != root->_data)
		{
			cout << "Prev and InOrder is not Catching!" << endl;
			return;
		}

		//3.上面找到根结点,同时通过此中序中的根结点计算出左子树结点的个数
		int NumOfLeft = rootIn - StartIn;

		//4.通过根的左子树的个数在前序中计算左子树最后一个数据的位置
		T* LastPlaceOfLeft = StartPre + NumOfLeft;

		//5.递归构建左子树
		if (NumOfLeft > 0)
		{
			_ReBuildTree(root->_left, StartPre + 1, LastPlaceOfLeft, StartIn, rootIn - 1);
		}

		//6.递归构建右子树
		if (NumOfLeft < EndPre - StartPre)
		{
			_ReBuildTree(root->_right, LastPlaceOfLeft + 1, EndPre, rootIn + 1, EndIn);
		}
	}

	void _PreOrder(Node* root)
	{
		if (root == NULL)
			return;
		cout << root->_data << " ";
		_PreOrder(root->_left);
		_PreOrder(root->_right);
	}

	void _InOrder(Node* root)
	{
		if (root == NULL)
			return;
		_InOrder(root->_left);
		cout << root->_data << " ";
		_InOrder(root->_right);
	}

	void _PostOrder(Node* root)
	{
		if (root == NULL)
			return;
		_PostOrder(root->_left);
		_PostOrder(root->_right);
		cout << root->_data << " ";
	}

	size_t _Size(Node* root)
	{
		if (root == NULL)
			return 0;
		return _Size(root->_left) + _Size(root->_right) + 1;
	}

	size_t _Size1(Node* root)
	{
		if (root == NULL)
			return 0;
		static int count = 0;
		++count;
		_Size1(root->_left);
		_Size1(root->_right);
		return count;
	}

	size_t _Size2(Node* root,int& count)
	{
		if (root == NULL)
			return 0;

		++count;
		_Size2(root->_left, count);
		_Size2(root->_right, count);
		return count;
	}
	
	size_t _Height(Node* root)
	{
		if (root == NULL)
			return 0;
		size_t left = _Height(root->_left);
		size_t right = _Height(root->_right);
		return left + 1 > right + 1 ? left + 1 : right + 1;
	}

	size_t _LeafNum(Node* root)
	{
		if (root == NULL)
			return 0;
		if (root->_left == NULL && root->_right == NULL)
			return 1;
		size_t leftOfLeaf = _LeafNum(root->_left);
		size_t rightOfLeaf = _LeafNum(root->_right);
		return leftOfLeaf + rightOfLeaf;
	}

	bool _Find(Node*& root, const T& x)
	{
		if (root && root->_data == x)
			return true;

		if (root->_left)
			return _Find(root->_left, x);

		if (root->_right)
			return _Find(root->_right, x);

		return false;
	}

	size_t _KLayerOfNodeNum(Node* root,const int& k)
	{
		if (root == NULL || k < 1)
			return 0;

		if (k == 1)
			return 1;

		//k层结点=左子树的k - 1层的结点 + 右子树的k - 1层的结点
		size_t KOfLeft = _KLayerOfNodeNum(root->_left, k - 1);
		size_t ROfRight = _KLayerOfNodeNum(root->_right, k - 1);
		return KOfLeft + ROfRight;
	}
	
	Node* _GetMirror(Node* root)
	{
		if (root == NULL)
			return NULL;

		//求左子树与右子树的镜像
		Node* leftMirror = _GetMirror(root->_left);
		Node* rightMirror = _GetMirror(root->_right);

		//交换左右子树 
		root->_left = rightMirror;
		root->_right = leftMirror;
		return root;
	}

	bool _IsCompleteBinaryTree2(Node* root)
	{
		if (root == NULL)
			return true;

		int left = _Height(root->_left);
		int right = _Height(root->_right);
		if (left - right < 0 || left - right > 1)
		{
			return false;
		}

		return _IsCompleteBinaryTree2(root->_left) && _IsCompleteBinaryTree2(root->_right);
	}

private:
	Node* _root;
};

void TestBinaryTree()
{
	//int a[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
	//int a[15] = { 1, 2, '#', 3, '#', '#', 4, 5, '#', 6, '#', 7, '#', '#', 8 };
	//int a[] = { 1, 2, '#', 3, '#', '#', 4, 5, 6, '#', 7, 8 };
	int a[] = { 0, 1, 3, 7,'#', '#', 8, '#', '#', 4, 9, '#', '#','#', 2, 5, '#', '#', 6 };
	//int a[] = { 1, 2, '#', 4, '#', '#', 3};
	BinaryTree<int> bt(a, sizeof(a) / sizeof(a[0]),'#');
	//前、中、后三种遍历的递归测试及层次遍历测试
	bt.PreOrder();
	bt.InOrder();                            
	bt.PostOrder();
	bt.LevelTraverse();

	//前、中、后三种遍历的非递归测试
	bt.PreOrder_Non();
	bt.InOrder_Non();
	bt.PostOrder_Non();
	bt.PostOrder_Non_Two_Stack();

	//总结点个数、高度、叶子结点个数、k层结点个数、查找函数及二叉树镜像问题
	cout <<"Size():"<< bt.Size() << endl;
	cout <<"Size1():"<< bt.Size1() << endl;
	cout <<"Size2():"<< bt.Size2() << endl;
	cout <<"Height:"<< bt.Height() << endl;
	cout <<"LeafNum():"<< bt.LeafNum() << endl;
	cout <<"KLayerOfNodeNum(3):"<< bt.KLayerOfNodeNum(3) << endl;
	//bt.GetMirror();
	cout << "IsCompleteBinaryTree()?" << bt.IsCompleteBinaryTree() << endl;
	cout << "IsCompleteBinaryTree2()?" << bt.IsCompleteBinaryTree2() << endl;
}

void TestPrevAndInReBuildBinaryTree()
{
	int PrevOrder[] = { 0, 1, 3, 7, 8, 4, 9, 2, 5, 6 };
	int InOrder[] = { 7, 3, 8, 1, 9, 4, 0, 5, 2, 6 };

	BinaryTree<int> bt(PrevOrder, InOrder, sizeof(PrevOrder) / sizeof(PrevOrder[0]));
}</span>


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值