【说明】:
本文是左程云老师所著的《程序员面试代码指南》第一章中“构造数组的MaxTree”这一题目的C++复现。
本文只包含问题描述、C++代码的实现以及简单的思路,不包含解析说明,具体的问题解析请参考原书。
感谢左程云老师的支持。
【题目】:
定义二叉树节点如下:
class Node { public: Node(int data) { value = data; left = NULL; right = NULL; } public: int value; Node *left; Node *right; };
一个数组的 MaxTree 定义如下:
- 数组必须没有重复元素;
- MaxTree 是一棵二叉树,数组的每一个值对应一个二叉树节点;
- 包括 MaxTree 树在内且在其中一的每一棵子树上,值最大的节点都是树的头。
给定一个没有重复元素的数组 arr,写出生成这个数组的 MaxTree 的函数,要求如果数组长度为 N,则时间复杂度为 O(N),额外空间复杂度为 O(N)。
【思路】:
利用栈找到每个数左右两边第一个比它大的数,并且用hash_map保存。(估计这样说大家都不明白,大家可以看原书,或者分析代码喽)
【编译环境】:
CentOS6.7(x86_64)
gcc 4.4.7
【实现】:
实现及测试代码:
#include <sstream> using namespace std; using namespace __gnu_cxx; class Node { public: Node(int data) { value = data; left = NULL; right = NULL; } public: int value; Node *left; Node *right; }; /* *函数说明:利用hash_map分别为每一个数的左边和右边第一个最大值(序号)设定关联 *输入参数:s为存放数组序号的栈;map为待建好的映射表 *输出参数:s为存放数组序号的栈;map为整理好的映射表 *返回值: */ void popStackSetMap(stack<int> &s,hash_map<int,string> &map) { int tmp = s.top(); s.pop(); stringstream ss; string str; if(s.empty()) { map[tmp] = str; } else { ss << s.top(); ss >> str; map[tmp] = str; //序号对应序号的关系 } return ; } Node* getMaxTree(int a[],int len) { stack<int> s; hash_map<int,string> lBigMap; //为数组内的每个数据分别对应一个左端第一个最大值,没有则为空 for(int i=0; i<len; i++) { while(!s.empty() && a[s.top()] < a[i]) popStackSetMap(s,lBigMap); s.push(i); //注意,这里保存的是数组序号,而不是数组值 } while(!s.empty()) popStackSetMap(s,lBigMap); //为数组内的每个数据分别对应一个右端第一个最大值,没有则为空 hash_map<int,string> rBigMap; for(int i=len-1; i>=0; i--) { while(!s.empty() && a[s.top()] < a[i]) popStackSetMap(s,rBigMap); s.push(i); //注意,这里保存的是数组序号,而不是数组值 } while(!s.empty()) popStackSetMap(s,rBigMap); //构造Node数组 Node* nArr[len]; for(int i=0;i<len;i++) { nArr[i] = new Node(a[i]); } //构造Node的MaxTree Node *head = NULL; for(int i=0;i<len;i++) { //调试代码 //cout << "nArr[" << i << "]->value = " << nArr[i]->value << endl; //cout << "lBigMap = " << lBigMap[i] << endl; //cout << "rBigMap = " << rBigMap[i] << endl; string ls = lBigMap[i]; string rs = rBigMap[i]; if(ls.empty() && rs.empty()) { head = nArr[i]; } else if(ls.empty()) { stringstream ss(rs); int rID; ss >> rID; if(NULL == nArr[rID]->left) nArr[rID]->left = nArr[i]; else nArr[rID]->right = nArr[i]; } else if(rs.empty()) { stringstream ss(ls); int lID; ss >> lID; if(NULL == nArr[lID]->left) nArr[lID]->left = nArr[i]; else nArr[lID]->right = nArr[i]; } else { stringstream lss(ls); int lID; lss >> lID; stringstream rss(rs); int rID; rss >> rID; int pID = a[lID] < a[rID] ? lID : rID; if(NULL == nArr[pID]->left) nArr[pID]->left = nArr[i]; else nArr[pID]->right = nArr[i]; } } return head; } int main() { int a[] = {3,4,5,1,2}; Node *head = getMaxTree(a,5); Node *left = head->left; Node *right = head->right; cout << "head->value = "<< head->value << endl; cout << head->value <<"->left->value = "<< left->value << endl; cout << head->value <<"->right->value = "<< right->value << endl; if(NULL != left->left) cout << left->value << "->left->value = " << left->left->value << endl; else cout << left->value << "->left is empty!" << endl; if(NULL != left->right) cout << left->value << "->right->value = " << left->right->value << endl; else cout << left->value << "->right is empty!" << endl; if(NULL != right->left) cout << right->value << "->left->value = " << right->left->value << endl; else cout << right->value << "->left is empty!" << endl; if(NULL != right->right) cout << right->value << "->right->value = " << right->right->value << endl; else cout << right->value << "->right is empty!" << endl; return 0; }
【说明】
1、hash_map并不属于标准的STL,但是大部分的开发环境已经将其实现。在GCC中也可直接使用,但是需要声明命名空间为 __gnu_cxx;
2、C++中的hash_map的使用自定义的类型时,需要在类中实现hash函数和等于比较函数,所以我使用了string作为替代;
3、在string与int类型的互换中,我使用了stringstream这一辅助类型。
4、关键的思路还是参考了左程云老师提出的思路,具体实现有些差别,小伙伴们可以自行查看。
5、hash_map使用方法的参考文章:
6、测试代码未使用二叉树的遍历算法,大家就凑合着看看吧。^_^ ^_^ ^_^
注:
转载请注明出处;
转载请注明源思路来自于左程云老师的《程序员代码面试指南》。
时间: 2024-11-07 02:27:56