二叉树学习笔记
2016-08-25 21:41
239 查看
二叉树
struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} };
二叉树的序列化及反序列化
序列化二叉树
//================================================== // 序列化二叉树 //================================================== void serializeBTree(TreeNode* pRoot, ostream& out, char mark, char separator) { if(NULL == pRoot) { out << mark << separator; return; } out << pRoot->val << separator; serializeBTree(pRoot->left, out, mark, separator); serializeBTree(pRoot->right, out, mark, separator); } /* 序列化二叉树 * pRoot:要序列化的二叉树 * mark:叶子节点下的 NULL 指针标记符(默认为 #) * separator:分隔符(默认为空格) */ string Serialize(TreeNode *pRoot, char mark, char separator) {//【序列化二叉树】 ostringstream os; if(NULL != pRoot) { serializeBTree(pRoot, os, mark, separator); } return os.str(); }
反序列化二叉树
//================================================== // 反序列化二叉树 //================================================== // 使用流 bool readStream(istream& in, int& num, char mark, char separator) { if(' ' == separator) {// 空格分割的情况 string str; in >> str; if("#" == str) return false; num = atoi(str.c_str()); return true; } else {// 其他字符分割的情况 char ch; string s = ""; in >> ch; while(ch != separator) { s += ch; in >> ch; } if(s[0] != mark) { num = atoi(s.c_str()); return true; } return false; } } void deserializeBTree(TreeNode* &pRoot, istream& in, char mark, char separator) {// 使用流 int num; if(readStream(in, num, mark, separator)) { pRoot = new TreeNode(num); deserializeBTree(pRoot->left, in, mark, separator); deserializeBTree(pRoot->right, in, mark, separator); } } // 使用 string bool readString(string& str, int& num, char mark, char separator) { string::size_type index = str.find_first_of(separator); if(string::npos != index) { string s = str.substr(0, index); str = str.substr(index+1); if(s[0] != mark) { num = atoi(s.c_str()); return true; } } return false; } void deserializeBTree(TreeNode* &pRoot, string& str, char mark, char separator) {// 使用 string int num; if(readString(str, num, mark, separator)) { pRoot = new TreeNode(num); deserializeBTree(pRoot->left, str, mark, separator); deserializeBTree(pRoot->right, str, mark, separator); } } /* 反序列化二叉树 * str:string 型的序列 * mark:叶子节点下的 NULL 指针标记符(默认为 #) * separator:分隔符(默认为空格) */ TreeNode* Deserialize(string sequence, char mark, char separator){//【反序列化二叉树】 TreeNode* pRoot = NULL; // istringstream in(sequence); // deserializeBTree(pRoot, in, mark, separator);// 使用流 deserializeBTree(pRoot, sequence, mark, separator);// 使用 string return pRoot; }
二叉树的遍历(递归)
//================================== // 二叉树遍历(递归) //================================== void PreorderTravel(TreeNode *pRoot) {// 【先序遍历(递归)】 if(pRoot) { cout << pRoot->val << " "; PreorderTravel(pRoot->left); PreorderTravel(pRoot->right); } } void InorderTravel(TreeNode *pRoot) {// 【中序遍历(递归)】 if(pRoot) { InorderTravel(pRoot->left); cout << pRoot->val << " "; InorderTravel(pRoot->right); } } void PostorderTravel(TreeNode *pRoot) {// 【后序遍历(递归)】 if(pRoot) { PostorderTravel(pRoot->left); PostorderTravel(pRoot->right); cout << pRoot->val << " "; } }
二叉树的遍历(非递归)
//================================== // 二叉树遍历(非递归) //================================== void PreorderNonRecursive(TreeNode *pRoot) { // 【前序遍历(非递归)】 stack<TreeNode*> s; TreeNode *p = pRoot; while(p != NULL || !s.empty()) { while(p != NULL) { cout << p->val << " ";// 根 s.push(p); p = p->left;// 左 } if(!s.empty()) { p = s.top(); s.pop(); p = p->right;// 右 } } } void InorderNonRecursive(TreeNode *pRoot) { // 【中序遍历(非递归)】 stack<TreeNode*> s; TreeNode *p = pRoot; while(p != NULL || !s.empty()) { while(p != NULL) { s.push(p); p = p->left;// 左 } if(!s.empty()) { p = s.top(); cout << p->val << " ";// 根 s.pop(); p = p->right;// 右 } } } /* 后序遍历:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点 p,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它; * 或者 p 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。 * 若非上述两种情况,则将 p 的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。*/ void PostorderNonRecursive(TreeNode *pRoot) { // 【后序遍历(非递归)】 stack<TreeNode*> s; TreeNode *cur;// 当前结点 TreeNode *pre = NULL;// 前一次访问的结点 s.push(pRoot); while(!s.empty()) { cur = s.top(); if((cur->left == NULL && cur->right == NULL) || // 如果当前结点没有孩子结点 (pre != NULL && (pre == cur->left || pre == cur->right))// 如果有孩子,因为孩子们是先入栈的,只要有一个孩子访问了,肯定是孩子们都被访问了(因为他们比当前结点先入栈的) ) { cout << cur->val << " "; s.pop(); pre = cur; } else { if(cur->right != NULL)// 右孩子先入栈,这样,每次取栈顶元素的时候,左孩子在右孩子前面被访问 s.push(cur->right); if(cur->left != NULL) s.push(cur->left); } } }
按层打印二叉树
从上往下打印二叉树(层序遍历不分行)
vector<int> TravelFromTopToBottom(TreeNode *pRoot) {// 【从上往下打印二叉树】 vector<int> result; if(NULL == pRoot) return result; queue<TreeNode*> myQueue; myQueue.push(pRoot); while(!myQueue.empty()) { TreeNode *p = myQueue.front(); result.push_back(p->val); myQueue.pop(); if(p->left) myQueue.push(p->left); if(p->right) myQueue.push(p->right); } return result; }
把二叉树打印成多行(层序遍历分行)
vector<vector<int> > LevelTravel(TreeNode* pRoot) { // 【把二叉树打印成多行】 vector<vector<int> > result; if(pRoot != NULL) { queue<TreeNode*> q; q.push(pRoot); int levelWith = 0; int n = 1; vector<int> v; while(!q.empty()) { TreeNode* p = q.front(); v.push_back(p->val); if(p->left) { q.push(p->left); ++levelWith; } if(p->right) { q.push(p->right); ++levelWith; } q.pop(); --n; if(0 == n) { result.push_back(v); v.resize(0); n = levelWith; levelWith = 0; } } } return result; }
按之字形顺序打印二叉树
vector<vector<int> > ZigzagTravel(TreeNode* pRoot) {// 【按之字形顺序打印二叉树】 vector<vector<int> > result; if(NULL == pRoot) return result; stack<TreeNode*> s1/*从右到左压入*/, s2/*从左到右压入*/; s1.push(pRoot); vector<int> vec; while(!s1.empty() || !s2.empty()) { while(!s1.empty()) { TreeNode* node = s1.top(); vec.push_back(node->val); if(node->left) s2.push(node->left); if(node->right) s2.push(node->right); s1.pop(); } result.push_back(vec); vec.resize(0); while(!s2.empty()) { TreeNode* node = s2.top(); vec.push_back(node->val); if(node->right) s1.push(node->right); if(node->left) s1.push(node->left); s2.pop(); } result.push_back(vec); vec.resize(0); } return result; }
重建二叉树
根据前序和中序重建二叉树
TreeNode* constrcutBT(const vector<int>& pre, vector<int>::size_type preLow, vector<int>::size_type preHigh, const vector<int>& in, vector<int>::size_type inLow, vector<int>::size_type inHigh) { // 前序的第一个是根 int rootValue = pre[preLow]; TreeNode* tree = new TreeNode(rootValue); if(0 == preHigh-preLow && 0 == inHigh-inLow && pre[preLow] == in[inLow]) return tree; // 在中序里面找到这个根的位置 vector<int>::size_type i = inLow; for(; i != inHigh; i++) { if(rootValue == in[i]) break; } if(i > inLow) {// 重建左子树 vector<int>::size_type in_L_Low = inLow, in_L_High = i - 1;// 左子树的中序起始点 vector<int>::size_type pre_L_Low = preLow + 1, pre_L_High = preLow + (i - inLow);// 左子树的前序起始点 tree->left = constrcutBT(pre, pre_L_Low, pre_L_High, in, in_L_Low, in_L_High); } if(i < inHigh) {// 重建右子树 vector<int>::size_type in_R_Low = i + 1, in_R_High = inHigh;// 右子树的中序起始点 vector<int>::size_type pre_R_Low = preLow + (i - inLow) + 1, pre_R_High = preHigh;// 右子树的前序起始点 tree->right = constrcutBT(pre, pre_R_Low, pre_R_High, in, in_R_Low, in_R_High); } return tree; } struct TreeNode* ReConstructBinaryTree(vector<int> pre, vector<int> in) {// 【根据前序和中序重建二叉树】 if(pre.empty() || in.empty() || pre.size() != in.size()) return NULL; return constrcutBT(pre, 0, pre.size()-1, in, 0, in.size()-1); }
判断二叉树是否是对称二叉树
bool isSymm(TreeNode* pRoot1, TreeNode* pRoot2) { if(NULL == pRoot1 && NULL == pRoot2) return true; if(NULL == pRoot1 || NULL == pRoot2) return false; if(pRoot1->val != pRoot2->val) return false; return (isSymm(pRoot1->left, pRoot2->right) && isSymm(pRoot1->right, pRoot2->left)); } bool IsSymmetrical(TreeNode* pRoot) {// 【对称二叉树】 return isSymm(pRoot, pRoot); }
二叉树的镜像(对换左右子树)
void Mirror(TreeNode *pRoot) {// 【二叉树的镜像(对换左右子树)】 if(pRoot != NULL) { TreeNode *p = pRoot->left; pRoot->left = pRoot->right; pRoot->right = p; Mirror(pRoot->left); Mirror(pRoot->right); } }
判断树的子结构
bool hasST(TreeNode *pRoot1, TreeNode *pRoot2) {// 判断树1中以此节点为根节点的子树是不是包含数2一样的结构 if(NULL == pRoot2) return true;// 递归终止条件 if(NULL == pRoot1) return false; if(pRoot1->val != pRoot2->val) return false; return (hasST(pRoot1->left, pRoot2->left) && hasST(pRoot1->right, pRoot2->right)); } bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {// 【判断树 pRoot2 是不是树 pRoot1 的子结构】 bool flag = false; if(pRoot1 != NULL && pRoot2 != NULL) { if(pRoot1->val == pRoot2->val)// 在树1中找到和树2的根节点的值一样的节点 flag = hasST(pRoot1, pRoot2);// 判断树1中以此节点为根节点的子树是不是包含数2一样的结构 if(!flag) flag = HasSubtree(pRoot1->left, pRoot2);// 在左子树中查找 if(!flag) flag = HasSubtree(pRoot1->right, pRoot2);// 在右子树中查找 } return flag; }
判断二叉树是否是平衡二叉树
bool isBalanced(TreeNode* pRoot, int& depth) { if(!pRoot) { depth = 0; return true; } int leftDepth, rightDepth; // 如果左右子树是平衡的,则计算当前节点作为根节点的树是否是平衡的 if(isBalanced(pRoot->left, leftDepth) && isBalanced(pRoot->right, rightDepth)) { int d = abs(leftDepth - rightDepth); if(d <= 1) { depth = leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1; return true; } } return false; } bool IsBalanced(TreeNode* pRoot) {// 【判断二叉树是否是平衡二叉树】 // // 方案一 // if(!pRoot) // return true; // int leftDepth = TreeDepth(pRoot->left);// 计算左子树深度 // int rightDepth = TreeDepth(pRoot->right);// 计算右子树深度 // int d = abs(leftDepth - rightDepth);// 左右子树深度差 // if(d > 1)// 如果深度差超过 1 则不是平衡二叉树 // return false; // return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right); // 方案二(方案一中一个结点会被重复遍历多次,效率不高。这里方案二采用后序遍历的方式,每个节点只访问一次) int depth; return isBalanced(pRoot, depth); }
二叉树的深度
//void getTreeDepth(TreeNode* p, int& depth, int& maxDepth) { // if(p) { // depth++; // if(!p->left && !p->right) {// 如果到了叶子节点,则更新深度值 // if(depth > maxDepth) // maxDepth = depth; // } // else { // if(p->left) { // getTreeDepth(p->left, depth, maxDepth); // depth--; // } // if(p->right) // getTreeDepth(p->right, depth, maxDepth); // } // } //} //int TreeDepth(TreeNode* pRoot) {//【二叉树的深度】方案一 // int depth = 0, maxDepth = 0; // getTreeDepth(pRoot, depth, maxDepth); // return maxDepth; //} int TreeDepth(TreeNode* pRoot) {//【二叉树的深度】方案二 if(!pRoot) return 0; int leftDepth = TreeDepth(pRoot->left);// 计算左子树深度 int rightDepth = TreeDepth(pRoot->right);// 计算右子树深度 return (leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1);// 树的深度为较大者深度 + 1 }
二叉树中和为某一值的路径
void findPath(TreeNode* root, int& curSum, const int& expectNumber, vector<int>& path, vector<vector<int> >& paths) { if(root) { curSum += root->val; path.push_back(root->val); if(NULL == root->left && NULL == root->right && curSum == expectNumber) paths.push_back(path); if(root->left) findPath(root->left, curSum, expectNumber, path, paths); if(root->right) findPath(root->right, curSum, expectNumber, path, paths); curSum -= root->val; path.pop_back(); } } vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {// 【二叉树中和为某一值的路径】 vector<vector<int> > paths; if(NULL == root) return paths; int curSum = 0; vector<int> path; findPath(root, curSum, expectNumber, path, paths); return paths; }
二叉搜索树
判断一个序列是不是二叉搜索树的后序遍历序列
bool VerifySquenceOfBST(vector<int> sequence) {// 【判断一个序列是不是二叉搜索树的后序遍历序列】 if(sequence.empty()) return false; int rootValue = sequence[sequence.size()-1];// 根节点 vector<int>::size_type length = 0, i = 0; for(; i < sequence.size()-1; i++)// 寻找根节点左右子树分割点 if(sequence[i] > rootValue) break; length = i;// 左子树节点数 for(++i; i < sequence.size()-1; i++)// 判断右子树节点中,是否有小于根节点值的 if(sequence[i] < rootValue) return false; bool L_flag = true, R_flag = true; if(length > 0) {// 递归判断左子树 vector<int> vecL(sequence.begin(), sequence.begin()+length); L_flag = VerifySquenceOfBST(vecL); } if(length < sequence.size()-1) {// 递归判断右子树 vector<int> vecR(sequence.begin()+length, sequence.end()-1); R_flag = VerifySquenceOfBST(vecR); } return (L_flag && R_flag); }
二叉搜索树转为双向链表
void convertTree2List(TreeNode* p, TreeNode* &pList) { if(p) { if(p->left) convertTree2List(p->left, pList);// 转换左子树 p->left = pList;// 将此根节点左边指向双向链表的最右边 if(pList) pList->right = p;// 双向链表的最右边的节点指向此根节点 pList = p;// 更新 pList 指向双向链表的最右边 if(p->right) convertTree2List(p->right, pList);// 转换右子树 } } TreeNode* Convert(TreeNode* pRootOfTree) {// 【二叉搜索树转为双向链表】 if(pRootOfTree) return NULL; TreeNode *pList/*指向双向链表最右边那个节点*/ = NULL, *pListHead/*双向链表*/ = NULL; convertTree2List(pRootOfTree, pList); pListHead = pList; while(pListHead && pListHead->left)// 因为 pList 指向的是双向链表的最右边,所以反向遍历到最左边得到表头 pListHead = pListHead->left; return pListHead; }
二叉搜索树的第 k 个结点
给定一颗二叉搜索树,请找出其中的第k小的结点。例如, 5 3 2 # # 4 # # 7 6 # # 8 # #,按结点数值大小顺序第三个结点的值为 4bool FindKthOfBST(TreeNode* pRoot, int& k, int& val) {//【查找二叉搜索树的第 k 小的结点,若找到返回 true,并用 val 存放这个结点的值】 // 用中序遍历即可从小到大访问二叉搜索树的结点 bool isFind = false; if(pRoot != NULL) { // 左 isFind = FindKthOfBST(pRoot->left, k, val); // 根 k--; if(0 == k) { val = pRoot->val; isFind = true; } // 右 if(!isFind) isFind = FindKthOfBST(pRoot->right, k, val); } return isFind; }
未完待续。。。。。。
相关文章推荐
- 学习笔记——二叉树两结点的最低共同父结点
- 数据结构学习笔记 --- 二叉树
- 学习笔记:树和二叉树的初步学习1
- 【算法学习笔记】08.数据结构基础 二叉树初步练习1
- 【算法学习笔记】08.数据结构基础 二叉树初步练习1
- 数据结构学习笔记:二叉树
- 严蔚敏数据结构学习笔记六.树和二叉树
- 二叉树学习笔记。
- 【算法学习笔记】10.数据结构基础 二叉树初步练习3(遍历与递归复习)
- 数据结构学习笔记之二叉树
- 二叉树学习笔记
- 数据结构学习笔记五:树和二叉树
- 学习笔记——已知二叉树的先序中序求后序、中序后序求先序的遍历序列
- 数据结构与算法分析学习笔记--第四章(搜索二叉树,递归和非递归实现删除、插入)
- 数据结构与算法分析学习笔记--第四章(二叉树:创建、递归遍历、非递归遍历、根据数据删除结点等)
- 【学习笔记】关于二叉树
- [学习笔记]树的相关知识&&二叉树(一)
- 学习笔记---二叉树排序,面试经常考的题目
- 【算法学习笔记】09.数据结构基础 二叉树初步练习2
- 学习笔记:树和二叉树的初步学习2