您的位置:首页 > 职场人生

二叉树相关面试题

2016-09-05 12:55 260 查看
<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();
};
};



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: