赞
踩
1、二叉树深度:O(log(n))~O(n)。
2、是否使用递归要看递归的深度,太深容易出现Stackoverflow的问题。
3、二叉树大部分情况下可能会考递归,当然也可能会出现考非递归的情况(迭代)。
1、通过O(n)的时间,把n的问题变成两个n/2的问题,复杂度是多少?
求解:
方法一、
先写T(n)的表达式:
T(n) = 2T(n/2) + O(n) = 2T(2T(n/2) + O(n/2)) + O(n) = 4T(n/2) + 2O(n) = ... = n(T(1)) + O(nlog(n)) = O(n) + O(nlog(n)) = O(nlog(n))
方法二、树形分析法:
这种复杂度的算法有:归并排序,快速排序(最好的情况下)
2、通过O(1)的时间,把n的问题变成两个n/2的问题,复杂度是多少?
方法一、
T(n) = 2T(n/2) + O(1) = ... = O(n)
方法二、树形分析法:
碰到二叉树的问题,就想想我要在整个二叉树上得到的结果,和我在左子树得到的结果和我在右子树上得到的结果有什么关系。(比如说整棵树上要求一个什么东西,我先不去求整个棵树,我先求出左子树是什么样,再求出右子树什么样,在研究整颗树要求的结果,和左子树结果与右子树结果,还有根的关系是什么)
(1)递归实现1(遍历方式):
1>递归四要素:1.递归的定义;2.递归的拆解;3.递归的出口;4.递归的调用。
这种实现方式,定义了一个全局变量,然后每次遍历都把结果装到这个全局的盒子里。它的递归函数没有返回值(返回值为void)
(2)递归实现2(分治方式)
这种方式,每次递归的时候都新建一个变量,然后左子树得到一个该变量的值,右子树也得到一个该变量的值,最后它俩拼出一个新的变量值作为结果。它的递归函数是有返回值的,也就是每次调用它都会有一个局部解(如果前序遍历的话,会是某个子树的前序遍历)。
1、前序遍历
题目链接:http://www.lintcode.com/problem/binary-tree-preorder-traversal/
2、前序遍历代码
/** * Definition of TreeNode: * class TreeNode { * public: * int val; * TreeNode *left, *right; * TreeNode(int val) { * this->val = val; * this->left = this->right = NULL; * } * } */ //递归版本(遍历方式) class Solution { public: /** * @param root: A Tree * @return: Preorder in ArrayList which contains node values. */ //递归的定义 void traverse(TreeNode *root, vector<int> *result) { //递归的出口 if(root == NULL) { return; } //递归的拆解 (*result).push_back(root->val); traverse(root->left, result); traverse(root->right, result); } vector<int> preorderTraversal(TreeNode * root) { vector<int> *result; //递归的调用 traverse(root, result); return *result; } }; //递归版本(分治方法) class Solution { public: /** * @param root: A Tree * @return: Preorder in ArrayList which contains node values. */ vector<int> preorderTraversal(TreeNode * root) { vector<int> result; //递归的出口 if(root == NULL) { return result; } //递归的拆解(分治) vector<int> left = preorderTraversal(root->left); vector<int> right = preorderTraversal(root->right); //合并 result.push_back(root->val); for(auto i : left) result.push_back(i); for(auto i : right) result.push_back(i); return result; } }; //非递归版本 class Solution { public: /** * @param root: A Tree * @return: Preorder in ArrayList which contains node values. */ vector<int> preorderTraversal(TreeNode * root) { vector<int> preorder = {}; stack<TreeNode *> Stack; if(root == NULL){ return preorder; } Stack.push(root); while(!Stack.empty()){ //将遍历结果存入preorder TreeNode* node = Stack.top(); Stack.pop(); preorder.push_back(node->val); //更新栈Stack if(node->right){ Stack.push(node->right); } if(node->left){ Stack.push(node->left); } } return preorder; } };
3、中序遍历和后序遍历递归的实现方法与前序遍历相似,只是遍历的顺序不同而已。但非递归的方法有些不同:
(1)中序遍历:中序遍历需要先一边找到最左边root=root->left,一边将root压入栈Stack中,然后再进行遍历输出和更新栈。
题目链接:https://www.lintcode.com/problem/binary-tree-inorder-traversal/description
class Solution { public: /** * @param root: A Tree * @return: Inorder in ArrayList which contains node values. */ //递归的定义 /*void Traversal(TreeNode *Node, vector<int> *inorder){ //递归的出口 if(Node == NULL){ return; } //递归的拆解 Traversal(Node->left, inorder); (*inorder).push_back(Node->val); Traversal(Node->right, inorder); }*/ vector<int> inorderTraversal(TreeNode * root) { /* //1、Traversal方法 vector<int> *inorder; //递归的调用 Traversal(root, inorder); return *inorder; */ /*//2、分治算法 vector<int> inorder = {}; if(root == NULL){ return inorder; } //递归的拆解,分治 vector<int> left = inorderTraversal(root->left); vector<int> right = inorderTraversal(root->right); //合并 for (auto i : left) inorder.push_back(i); inorder.push_back(root->val); for (auto i : right) inorder.push_back(i); return inorder;*/ //3、非递归方法 vector<int> inorder = {}; stack<TreeNode *> Stack; while (root != NULL){ Stack.push(root); root = root->left; } /** 1 / \ 2 3 / / \ 2 3 4 / \ 3 4 / \ 2 3 */ while (!Stack.empty()){ //将遍历存到结果(inorder)中 TreeNode *Node = Stack.top(); inorder.push_back(Node->val); //更新Stack if (Node->right == NULL) { Node = Stack.top(); Stack.pop(); while(!Stack.empty() && Stack.top()->right == Node){ Node = Stack.top(); Stack.pop(); } } else { Node = Node->right; while(Node != NULL){ Stack.push(Node); Node = Node->left; } } } return inorder; } };
(2)后序遍历:后序遍历代码实现时,边找最左边和最右边的节点,边更新栈和输出结果。
题目链接:http://www.jiuzhang.com/solutions/binary-tree-postorder-traversal/
代码实现:使用栈进行二叉树后序遍历,首先对左子树进行遍历压入栈中,直至左子树为空,然后访问右子树。故每个节点会被访问两次,当节点被第二次访问时,即curr->right=lastvisit时,该节点出栈。
/** * Definition of TreeNode: * class TreeNode { * public: * int val; * TreeNode *left, *right; * TreeNode(int val) { * this->val = val; * this->left = this->right = NULL; * } * } */ // //递归的定义 // void Traversal(TreeNode *root, vector<int> *postorder) // { // //递归的出口 // if(root == NULL){ // return; // } // //递归的拆解 // Traversal(root->left, postorder); // Traversal(root->right, postorder); // (*postorder).push_back(root->val); // } class Solution { public: /** * @param root: A Tree * @return: Postorder in ArrayList which contains node values. */ vector<int> postorderTraversal(TreeNode * root) { // //1、Traversal方法 // vector<int> *postorder; // //递归的调用 // Traversal(root, postorder); // return *postorder; /*//2、分治算法 vector<int> postorder; //递归的出口 if(root == NULL) { return {}; } //分治 vector<int> left = postorderTraversal(root->left); vector<int> right = postorderTraversal(root->right); //合并 for(auto i : left) postorder.push_back(i); for(auto j : right) postorder.push_back(j); postorder.push_back(root->val); return postorder;*/ /** * 1 * / \ * 2 3 * / \ \ * 3 1 4 * \ / * 1 2 */ //3、非递归方法 stack<TreeNode *> Stack; vector<int> postorder; TreeNode *current = root, *lastVisited = NULL; while(current != NULL || !Stack.empty()){ while(current != NULL){ Stack.push(current); current = current->left; } current = Stack.top(); if(current->right == NULL || current->right == lastVisited){ Stack.pop(); postorder.push_back(current->val); lastVisited = current; current = NULL; }else{ current = current->right; } } return postorder; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。