二叉树相关面试题目总结

来源:互联网 发布:五级网络啥时候上市 编辑:程序博客网 时间:2024/06/01 15:56
前言:
一、为什么要树结构?
不像数组、链表是线性的数据结构,树是一种分层的非线性数据结构
(1)使用树的一个原因是:我们需要存储有分层关系的信息(比如说文件系统)
(2)另外一个是(BST):当把树建成有一定的形式的树可以方便数据的查找(对于平衡的树,查找时间复杂度为O(logn))。
(3)同理对于这样一个树(AVL/红黑树):他们的插入和删除的时间复杂度是(O(logn))
(4)相对于数组来说,树使用指针操作,可以动态的扩展节点。
二、二叉树的BFS和DFS
1、一个树典型的以两种方式进行遍历:
  • 广度优先遍历(或者层序遍历)
  • 深度优先遍历
  1. 中序遍历
  2. 前序遍历
  3. 后序遍历
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-1int 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;//这里elsereturn 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.1vector<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题目的博客

0 0
原创粉丝点击