前言:
一、为什么要树结构? 不像数组、链表是线性的数据结构,树是一种分层的非线性数据结构 (1)使用树的一个原因是:我们需要存储有分层关系的信息(比如说文件系统) (2)另外一个是(BST):当把树建成有一定的形式的树可以方便数据的查找(对于平衡的树,查找时间复杂度为O(logn))。 (3)同理对于这样一个树(AVL/红黑树):他们的插入和删除的时间复杂度是(O(logn)) (4)相对于数组来说,树使用指针操作,可以动态的扩展节点。
二、二叉树的BFS和DFS
1、一个树典型的以两种方式进行遍历:
- 广度优先遍历(或者层序遍历)
- 深度优先遍历
- 中序遍历
- 前序遍历
- 后序遍历
2、四种遍历方式的比较 (1)时间复杂度上,上面四种遍历方式都需要O(n)的时间,因为他们都遍历了每一个node (2)空间复杂度上,
- 对于BFS来说空间复杂度为O(w)其中w是二叉树的最大宽度,在层序遍历的时候,使用队列依次存储不同层次的nodes
- 对于DFS来说空间复杂度是O(h)其中h是二叉树的最大高度,在深度遍历的时候,使用stack来存储他们的祖先nodes
3、如何选择一种遍历方式? 平衡二叉树的高度为O(logn),最坏的情况下出现倾斜树的时候成为O(n)
- 额外的空间是一个选择的标准
- DFS一般使用的是递归的方法,递归方法的函数调用的开销也是一个因素
- 最重要的是:BFS总是从根节点开始,而DFS更倾向于从叶子节点开始,所以如果我们的问题是寻找查找离根节点很近的话我们要用BFS,反之使用DFS。
三、二叉树的一些特性 (1)第i层上的节点个数是2^(i-1),也就是i层上的节点个数是i-1层上的2倍 (2)第i层之前的所有节点个数是2^i-1;(1+2+4+7+2^(i-1)) (3)如果二叉树也有N个节点,最小可能的高度或者最小的层数是(log2(N+1)) (4)一个二叉树有L个叶子节点那么至少有log2L+1层
(5)二叉树中度为0的节点要比度为2的节点多一个 完全二叉树:
满二叉树(节点只有度为0和度为2,
这里和我之前理解不同!!)
完美二叉树
四、一些习题和代码
注解 1、求二叉树中的节点个数(222) 2、求二叉树的深度(104) 求二叉树的最小深度(111)
3、前中后序遍历(94/144/145)
4、分层遍历二叉树(102/107)
之字形遍历(103)
5、将二叉查找树变为有序的双向链表(114)
6、求二叉树第k层节点个数
7、求二叉树中叶子节点的个数
8、判断两个二叉树的结构是否相同(100)
9、判断二叉树是否为平衡二叉树(110)
10、求二叉树的镜像(226)
判断二叉树是否对称(101)
<span style="line-height: 1.5; font-family: 'Courier New'; background-color: inherit;">11、求二叉树两个节点的最低公共祖先节点(236)</span>
12、求二叉树中节点的最大距离
13、由前序遍历和中序遍历重建二叉树(105)
由中序和后序遍历重建二叉树(106)
14、判断二叉树是否为完全二叉树() 15、将一个有序数组转化为二叉查找树(108)
#include <iostream>
#include <queue>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int n) :val(n), left(nullptr), right(nullptr){}
};
//1、求二叉树中的节点个数
//暴力递归法用于普通的二叉树
int countNodes(TreeNode* root)
{
if (root == NULL)
return 0;
return countNodes(root->left) + countNodes(root->right) + 1;
}
//对于完全二叉树可以使用公式2^h-1
int getleft(TreeNode* root)
{
int count = 0;
while (root->left != NULL)
{
root = root->left;
count++;
}
return count;
}
int getright(TreeNode* root)
{
int count = 0;
while (root->right != NULL)
{
root = root->right;
count++;
}
return count;
}
int countNodes2(TreeNode* root)
{
if (root == NULL)
return 0;
int leftcount = getleft(root)+1;
int rightcount = getright(root)+1;
if (leftcount == rightcount)
return (2 << (leftcount-1)) - 1;//这里
else
return countNodes2(root->left) + countNodes2(root->right) + 1;
}
//2、求二叉树的深度
//2.1求二叉树的最大深度
int maxDepth(TreeNode* root)
{
if (root == NULL)
return 0;
int maxLeft = maxDepth(root->left);
int maxRight = maxDepth(root->right);
return maxLeft > maxRight ? (maxLeft + 1) : (maxRight + 1);
}
//2.2求二叉树的最小深度
int minDepth(TreeNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL&&root->right == NULL)
return 1;
int left = minDepth(root->left);
int right = minDepth(root->right);
if (root->left == NULL)
return right + 1;
if (root->right == NULL)
return left + 1;
return left > right ? (right + 1) : (left + 1);
}
int minDepth2(TreeNode* root)
{
queue<pair<TreeNode*, int> >q;
if (root == NULL)
return 0;
q.push(make_pair(root, 1));
while (!q.empty())
{
pair<TreeNode*, int> cur = q.front();
q.pop();
if (cur.first->left == NULL&&cur.first->right == NULL)//遇到第一个叶子节点的时候返回
return cur.second;
if (cur.first->left)
q.push(make_pair(cur.first->left,cur.second+1));
if (cur.first->right)
q.push(make_pair(cur.first->right, cur.second + 1));
}
}
//3、前中后序遍历
//3.1 递归遍历
vector<int> vec;
vector<int> inorderTraversal(TreeNode* root) {
if (root == NULL)
return vec;
inorderTraversal(root->left);
vec.push_back(root->val);
inorderTraversal(root->right);
return vec;
}
vector<int> preorderTraversal(TreeNode* root) {
if (root == NULL)
return vec;
vec.push_back(root->val);
preorderTraversal(root->left);
preorderTraversal(root->right);
return vec;
}
vector<int> postorderTraversal(TreeNode* root) {
if (root == NULL)
return vec;
postorderTraversal(root->left);
postorderTraversal(root->right);
vec.push_back(root->val);
return vec;
}
//3.2非递归版本
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
TreeNode* temp = root;
while (temp != NULL|| !s.empty())
{
while (temp != NULL)
{
s.push(temp);
temp = temp->left;
}
if (!s.empty())
{
temp = s.top();
s.pop();
vec.push_back(temp->val);
temp = temp->right;
}
}
return vec;
}
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
TreeNode* temp = root;
while (temp || !s.empty())
{
while (temp != NULL)
{
vec.push_back(temp->val);
s.push(temp);
temp = temp->left;
}
if (!s.empty())
{
temp = s.top();
temp = temp->right;
s.pop();
}
}
return vec;
}
vector<int> postorderTraversal(TreeNode* root) {
if (root == NULL)
return vec;
return vec;
}
//4、分层遍历二叉树
//4.1
vector<vector<int>> levelOrder(TreeNode* root) {
vector<TreeNode*> q;
vector<vector<int> >res;
if (root != NULL)
{
q.push_back(root);
int cur = 0;
int last = 1;
while (cur < q.size())
{
last = q.size();
vector<int> vec;
while (cur < last)
{
vec.push_back(q[cur]->val);
if (q[cur]->left)
q.push_back(q[cur]->left);
if (q[cur]->right)
q.push_back(q[cur]->right);
cur++;
}
res.push_back(vec);
}
}
return res;
}
//4.2之字形打印二叉树
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<TreeNode*> q;
vector<vector<int> >res;
if (root != NULL)
{
q.push_back(root);
int cur = 0;
int last = 1;
int row = 1;
while (cur < q.size())
{
last = q.size();
vector<int> vec;
while (cur < last)
{
vec.push_back(q[cur]->val);
if (q[cur]->left)
q.push_back(q[cur]->left);
if (q[cur]->right)
q.push_back(q[cur]->right);
cur++;
}
if (row % 2 == 0)
{
reverse(vec.begin(), vec.end());
}
row++;
res.push_back(vec);
}
}
return res;
}
//5、将二叉查找树变为有序的双向链表
//6、求二叉树第k层节点个数
int numOfKthLevel(TreeNode* root, int k)
{
if (root == NULL || k < 1)
return 0;
if (k == 1)
return 1;
int numleft = numOfKthLevel(root->left, k - 1);
int numright = numOfKthLevel(root->right, k - 1);
return numleft + numright;
}
//7、求二叉树中叶子节点的个数
int numOfLeaf(TreeNode* root)
{
if (root == NULL)
return 0;
bool isleaf = root->left == NULL&&root->right == NULL;
if (isleaf)
return 1;
int numleft = numOfLeaf(root->left);
int numright = numOfLeaf(root->right);
return numleft + numright;
}
//8、判断两个二叉树的结构是否相同
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == NULL&&q == NULL)
return true;
if ((p == NULL&&q != NULL) || (p != NULL&&q == NULL))
return false;
if (p->val != q->val)
return false;
else
{
bool l = isSameTree(p->left, q->left);
bool r = isSameTree(p->right, q->right);
if (l&&r)
return true;
else return false;
}
}
//9、判断二叉树是否为平衡二叉树
bool isBalanced(TreeNode* root) {
if (root == NULL)
return true;
int* depth = 0;
return isBalanced2(root, depth);
}
bool isBalanced2(TreeNode* root, int *depth)
{
if (root == NULL)
{
depth = 0;
return true;
}
int nleft, nright;
bool rl = isBalanced2(root->left, &nleft);
bool rr = isBalanced2(root->right, &nright);
if (rl&&rr)
{
int diff = nleft - nright;
if (diff >= -1 && diff <= 1)
{
*depth = nleft > nright ? (nleft + 1) : (nright + 1);
return true;
}
}
return false;
}
//10、求二叉树的镜像
TreeNode* invertTree(TreeNode* root) {
if (root == NULL)
return NULL;
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
root->left = invertTree(root->left);
root->right = invertTree(root->right);
return root;
}
//10.2判断一个树是否对称
bool isSymmetric(TreeNode* root) {
if (root == NULL)
return true;
return isSymmetric2(root->left, root->right);
}
bool isSymmetric2(TreeNode* root1, TreeNode* root2)
{
if (root1 == NULL&&root2 == NULL)
return true;
if ((root1 != NULL&&root2 == NULL) || (root1 == NULL&&root2 != NULL))
return false;
if (root1->val != root2->val)
return false;
bool l = isSymmetric2(root1->left, root2->right);
bool r = isSymmetric2(root1->right, root2->left);
return l&&r;
}
//11、求二叉树两个节点的最低公共祖先节点
//12、求二叉树中节点的最大距离
//13、由前序遍历和中序遍历重建二叉树
typedef vector<int>::iterator Iter;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0 || inorder.size() == 0||preorder.size()!=inorder.size())
return NULL;
return buildTree2(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
}
TreeNode* buildTree2(Iter pbegin, Iter pend, Iter ibegin, Iter iend)
{
if (pbegin == pend || ibegin == iend)
return NULL;
TreeNode* root = new TreeNode(*pbegin);
auto iroot = find(ibegin, iend, *pbegin);
int leftlength = iroot - ibegin;
root->left = buildTree2(pbegin+1,pbegin+leftlength+1, ibegin,iroot);
root->right = buildTree2(pbegin + leftlength + 1,pend, iroot+1,iend);
return root;
}
//由后序和中序重建二叉树
typedef vector<int>::iterator Iter;
TreeNode* buildTree2(Iter pbegin, Iter pend, Iter ibegin, Iter iend)
{
if (pbegin == pend || ibegin == iend)
return NULL;
TreeNode* root = new TreeNode(*(pend - 1));
auto iroot = find(ibegin, iend, *(pend - 1));
int leftlength = iroot - ibegin;
root->left = buildTree2(pbegin, pbegin + leftlength, ibegin, iroot);
root->right = buildTree2(pbegin + leftlength, pend - 1, iroot + 1, iend);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0 || inorder.size() == 0 || postorder.size() != inorder.size())
return NULL;
return buildTree2(postorder.begin(), postorder.end(), inorder.begin(), inorder.end());
}
//14、判断二叉树是否为完全二叉树
//15、将有序数组组成二叉查找树
TreeNode* sortedArrayToBST(vector<int>& nums) {
if (nums.empty())
return NULL;
TreeNode* root = new TreeNode(nums[nums.size() / 2]);
vector<int> pre(nums.begin(), nums.begin() + nums.size() / 2);
vector<int> last(nums.begin() + nums.size() / 2 + 1, nums.end());
root->left = sortedArrayToBST(pre);
root->right = sortedArrayToBST(last);
return root;
}
参考文章:http://blog.csdn.net/luckyxiaoqiang/article/details/7518888#topic2 以及一些leetcode题目的博客