以 O(h) 的时间复杂度将二叉搜索树分成两半

问题描述

我正在练习二叉搜索树,我必须回答一个问题: 一个树结构被给出为

struct tree{
    int key;
    int lcnt;
    struct tree *lc;
    struct tree *rc;
};

其中 lcnt 是一个整数,保存每个节点左子树的节点数。问题是每次使用有效值的 lcnt 将树分成两半更新。分割算法必须花费 O(h) 时间,其中 h 是树的高度。我在下面找到了解决方案,它适用于大多数树木。但是现在考虑这棵树

          170
         /
       45
        \
         30

结果将是:tree1: 170,tree2: 45。 我不知道如何修复它,因为如果我尝试诸如“如果节点是叶子则不要拆分”之类的东西,那么我就会遇到其他树的问题。 split 函数采用参数 root ,即主树的根,一个整数,即树的长度/2,并返回 2 棵新树。一个返回,另一个通过引用使用第三个参数双指针树。我还使用 updt 函数和一些计算来在每次拆分时更新 lcnt。

代码在这里

struct tree* split(struct tree *root,struct tree **new_tree,int collect){
     struct tree *new_root_1,*new_root_2,*link1=NULL,*link2=NULL;
     struct tree *current=root,*prev=NULL,*temp=NULL;
     if(!root)
         return NULL; //empty tree
     int collected=0,created_root1=0,created_root2=0;
     int decrease;
     while(current!=NULL && collected<collect){
         if(collected+current->lcnt+1<=collect){
             // there is space for the left subtree so take it all and move to the right
             collected=collected+current->lcnt+1;  //update the number of the collected nodes
             if(!created_root1){
                 //create the root for the one tree
                 created_root1=1;
                 new_root_1=current;
                 link1=current;
             }else{
                 link1->rc=current;
                 link1=current;
             }
             if(!created_root2 && collect==collected)
                 //in case the tree must be splited in half
                 new_root_2=current->rc;
             prev=current;
             current=current->rc;
             //break the node link
             prev->rc=NULL;
         }else{
             // there is no space for the left subtree so traverse it until it becomes small enough
             if(!created_root2){
                 //create the root for the second tree
                 created_root2=1;
                 new_root_2=current;
                 link2=current;
             }else{
                 link2->lc=current;
                 // at every link at left the count_total_tasks will help to update the lcnt of the 
                 parent node
                 temp=new_root_2;
                 while(temp!=NULL){
                     temp->lcnt=count_total_tasks(temp->lc);
                     temp=temp->lc;
                 }
                 
                 link2=current;
             }
             prev=current;
             current=current->lc;
 
             //break the node link
             prev->lc=NULL;
             //update the lcnt
             decrease=prev->lcnt;
             updt(new_root_2,decrease);         
         }
     }
     *new_tree=new_root_2;
 
     return new_root_1; 
 }

这是 updt 函数

void updt(struct tree* root,int decrease){
    struct tree *temp;
    temp=root;
    while(temp!=NULL){
    temp->lcnt=temp->lcnt-decrease;
        temp=temp->lc;
    }
}

解决方法

您的测试用例,

     170
     /
   45
    \
     30

不是有效的二叉搜索树。