資料結構 劃分樹小結

2021-07-11 03:43:09 字數 1794 閱讀 5544

劃分樹是一種基於線段樹的資料結構。主要用於快速求出(在log(n)的時間複雜度內)序列區間的第k大值。

先看下圖已經建好的劃分樹是什麼樣子的,原始陣列是[1,5,2,3,6,4,7,3,0,0],並把它作為樹的第0層,然後把這些數中較小的數再組成[1,2,3,0,0],順序還是遵照原陣列的順序,同樣將較大的數再組成[5,6,4,7,3]。把這兩個陣列作為樹的第二層,它們的父親則是第一層的原始陣列,這樣一直往下建立,就把劃分樹建好了。

那麼到底如何建立這個劃分樹呢?例如如何將[1,5,2,3,6,4,7,3,0,0]分為[1,2,3,0,0]和[5,6,4,7,3]兩部分?

設[1,5,2,3,6,4,7,3,0,0]為陣列a,長度為len。

首先預處理將陣列a排序:[0,0,1,2,3,3,4,5,6,7],然後在a中分別找到「0,0,1,2,3」這(len/2)個數,並按陣列a的順序放到下一層[1,2,3,0,0]。可以發現,這一操作的複雜度是o(len)。

下面看如何查詢在某一區間內的第k小的數。仍然觀察下圖,要查詢區間[3,9]中第2小的數,先標記在原陣列a中[3,9]這個區間(陣列下標從1開始),即val[0]層塗上黃色背景的部分,現在我們如何知道這個黃色背景的部分在下一層如何分布呢?這裡就需要用到乙個陣列toleft[ ][ ] ,toleft[dep][i]表示下標小於等於i的數中在第dep層中分在其左孩子的個數。

比如圖中val[0]這一層中,toleft[0][1]=1,toleft[0][2]=1,toleft[0][3]=2…..。這樣的話就可以利用toleft陣列來確定黃色背景區域在下一層如何分布了。可以確定[3,9]區間在左孩子的有left[0][9]-left[0][3]=3個,所以最終結果肯定在左孩子中找了。當然在這個左孩子中,要排除掉藍色背景部分的1,0,就順利得到下一步要在第二層查詢的是:區間[2,4]的第2小的數。依次類推,得到最終結果。

摘自

/*

* 劃分樹(查詢區間第k大)

*/const

int maxn = 100010

;int tree[20][maxn];//

表示每層每個位置的值

int sorted[maxn];//

已經排序好的數

int toleft[20][maxn];//

toleft[p][i]表示第i層從1到i有數分入左邊

void build(int l,int r,int

dep)

上海大學 acm 模板 by kuangbin

40 / 152

acm 模板 kuangbin

else

tree[dep+1][rpos++] =tree[dep][i];

toleft[dep][i] = toleft[dep][l-1] + lpos -l;

}build(l,mid,dep+1

); build(mid+1,r,dep+1);}

//查詢區間第k大的數,[l,r]是大區間,[l,r]是要查詢的小區間

int query(int l,int r,int l,int r,int dep,int

k)

else

}int

main()

sort(sorted+1,sorted+n+1

); build(

1,n,0

);

ints,t,k;

while(m--)

}return0;

}

劃分樹小結

最近學習了一下劃分樹,下面總結一下。我們在求區間最值的時候,一般可以用線段樹解決,但是如果要求區間第k小或者第k大值的話線段樹就有點力不從心了,這是我們可以用劃分樹來解決。劃分樹利用了快速排序的思想,首先是建樹,我們設當前區間的中位數為mid,為了能快速找到區間的中位數,我們一般先對原序列做一次排序...

Book 資料結構 線段樹 小結

2014 09 12 21 49 59 2014 10 04 16 59 44 花了挺長的一段時間學習線段樹,所刷的題 poj線段樹20題彙總,hdu題庫數道 比賽題2道。線段樹這種結構,主要優勢在於把區間問題從o n 的複雜度優化到o logn 幾個注意點 no.1 線段樹的陣列通常要開到葉子節點...

資料結構小結

資料結構就是乙個集合 資料結構 邏輯結構 線性資料結構 線性表 棧 佇列 字串 陣列 對應順序表 非線性資料結構 集合 樹結構 圖 儲存結構 順序儲存結構 順序表 非順序儲存結構 鏈式儲存結構 鍊錶 由指標來實現 雜湊 雜湊 索引 一種邏輯結構可以使用不同的儲存結構,那麼就會形成不同的名稱。線性表是...