二叉树(补充)

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); //判断此树和其镜像树是否相同
        
    }


3.按之字形顺序打印二叉树

按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:将树的层次,按奇偶分开,偶数层从左到右打印,奇数层从右到左打印。

打印某一层节点的同时要保存下一层的节点。这里用两个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;//大顶堆
    

};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值