1.二叉树的下一个节点
给定一个二叉树和其中的一个结点,请找出中序遍历(左,根,右)顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:1)当前节点的右子树存在,则在其右子树中一直向左遍历,则下一节点就是最左边的叶子节点。
2)当前节点的右子树不存在且当前节点是其父节点的左子节点,则其父节点就是下一节点。
3)当前节点的右子树不存在且当前节点是其父节点的右子节点,则一直向上遍历,寻找一个节点是这个节点父节点的左子节点,则这个父节点就是下一节点。
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(!pNode)
return NULL;
TreeLinkNode* result=NULL;
if(pNode->right){//右子树存在
TreeLinkNode* node=pNode->right;
while(node->left)
node=node->left;
result=node;
}
else{//右子树不存在
if(pNode->next && pNode==pNode->next->left) //此时节点是其父节点的左节点
result=pNode->next;
else{//此时节点是其父节点的右节点
TreeLinkNode* node=pNode->next;
while(node && node->next){
if(node==node->next->left){ //向上寻找一个节点是其父节点的左节点,返回父节点
result=node->next;
break;
}
node=node->next;
}
}
}
return result;
}
2.对称的二叉树
判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
bool isSymmetrical(TreeNode* pRoot)
{
return isSame(pRoot,pRoot);
}
bool isSame(TreeNode* root1,TreeNode* root2){
if(!root1 && !root2)
return true;
if((root1 && !root2) || (!root1 && root2))
return false;
if(root1->val!=root2->val)
return false;
else
return isSame(root1->left,root2->right) && isSame(root1->right,root2->left); //判断此树和其镜像树是否相同
}
按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
思路:将树的层次,按奇偶分开,偶数层从左到右打印,奇数层从右到左打印。
打印某一层节点的同时要保存下一层的节点。这里用两个stack q,p分别保存偶数,奇数层。
奇数层节点压栈,由左到右压;偶数层压栈,由右到左压。这样出栈的时候刚好相反。
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
vector<int> temp;
if(!pRoot)
return result;
stack<TreeNode*> q,p;//q 左到右,p 右到左
int index=0;
q.push(pRoot);
while(!q.empty() || !p.empty()){
if(index%2==0){
while(!q.empty()){
TreeNode* node=q.top();
temp.push_back(node->val);
if(node->left)
p.push(node->left);
if(node->right)
p.push(node->right);
q.pop();
}
}
else{
while(!p.empty()){
TreeNode* node=p.top();
temp.push_back(node->val);
if(node->right)
q.push(node->right);
if(node->left)
q.push(node->left);
p.pop();
}
}
result.push_back(temp);
temp.clear();
++index;
}
return result;
}
4.把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路:基本和上题一样,也是按奇偶分层,只不过每层都是从左到右打印。这里用两个队列queue(队尾进队首出)保存奇偶层节点。每层节点进队的顺序从左到右,这样出队时刚好也是从左到右。
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
vector<int> temp;
if(!pRoot)
return result;
queue<TreeNode*> q,p; //相隔保存每行的节点
q.push(pRoot);
int index=0;// 由上到下按奇偶分开
while(!q.empty() || !p.empty()){
if(index%2==0)
while(!q.empty()){
TreeNode* node=q.front();
temp.push_back(node->val);
if(node->left)
p.push(node->left);
if(node->right)
p.push(node->right);
q.pop();
}
else
while(!p.empty()){
TreeNode* node=p.front();
temp.push_back(node->val);
if(node->left)
q.push(node->left);
if(node->right)
q.push(node->right);
p.pop();
}
result.push_back(temp);
temp.clear();
++index;
}
return result;
}
5.二叉搜索树的第k个结点
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
思路:按节点大小顺序寻找,肯定是中序遍历。先是左子树中寻找,然后是根节点,最后是右子树中寻找。是一个递归的过程。这里用一个整型变量k来记录遍历到了第一个节点。当k变成1时,刚好是第k个顺序节点。
TreeNode* KthNode(TreeNode* pRoot, unsigned int k)
{ if(!pRoot || k==0)
return NULL;
return FindKNode(pRoot,k);
}
TreeNode* FindKNode(TreeNode* pRoot, unsigned int &k){ //中序遍历
if(!pRoot)
return NULL;
TreeNode* result=NULL;
result=FindKNode(pRoot->left,k);//左子树中寻找
if(!result){
if(k==1)//检查根节点是否是第k大的节点
result=pRoot;
else
--k;
}
if(!result)
result=FindKNode(pRoot->right,k);//右子树中寻找
return result;
}
6. 数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路:考虑到时间复杂度的原因,我们这里不用常规的排序算法。
这里借助两个堆结构(最小堆和最大堆)来存放数据。为了寻找中位数,必须保证两个堆的大小之差不能超过1,这样通过两个堆顶的元素就可以求得中位数。
当已有总元素个数是偶数时,新元素压入最小堆;奇数时,压入最大堆。
为了保证每次压堆后,最小堆中的元素都大于最大堆的元素,压堆的时候需做适当的元素调整。
class Solution {
public:
void Insert(int num)
{
int l=min.size()+max.size();
if(l%2==0){
if(max.size()>0 && num<max[0]){
max.push_back(num);
push_heap(max.begin(),max.end(),less<int>());
num=max[0];
pop_heap(max.begin(),max.end(),less<int>());
max.pop_back();
}
min.push_back(num);
push_heap(min.begin(),min.end(),greater<int>());
}
else{
if(num>min[0]){//奇数时,min的size肯定大于0;
min.push_back(num);
push_heap(min.begin(),min.end(),greater<int>());
num=min[0];
pop_heap(min.begin(),min.end(),greater<int>());
min.pop_back();
}
max.push_back(num);
push_heap(max.begin(),max.end(),less<int>());
}
}
double GetMedian()
{ int l=min.size()+max.size();
if(l==0)
return 0;
if(l%2==0)
return (double(min[0]+max[0])/2);
else
return double(min[0]);
}
private:
vector<int> min;//小顶堆,最小堆
vector<int> max;//大顶堆
};