線段樹總結一【轉】

來源:互聯網
上載者:User

標籤:blog   http   使用   os   strong   資料   2014   ar   

資料結構:線段樹 【轉】

http://blog.csdn.net/wypblog/article/details/8219727

一、線段樹基本概念

           線段樹是一種二叉搜尋樹,與區間樹相似,它將一個區間劃分成一些單元區間,每個單元區間對應線段樹中的一個葉結點。
    對於線段樹中的每一個非葉子節點[a,b],它的左兒子表示的區間為[a,(a+b)/2],右兒子表示的區間為[(a+b)/2+1,b]。因此線段樹是平衡二叉樹,最後的子節點數目為N,即整個線段區間的長度。

    使用線段樹可以快速的尋找某一個節點在若干條線段中出現的次數,時間複雜度為O(logN)。而未最佳化的空間複雜度為2N,因此有時需要離散化讓空間壓縮。

   性質:父親的區間是[a,b],(c=(a+b)/2)左兒子的區間是[a,c],右兒子的區間是[c+1,b],線段樹需要的空間為數組大小的四倍

二、線段樹的儲存資料結構

    由上面的圖可以看出,儲存一顆線段樹和二叉樹有點類似,需要左孩子和右孩子節點,另外,為了儲存每條線段出現的次數,所以一般會加上計數的元素,其具體如下:

1 struct Node         // 線段樹2 {3     int left;4     int right;5     int counter;6 }segTree[4*BORDER]; 

其中,;left代表左端點、right代表右端點,counter代表每條線段出現的次數,BORDE代表線段端點座標不超過100。由上面的性質可以知道,我們需要4倍的空間來儲存。

三、線段樹支援的操作

一顆線段樹至少支援以下四個操作:

    • void construct(int index, int lef, int rig),構建線段樹 根節點開始構建區間[lef,rig]的線段樹
    • void insert(int index, int start, int end),插入線段[start,end]到線段樹, 同時計數區間次數
    • int query(int index, int x),查詢點x的出現次數,從根節點開始到[x,x]葉子的這條路徑中所有點計數相加方為x出現次數
    • void delete_ (int c , int d, int index),從線段樹中刪除線段[c,d]

 

具體操作如下:

1、線段樹的建立

/* 構建線段樹 根節點開始構建區間[lef,rig]的線段樹*/
void construct(int index, int lef, int rig)
{
segTree[index].left = lef;
segTree[index].right = rig;
if(lef == rig) // 分葉節點
{
segTree[index].counter = 0;
return;
}
int mid = (lef+rig) >> 1;
construct((index<<1)+1, lef, mid);
construct((index<<1)+2, mid+1, rig);
segTree[index].counter = 0;
}

 1 /* 構建線段樹 根節點開始構建區間[lef,rig]的線段樹*/ 2 void construct(int index, int lef, int rig) 3 { 4     segTree[index].left = lef; 5     segTree[index].right = rig; 6     if(lef == rig)   // 分葉節點 7     { 8         segTree[index].counter = 0; 9         return;10     }11     int mid = (lef+rig) >> 1;12     construct((index<<1)+1, lef, mid);13     construct((index<<1)+2, mid+1, rig);14     segTree[index].counter = 0;15 }
2、線段樹的元素插入

/* 插入線段[start,end]到線段樹, 同時計數區間次數 */
void insert(int index, int start, int end)
{
if(segTree[index].left == start && segTree[index].right == end)
{
++segTree[index].counter;
return;
}
int mid = (segTree[index].left + segTree[index].right) >> 1;
if(end <= mid)//左子樹
{
insert((index<<1)+1, start, end);
}else if(start > mid)//右子樹
{
insert((index<<1)+2, start, end);
}else//分開來了
{
insert((index<<1)+1, start, mid);
insert((index<<1)+2, mid+1, end);
}
}

 1 /* 插入線段[start,end]到線段樹, 同時計數區間次數 */ 2 void insert(int index, int start, int end) 3 { 4     if(segTree[index].left == start && segTree[index].right == end) 5     { 6         ++segTree[index].counter; 7         return; 8     } 9     int mid = (segTree[index].left + segTree[index].right) >> 1;10     if(end <= mid)//左子樹 11     {12         insert((index<<1)+1, start, end);13     }else if(start > mid)//右子樹 14     {15         insert((index<<1)+2, start, end);16     }else//分開來了 17     {18         insert((index<<1)+1, start, mid);19         insert((index<<1)+2, mid+1, end);20     }21 }
3、線段樹的元素尋找

/* 查詢點x的出現次數
* 從根節點開始到[x,x]葉子的這條路徑中所有點計數相加方為x出現次數
*/
int query(int index, int x)
{
if(segTree[index].left == segTree[index].right) // 走到葉子,返回
{
return segTree[index].counter;
}
int mid = (segTree[index].left+segTree[index].right) >> 1;
if(x <= mid)
{
return segTree[index].counter + query((index<<1)+1,x);
}
return segTree[index].counter + query((index<<1)+2,x);
}

 1 /* 查詢點x的出現次數  2  * 從根節點開始到[x,x]葉子的這條路徑中所有點計數相加方為x出現次數 3  */ 4 int query(int index, int x) 5 { 6     if(segTree[index].left == segTree[index].right) // 走到葉子,返回 7     { 8         return segTree[index].counter; 9     }10     int mid = (segTree[index].left+segTree[index].right) >> 1;11     if(x <= mid)12     {13         return segTree[index].counter + query((index<<1)+1,x);14     }15     return segTree[index].counter + query((index<<1)+2,x);16 }
4、線段樹的元素刪除

void delete_ (int c , int d, int index)
{
if(c <= segTree[index].left && d >= segTree[index].right)
segTree[index].counter--;
else
{
if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left);
if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right);
}
}


 1 void  delete_ (int c , int  d, int index) 2 { 3        if(c <= segTree[index].left && d >= segTree[index].right)  4            segTree[index].counter--; 5        else  6        { 7           if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left); 8           if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right); 9        }10 } 
四、線段樹的應用
  • 區間最值查詢問題
  • 連續區間修改或者單節點更新的動態查詢問題 
  • 多維空間的動態查詢
(轉載請註明:http://www.iteblog.com/archives/144,請不要用於商業目的。)
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.