划分树

1.划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值.

2.查找整序列的第k大值方法:

a.采用快速查找法,分治思想。然而此方法会破坏原序列,并且需要O(n)的时间复杂度。

b.使用二叉平衡树进行维护,此方法每次查找时间复杂度仅为O(logn)。然而此方法丢失了原序列的顺序信息,无法查找出某区间内的第k大值

c.划分树:基本思想就是对于某个区间,把它划分成两个子区间,左边区间的数小于右边区间的数。查找的时候通过记录进入左子树的数的个数,确定下一个查找区间,最后范围缩小到1,就找到了。

3.建树:

使用一个辅助数组对原数组进行排序,找到这个区间的中位数a[mid],小于等于a[mid]的数划入左子树[l,mid],大于则划入右子树[mid+1,r]。同时,对于第i个数,记录在[l,i]区间内有多少数被划入左子树.注意对于被分到同一子树的元素,元素间的相对位置不能改变。然后递归建树。

4.查找:

查找的过程中主要问题就是确定将要查找的区间。查找的定义:查找深度为h,在大区间[st,ed]中找小区间[s,e]中的第k元素。

解决方法:

在大区间[st,ed]中找小区间[s,e]中的第k元素:在区间[st,s-1]中有sum[s-1]进入左子树,记它为l。同理区间[st,e]中有sum[e]个数进去左子树,记它为r。所以,我们知道区间小区间[s,e]中有(r-l)个数进入左子树。那么如果(r-l)>=k,那么就在左子树中继续查找,否则就在右子树中继续查找。

如果接下来要查找的是左子树,即在大区间[st,mid]中找小区间[?,?]中的第k元素:那么小区间应该是[st+l,st+r-1]。显然,这里k不用变。

如果接下来要查找的是右子树,即在大区间[mid+1,ed]中找小区间[?,?]中的第k-(r-l)元素:那么小区间应该是[mid+1++([st,s-1]区间中进入右子树的个数),mid+1+[st,e]区间进入右子树的个数)-1]。显然,这里k要减去区间里已经进入左子树的个数,即k变为k-(r-l)。

 于是递归继续查找直到s=e即可。
代码:
View Code
  1 #include <iostream>

  2 #include <stdio.h>

  3 #include <algorithm>

  4 #include <memory.h>

  5 using namespace std;

  6 //此方法只能对互不相同的元素进行处理

  7 const int maxnum=9;

  8 struct node

  9 {

 10     int array[maxnum];

 11     int sum[maxnum];

 12 }tree[10];   //树有10层

 13 int sorted[maxnum];

 14 

 15 void Build_tree(int cur,int l,int r)

 16 {

 17     if(l==r)

 18         return ;

 19     int m=(l+r)/2;

 20     int i;

 21     

 22     int lsame=m-l+1; //这是往cur+1左子树中一共放入的节点,其中小于中值的一定在左子树中,等于中值的可能在左子树,也可能在右子树

 23     for(i=l;i<=r;i++)

 24         if(tree[cur].array[i]<sorted[m])

 25             lsame--;//与中值相同的放在左子树中的个数

 26 

 27     int lnum=l,rnum=m+1;

 28     for(i=l;i<=r;i++)

 29     {

 30         if(i==l)

 31             tree[cur].sum[i]=0;

 32         else

 33             tree[cur].sum[i]=tree[cur].sum[i-1];

 34         if(tree[cur].array[i]<sorted[m])

 35         {

 36             tree[cur].sum[i]++;

 37             tree[cur+1].array[lnum++]=tree[cur].array[i];

 38         }

 39         else if(tree[cur].array[i]>sorted[m])

 40             tree[cur+1].array[rnum++]=tree[cur].array[i];

 41         else   //if(tree[cur].array[i]==sorted[m])

 42         {

 43             if(lsame>0)

 44             {

 45                 lsame--;

 46                 tree[cur].sum[i]++;

 47                 tree[cur+1].array[lnum++]=tree[cur].array[i];

 48             }

 49             else

 50                 tree[cur+1].array[rnum++]=tree[cur].array[i];

 51         }

 52     }

 53     Build_tree(cur+1,l,m);

 54     Build_tree(cur+1,m+1,r);

 55 }

 56 

 57 int find(int cur,int st,int ed,int l,int r,int k)

 58 {

 59     cout<<cur<<" "<<st<<" "<<ed<<" "<<l<<" "<<r<<" "<<k<<endl;

 60     if(l==r)

 61         return tree[cur].array[l];

 62     int m=(st+ed)/2;

 63     int lnum,rnum;

 64     if(l-1<st)

 65         lnum=0;

 66     else

 67         lnum=tree[cur].sum[l-1];

 68     rnum=tree[cur].sum[r];

 69     if(rnum-lnum>=k)//表示有几个点进入左子树

 70     {

 71         return find(cur+1,st,m,st+lnum,st+rnum-1,k);

 72     }

 73     else

 74     {

 75 //        int rightl,rightr;

 76 //        if(l-1<st)

 77 //            rightl=0;

 78 //        else

 79 //            rightl=l-1-lnum;

 80 //        rightr=(r-l+1)-rnum-1;

 81         return find(cur+1,m+1,ed,m+1+(l-st-lnum),m+1+(r-st-rnum),k-(rnum-lnum));

 82     }

 83 }

 84 

 85 int main()

 86 {

 87     int i,j;

 88     for(i=1;i<maxnum;i++)

 89     {

 90         scanf("%d",&tree[0].array[i]);

 91         sorted[i]=tree[0].array[i];

 92     }

 93     sort(sorted+1,sorted+maxnum);

 94     Build_tree(0,1,maxnum-1);

 95 

 96     for(i=0;i<4;i++)

 97     {

 98         cout<<i<<endl;

 99         for(j=1;j<maxnum;j++)

100             cout<<tree[i].array[j]<<" ";

101         cout<<endl;

102         for(j=1;j<maxnum;j++)

103             cout<<tree[i].sum[j]<<" ";

104         cout<<endl;

105     }

106 

107     int res;

108     res=find(0,1,maxnum-1,2,5,2);

109     cout<<res<<endl;

110     return 0;

111 }

112 

113 

114 /*

115 1 1 1 1 1 1 1 1

116 */

117 

118 

119 //    for(i=0;i<4;i++)

120 //    {

121 //        cout<<i<<endl;

122 //        for(j=1;j<maxnum;j++)

123 //            cout<<tree[i].array[j]<<" ";

124 //        cout<<endl;

125 //        for(j=1;j<maxnum;j++)

126 //            cout<<tree[i].sum[j]<<" ";

127 //        cout<<endl;

128 //    }

问题:

一开始的处理只能针对互不相同的元素,后来引入一个lsame,解决了重复相同元素的问题。

 

 

 

你可能感兴趣的:(树)