算法基础知识——树(一)
目录:
- 重建二叉树【剑指Offer_编程题】
- 二叉树的镜像【剑指Offer_编程题】
- 从上往下打印二叉树【剑指Offer_编程题】
- 二叉搜索树的后续遍历序列【剑指Offer_编程题】
- 二叉树中和为某一值的路径【剑指Offer_编程题】
- 二叉树的深度【剑指Offer_编程题】
- 平衡二叉树【剑指Offer_编程题】
- 二叉搜索树与双向链表【剑指Offer_编程题】
- 对称的二叉树【剑指Offer_编程题】
- 二叉树的下一个结点【剑指Offer_编程题】
- 把二叉树打印成多行【剑指Offer_编程题】
- 二叉搜索树的第k个结点【剑指Offer_编程题】
- 按之字形顺序打印二叉树【剑指Offer_编程题】
- 高度最小的BST【程序员面试金典_ 编程题】
- 输出单层结点【程序员面试金典_ 编程题】
一、应用实例:
1、题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
//write code here
}【剑指Offer_编程题】
- 输入格式:前序遍历序列和中序遍历序列
- 输出格式:重建的二叉树
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin){
if(pre.size() == 0 || vin.size() == 0){
return NULL;
}
vector<int> left_pre, right_pre, left_vin, right_vin;
TreeNode *head = new TreeNode(pre[0]);
int gen = 0;
for(int i = 0; i < vin.size(); i++){
if(vin[i] == head->val){
gen = i;
break;
}
}
for(int i = 0; i < gen; i++){
left_vin.push_back(vin[i]);
left_pre.push_back(pre[i + 1]);
}
for(int i = gen + 1; i < vin.size(); i++){
right_vin.push_back(vin[i]);
right_pre.push_back(pre[i]);
}
head->left = reConstructBinaryTree(left_pre, left_vin);
head->right = reConstructBinaryTree(right_pre, right_vin);
return head;
}
};
2、题目描述:题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
void Mirror(TreeNode *pRoot) {
//write code here
}【剑指Offer_编程题】
- 输入格式:源二叉树
- 输出格式:镜像二叉树
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot == NULL){
return;
}
TreeNode *p = pRoot->right;
pRoot->right = pRoot->left;
pRoot->left = p;
Mirror(pRoot->right);
Mirror(pRoot->left);
}
};
3、题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
vector<int> PrintFromTopToBottom(TreeNode* root) {
//write code here
}【剑指Offer_编程题】
- 输入格式:二叉树根节点指针
- 输出格式:节点列表
- 样例输入:无
- 样例输出:无
示例代码:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
queue<TreeNode *> myQueue;
vector<int> result;
if(root != NULL){
myQueue.push(root);
}
while(!myQueue.empty()){
TreeNode *current = myQueue.front();
myQueue.pop();
result.push_back(current->val);
if(current->left){
myQueue.push(current->left);
}
if(current->right){
myQueue.push(current->right);
}
}
return result;
}
};
4、题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
bool VerifySquenceOfBST(vector<int> sequence) {
//write code here
}【剑指Offer_编程题】
- 输入格式:整型序列
- 输出格式:如果是则输出Yes,否则输出No
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence){
if(sequence.empty()){
return false;
}
int length = sequence.size();
if(length == 1){
return true;
}
vector<int> leftSeq, rightSeq;
int i = length - 2;
while(i >= 0 && sequence[i] > sequence[length - 1]){
rightSeq.push_back(sequence[i]);
i--;
}
while(i >= 0 && sequence[i] < sequence[length - 1]){
leftSeq.push_back(sequence[i]);
i--;
}
if(i >= 0){
return false;
}
VerifySquenceOfBST(leftSeq);
VerifySquenceOfBST(rightSeq);
return true;
}
};
5、题目描述:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
//wirte code here
}【剑指Offer_编程题】
- 输入格式:TreeNode* root,int expectNumber
- 输出格式:vector<vector<int> >
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
vector<vector<int> > resultList;
vector<int> myVector;
vector<vector<int> > FindPath(TreeNode* root,int expectNumber){
if(root == NULL){
return resultList;
}
myVector.push_back(root->val);
expectNumber -= root->val;
if(expectNumber == 0 && root->left == NULL && root->right == NULL){
resultList.push_back(myVector);
}
FindPath(root->left, expectNumber);
FindPath(root->right, expectNumber);
myVector.erase(myVector.end() - 1);
return resultList;
}
};
6、题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
int TreeDepth(TreeNode* pRoot){
//write code here
}【剑指Offer_编程题】
- 输入格式:根结点指针变量
- 输出格式:树的深度
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
int maxDepth = 0;
void CountDepth(TreeNode* pRoot, int count){
if(pRoot == NULL){
return;
}
if(pRoot->left == NULL && pRoot->right == NULL){
maxDepth = max(maxDepth, count);
}
CountDepth(pRoot->left, count + 1);
CountDepth(pRoot->right, count + 1);
}
int TreeDepth(TreeNode* pRoot){
maxDepth = 0;
if(pRoot != NULL){
CountDepth(pRoot, 1);
}
return maxDepth;
}
};
7、题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
bool IsBalanced_Solution(TreeNode* pRoot) {
//write code here
}【剑指Offer_编程题】
- 输入格式:树根结点指针变量
- 输出格式:判断结果
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
vector<int> myVector;
void JudgeBST(TreeNode* pRoot){
//中序遍历进行判断
if(pRoot != NULL){
JudgeBST(pRoot->left);
myVector.push_back(pRoot->val);
JudgeBST(pRoot->right);
}
}
int getDepth(TreeNode *p){
if(p == NULL){
return 0;
}
int left = getDepth(p->left);
if(left == -1){
return -1;
}
int right = getDepth(p->right);
if(right == -1){
return -1;
}
return abs(right - left) > 1 ? -1 : max(right, left) + 1;
}
bool IsBalanced_Solution(TreeNode* pRoot){
if(pRoot == NULL){
return true;
}
//理论上需要先判断是否是一棵二叉排序树
/*myVector.clear();
JudgeBST(pRoot);
for(int i = 1; i < myVector.size(); i++){
if(myVector[i] <= myVector[i - 1]){
return false;
}
}*/
if(getDepth(pRoot) == -1){
return false;
}
return true;
}
};
8、题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
TreeNode* Convert(TreeNode* pRootOfTree){
//write code here
}【剑指Offer_编程题】
- 输入格式:根结点指针
- 输出格式:排序后的根结点指针
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
void ConvertHelper(TreeNode *cur, TreeNode *&prev){
if(cur != NULL){
ConvertHelper(cur->left, prev);
cur->left = prev;
if(prev){
prev->right = cur;
}
prev = cur;
ConvertHelper(cur->right, prev);
}
}
TreeNode* Convert(TreeNode *pRootOfTree){
if(pRootOfTree == NULL){
return pRootOfTree;
}
TreeNode *prev = NULL;
ConvertHelper(pRootOfTree, prev);
TreeNode *res = pRootOfTree;
while(res->left){
res = res->left;
}
return res;
}
};
9、题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
bool isSymmetrical(TreeNode* pRoot){
//write code here
}【剑指Offer_编程题】
- 输入格式:根结点指针
- 输出格式:判断是否对称
- 样例输入:无
- 样例输出:无
示例代码1:
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot){
if(pRoot == NULL){
return true;
}
queue<TreeNode *> myQueue;
myQueue.push(pRoot);
bool flag = true; //第一次根结点时flag为true,之后列为false
while(!myQueue.empty()){
TreeNode *leftTree = NULL, *rightTree = NULL;
if(flag){ //初始时
TreeNode *node = myQueue.front();
myQueue.pop();
if(node->left != NULL && node->right != NULL){
if(node->left->val != node->right->val){
return false;
}else{
myQueue.push(node->left);
myQueue.push(node->right);
}
}
flag = false;
}else{
leftTree = myQueue.front();
myQueue.pop();
rightTree = myQueue.front();
myQueue.pop();
if(leftTree->left != NULL && rightTree->right != NULL){
if(leftTree->left->val == rightTree->right->val){
myQueue.push(leftTree->left);
myQueue.push(rightTree->right);
}else{
return false;
}
}else if(leftTree->left == NULL && rightTree->right != NULL
|| leftTree->left != NULL && rightTree->right == NULL){
return false;
}
if(leftTree->right != NULL && rightTree->left != NULL){
if(leftTree->right->val == rightTree->left->val){
myQueue.push(leftTree->right);
myQueue.push(rightTree->left);
}else{
return false;
}
}else if(leftTree->right == NULL && rightTree->left != NULL
|| leftTree->right != NULL && rightTree->left == NULL){
return false;
}
}
}
return true;
}
};
示例代码2:
class Solution {
public:
bool SymmetricalHelper(TreeNode *left, TreeNode *right){
if(left == NULL) return right == NULL;
if(right == NULL) return false;
if(left->val != right->val) return false;
return SymmetricalHelper(left->right, right->left)
&& SymmetricalHelper(left->left, right->right);
}
bool isSymmetrical(TreeNode *pRoot){
if(pRoot == NULL){
return true;
}
return SymmetricalHelper(pRoot->left, pRoot->right);
}
};
10、题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
TreeLinkNode* GetNext(TreeLinkNode* pNode){}
//write code here
}【剑指Offer_编程题】
- 输入格式:二叉树的其中一个结点
- 输出格式:中序遍历顺序的下一个结点
- 样例输入:无
- 样例输出:无
示例代码1:
class Solution {
public:
vector<TreeLinkNode *> nodeList;
void InOrder(TreeLinkNode *T){
if(T != NULL){
InOrder(T->left);
nodeList.push_back(T);
InOrder(T->right);
}
}
TreeLinkNode* GetNext(TreeLinkNode *pNode){
TreeLinkNode *head = NULL, *tmp = pNode;
while(tmp->next != NULL){
tmp = tmp->next;
}
head = tmp;
nodeList.clear();
InOrder(head);
for(int i = 0; i < nodeList.size() - 1; i++){
if(nodeList[i] == pNode){
return nodeList[i + 1];
}
}
return NULL;
}
};
示例代码2:
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode *pNode){
if(pNode == NULL){
return NULL;
}
//该结点的右孩子为空
if(pNode->right == NULL){
//向上找父结点,找到第一个父结点是左孩子则停止
while(pNode->next != NULL){
if(pNode->next->left == pNode){
return pNode->next;
}else{
pNode = pNode->next;
}
}
}
//该结点右孩子不为空
else{
pNode = pNode->right;
while(pNode->left){
pNode = pNode->left;
}
return pNode;
}
return NULL;
}
};
11、题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
vector<vector<int> > Print(TreeNode* pRoot) {
//write code here
}【剑指Offer_编程题】
- 输入格式:根结点指针变量
- 输出格式:二维数组,按层输出
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > resultList;
if(pRoot == NULL){
return resultList;
}
queue<TreeNode *> myQueue;
vector<int> tmpValVector;
vector<TreeNode *> tmpVector;
myQueue.push(pRoot);
while(!myQueue.empty()){
tmpVector.clear();
tmpValVector.clear();
while(!myQueue.empty()){
if(myQueue.front()->left != NULL){
tmpVector.push_back(myQueue.front()->left);
}
if(myQueue.front()->right != NULL){
tmpVector.push_back(myQueue.front()->right);
}
tmpValVector.push_back(myQueue.front()->val);
myQueue.pop();
}
resultList.push_back(tmpValVector);
for(int i = 0; i < tmpVector.size(); i++){
myQueue.push(tmpVector[i]);
}
}
return resultList;
}
};
12、题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如,(5,3,7,2,4,6,8)中,按结点数值大小顺序第三小结点的值为4。
TreeNode* KthNode(TreeNode* pRoot, int k){
//write code here
}【剑指Offer_编程题】
- 输入格式:树的根结点指针,整型k
- 输出格式:第k小的结点的指针变量
- 样例输入:无
- 样例输出:无
示例代码1:
class Solution {
public:
int index = 0;
TreeNode* KthNode(TreeNode* pRoot, int k){
if(pRoot){
TreeNode *node = KthNode(pRoot->left, k);
if(node != NULL){
return node;
}
index++;
if(index == k){
return pRoot;
}
node = KthNode(pRoot->right, k);
if(node != NULL){
return node;
}
}
return NULL;
}
};
示例代码2:
class Solution {
public:
vector<TreeNode *> resultList;
void InOrder(TreeNode* pRoot){
if(pRoot != NULL){
InOrder(pRoot->left);
resultList.push_back(pRoot);
InOrder(pRoot->right);
}
}
TreeNode* KthNode(TreeNode* pRoot, int k){
if(k <= 0 || pRoot == NULL){
return NULL;
}
resultList.clear();
InOrder(pRoot);
if(k > resultList.size()){
return NULL;
}
return resultList[k - 1];
}
};
13、题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
vector<vector<int> > Print(TreeNode* pRoot){
//write code here
}【剑指Offer_编程题】
- 输入格式:根结点指针变量
- 输出格式:二维数组,按层输出
- 样例输入:无
- 样例输出:无
示例代码:
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot){
vector<vector<int> > resultList;
if(pRoot == NULL){
return resultList;
}
int level = 1;
queue<TreeNode *> myQueue;
myQueue.push(pRoot);
while(!myQueue.empty()){
vector<int> tmpValVector;
vector<TreeNode *> tmpNodeVector;
while(!myQueue.empty()){
TreeNode *node = myQueue.front();
myQueue.pop();
tmpValVector.push_back(node->val);
if(node->left != NULL){
tmpNodeVector.push_back(node->left);
}
if(node->right != NULL){
tmpNodeVector.push_back(node->right);
}
}
if(level % 2 == 0){
reverse(tmpValVector.begin(), tmpValVector.end());
}
resultList.push_back(tmpValVector);
for(int i = 0; i < tmpNodeVector.size(); i++){
myQueue.push(tmpNodeVector[i]);//从左到右入结点
}
level++;
}
return resultList;
}
};
14、题目描述:对于一个元素各不相同且按升序排列的有序序列,请编写一个算法,创建一棵高度最小的二叉查找树。给定一个有序序列int[] vals,请返回创建的二叉查找树的高度。
int buildMinimalBST(vector<int> vals) {
// write code here
}【程序员面试金典_ 编程题】
- 输入格式:有序序列
- 输出格式:高度值
- 样例输入:无
- 样例输出:无
示例代码:
class MinimalBST {
public:
int buildMinimalBST(vector<int> vals) {
int length = vals.size();
int count = 0;
while(length > 0){
count++;
length /= 2;
}
return count;
}
};
15、题目描述:对于一棵二叉树,请设计一个算法,创建含有某一深度上所有结点的链表。给定二叉树的根结点指针TreeNode* root,以及链表上结点的深度,请返回一个链表ListNode,代表该深度上所有结点的值,请按树上从左往右的顺序链接,保证深度不超过树的高度,树上结点的值为非负整数且不超过100000。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
ListNode* getTreeLevel(TreeNode* root, int dep){
//write code here
}【程序员面试金典_ 编程题】
- 输入格式:根结点指针变量,深度值
- 输出格式:含有某一深度上所有结点的链表
- 样例输入:无
- 样例输出:无
示例代码:
class TreeLevel {
public:
ListNode* getTreeLevel(TreeNode* root, int dep){
if(root == NULL || dep <= 0){
return NULL;
}
ListNode *head = new ListNode(-1);
ListNode *p = head;
queue<TreeNode *> myQueue;
myQueue.push(root);
int curr = 1;
while(!myQueue.empty()){
vector<TreeNode *> tmpVector;
while(!myQueue.empty()){
TreeNode *node = myQueue.front();
myQueue.pop();
if(curr == dep){
p->next = new ListNode(node->val);
p = p->next;
}else{
if(node->left){
tmpVector.push_back(node->left);
}
if(node->right){
tmpVector.push_back(node->right);
}
}
}
for(int i = 0; i < tmpVector.size(); i++){
myQueue.push(tmpVector[i]);
}
curr++;
}
return head->next;
}
};