剑指offer-数据结构—树
1.重建二叉树
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
TreeNode* root = nullptr;
int size1 = pre.size();
int size2 = vin.size();
if (size1 <= 0 || size2 <= 0)
return nullptr;
root = ContructTree(pre, vin, 0, size1 - 1, 0, size2 - 1);
return root;
}
TreeNode* ContructTree(vector<int> pre, vector<int> vin, int prel, int prer, int vinl, int vinr) {
TreeNode* T = nullptr;
if (prer >= prel) {
int index = 0;
for (index = vinl; index <= vinr; index++) {
// 寻找到前序第一个节点在中序中的位置。
if (vin[index] == pre[prel]) {
break;
}
}
T = new TreeNode(pre[prel]);
int leftlen = index - vinl;
int rightlen = vinr - index;
if (leftlen > 0)
T -> left = ContructTree(pre, vin, prel + 1, prel + leftlen, vinl, vinl + leftlen - 1);
else
T -> left = nullptr;
if (rightlen > 0)
T -> right = ContructTree(pre, vin, prer - rightlen + 1, prer, vinr - rightlen + 1, vinr);
else
T -> right = nullptr;
}
return T;
}
};
2.二叉树的下一个节点
题目描述: 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路分析: 分为以下三种情况考虑:
(1)给定节点有右子节点,那么中序遍历的下一个节点就是给定节点的右子节点的最左子节点;
(2)给定节点没有右子节点,并且给定节点是该节点的父节点的左子节点,那么中序遍历的下一个节点就是给定节点的父节点;
(3)给定节点没有右子节点,并且给定节点是该节点的父节点的右子节点,从该节点开始往上寻找,直到找到一个节点m是m的父节点n的左子节点,那么中序遍历的下一个节点就是父节点n。(这里的依据是中序遍历先遍历左子树,输出根节点值,再遍历右子树,那么给定一个节点,并且知道节点没有右子节点,并且这个节点是它的父节点的右子节点,所以需要寻找的就是一个虚拟的根节点)。
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode) {
TreeLinkNode* ret = nullptr;
if (pNode == nullptr)
return ret;
if (pNode -> right != nullptr) {
// 如果节点有右子节点,那么中序的下一个节点就是右子节点的最左子节点
ret = pNode -> right;
while (ret -> left != nullptr)
ret = ret -> left;
} else if (pNode -> right == nullptr) {
// 如果没有右子节点
if (pNode -> next && pNode -> next -> left == pNode) {
// 看该节点是左子节点还是右子节点,如果是左子节点,那么
// 中序的下一个节点就是父节点
ret = pNode -> next;
} else if (pNode -> next && pNode -> next -> right == pNode) {
// 如果这个这个节点是它的父节点右子节点,并且本身没有右子节点
// 那么沿着该节点的父节点往上寻找,直到找到一个节点是它父节点的
// 左子节点,那么那个节点的父节点就是要寻找的节点
TreeLinkNode* temp = pNode -> next;
TreeLinkNode* tempfather = nullptr;
while (temp) {
tempfather = temp -> next;
if (tempfather && tempfather -> left == temp) {
ret = tempfather;
break;
}
temp = temp -> next;
}
}
}
return ret;
}
};
3.树的子结构
题目描述: 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
注意:本题中两个数是整数所以可以直接比较大小,但是如果是浮点数,由于计算机内表示的小数都有误差,所以需要自己单独写一个函数来判断两个浮点数是不是相等,判断时两个数的误差不超过10^(-7)都可以认为两个数相等。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool isTheSubTree(TreeNode* root1, TreeNode* root2) {
// 向下寻找到了树B的叶节点,说明树B是树A的子树
if (root2 == nullptr)
return true;
// 如果输A到达了叶节点但是树B还没有到达叶节点,那么树B不是树A的子树
if (root1 == nullptr)
return false;
if (root1 -> val != root2 -> val)
return false;
return isTheSubTree(root1 -> left, root2 -> left) && isTheSubTree(root1 -> right, root2 -> right);
}
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
// 判断树pRoot2(A)是否是PRoot1(B)的子结构
// 在树A中查找树B中的根节点,查找到了之后判断后面的子树是否相等
bool result = false;
if (pRoot1 && pRoot2) {
if (pRoot1 -> val == pRoot2 -> val)
result = isTheSubTree(pRoot1, pRoot2);
if (!result)
result = HasSubtree(pRoot1 -> left, pRoot2);
if (!result)
result = HasSubtree(pRoot1 -> right, pRoot2);
}
return result;
}
};
4.二叉树的镜像
题目描述:
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
思路分析:使用递归的思路很容易的就可以得出二叉树的镜像
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if (pRoot == nullptr)
return;
TreeNode* temp = nullptr;
temp = pRoot -> left;
pRoot -> left = pRoot -> right;
pRoot -> right = temp;
Mirror(pRoot -> left);
Mirror(pRoot -> right);
}
};
5.对称的二叉树
题目描述: 请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* root1, TreeNode* root2) {
if (root1 == nullptr && root2 == nullptr)
return true;
else if (root1 == nullptr && root2 != nullptr)
return false;
else if (root1 != nullptr && root2 == nullptr)
return false;
else if (root1 -> val != root2 -> val)
return false;
else return isSymmetrical(root1 -> left, root2 -> right)
&& isSymmetrical(root1 -> right, root2 -> left);
}
bool isSymmetrical(TreeNode* pRoot) {
return isSymmetrical(pRoot, pRoot);
}
};
6.层次遍历二叉树
题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印。
/*
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) {
vector<int> vec;
if (root == nullptr) return vec;
queue<TreeNode*> que;
que.push(root);
TreeNode* proot = nullptr;
while (!que.empty()) {
proot = que.front();
vec.push_back(proot -> val);
if (proot -> left != nullptr)
que.push(proot -> left);
if (proot -> right != nullptr)
que.push(proot -> right);
que.pop();
}
return vec;
}
};
7.二叉树的后序遍历序列
题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路分析: 首先画出一棵二叉搜索树,然后从遍历的序列可以得知序列的最后一个元素是根节点,然后从开始节点开始,寻找根节点左边的部分,然后根据左边的部分继续查找,如果根节点右边的部分存在比根节点的值小的节点,那么后序的序列就是错的,接着找出根节点的右子树,然后再递归分别判断左子树和右子树。
测试样例: (1)空二叉树;(2)只有左子树的搜索二叉树;(3)只有右子树的搜索二叉树;(4)一般的搜索二叉树的后序序列;(5)具有错误的序列的后序序列。
class Solution {
public:
bool isPostSequence(vector<int> vec, int start, int end) {
//if (vec.size() <= 0 || end - start <= 0)
if (vec.size() <= 0) return false;
if (start == end) return true;
if (start > end) return false;
int root = vec[end];
int index = 0;
//在二叉树中寻找值小于根节点的值
for (index = start; vec[index] < vec[end]; ++index);
bool left = true;
if (index > start)
left = isPostSequence(vec, start, index - 1);
// 看看二叉树的右子树中是否有小于根节点的值
for (int i = index + 1; i <= end; i++)
if (vec[i] < root) {
return false;
}
bool right = true;
// 判断右子树
if (end - 1 > index)
right = isPostSequence(vec, index, end - 1);
if (left && right) return true;
return false;
}
bool VerifySquenceOfBST(vector<int> sequence) {
if (sequence.size() > 0) {
if (isPostSequence(sequence, 0, sequence.size() - 1))
return true;
return false;
}
return false;
}
};