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

二叉树的面试题

2016-07-25 21:17 375 查看

二叉树的面试题

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