何為四叉樹?
四元樹又稱四叉樹是一種樹狀數據結構,在每一個節點上會有四個子區塊。四元樹常應用於二維空間數據的分析與分類。 它將數據區分成為四個象限。數據范圍可以是方形或矩形或其他任意形狀。
概念可能太抽象,沒關系,先繼續閱讀看看如何實現四叉樹。
如何實現傳統的四叉樹?
請參考以下兩篇文章,這兩篇文章不需要VPN即可閱讀,更加棒的是兩篇文章都附帶代碼。
http://www.kyleschouviller.com/wsuxna/quadtree-source-included/
為了照顧一下英文不好的同學,我送佛送到西,翻譯部分內容,方便理解什么是四叉樹。
四叉樹是一種數據結構,用於將二維區域划分為更易於管理的部分。它是一個擴展的二叉樹,二叉樹有兩個孩子節點,它有四個。
舉例如下,圖片所代表的二維空間被分成I,II,III,IV 四個部分。


當越來越多紅色方塊需要塞入的二維空間中時,為了防止四叉樹根節點管理方塊過的,此時根節點將會分裂成4個子節點。每個子節點代表和管理父節點1/4空間。
紅色方塊分別轉交給子節點管理。任何不能被子節點完全包含的紅色方塊,將由該節點的父節點管理。

當更多紅色方塊塞入到二維空間時,子節點可以繼續分割新的子節點。

正如你所見,每個節點分別管理少量的紅色方塊。OK,你可能會想這有什么用呢?因為父節點的空間完全包含子節點的空間,故沒有和父節點空間產生交集,則不會和其任意的子節點空間產生交集。
這對於過濾碰撞檢測,范圍檢索有巨大的幫助。
比如,對於2D塔防游戲,屏幕中有大量的子彈和小怪,對所有的子彈和所有小怪全遍歷檢測是否碰撞,CPU肯定吃不消。如果子彈在屏幕左上角的,只需檢測屏幕左上角的節點體系。
采用四叉樹優化后,每個子彈只需要少量的小怪進行細致的碰撞檢測。
傳統四叉樹缺點?
- 對於很小的物體,如果處在世界空間的中心,則只能分配到根節點中。
- 應用於動態場景時,節點在需要分割時才進行分割(不需要時也可以刪除節點),雖然節省內存,但是需要經常性的開辟和釋放內存,影響性能。
- 應用於動態場景時,需要在對象的位置時刻在變化,對象可能隨時切換在樹中的節點。而且這些節點並不是在同一層級(可能引起樹結構的改變),影響性能。
松散的四叉樹?
松散的意思就是,讓節點所管理的空間比節點自身代表的空間大一些,這樣節點和節點管理空間之間會有部分重合,顯得比較松散故因此得名。至於大多少最好,沒有明確的理論支持。
但是截至目前大一倍是非常好的選擇。在我給出的代碼中,我使用nodeRect和looseRect 加以區分這兩個空間。其中,looseRect尺寸為nodeRect尺寸的兩倍。
不難想到,當一個物體的尺寸小於nodeRect的尺寸時,只要物體的中心處於nodeRect之中,那么物體一定包含於其looseRect之中。
對於松散的四叉樹,我們不在要求nodeRect完全包含物體,只要求looseRect完全包含物體,那么對於很小的物體,即使處於特殊位置,也能夠分配到相應大小的子節點中。
松散的四叉樹克服了傳統四叉樹的第一個缺點。
我沒有找到專門描述松散四叉樹的資料,不過不用擔心,松散八叉樹的資料還是很多的。推薦如下:
http://cloudgrassland.com/2015/12/162-2/
https://anteru.net/blog/2008/11/14/315/index.html
http://www.tulrich.com/geekstuff/partitioning.html
閱讀一系列文章之后,我們可以發現松散的四叉樹,還可以克服傳統四叉樹的另外兩個缺點。讓它更適用於動態場景。方法就是將網格與松散的四叉樹結合。
上文中已經提到,松散1倍情況下,當一個物體的尺寸小於nodeRect的尺寸時,只要物體的中心處於nodeRect之中,那么物體一定包含於其looseRect之中。
所以,對於尺寸固定的物體,它在四叉樹中的層級也是固定的。並且我們給四叉樹每一層,分配一個網格,用網格來把空間進行均勻分割。
已知深度的情況下(使用特定層網格),只需要選擇距離物體中心最近的節點就可以確定物體應該被哪個節點的包圍盒所包含,時間復雜度O(1)。也就是說當物體
運動時,可以非常輕易的更改其在四叉樹中的節點位置。
松散四叉樹缺點?
- 如果松散四叉樹使用網格,網格需要預先開辟足量的內存,所以會使用更多內存。同樣我們無需動態的增加或減少內存。既是優點又是缺點!
- 查詢一個松散的四叉樹時,需要復雜一點。因為節點是松散的,需要查詢的節點會增加一點。
松散的四叉樹實戰!
也許你已經不厭其煩,正所謂 talking is cheap,show me the code
https://github.com/RonTang/GridLooseQuadtree/
這個是過年期間抽空寫出的代碼,具體沒有來的及完善,不過應該可用於學習交流。
啊哈,新年的第一篇文章,祝大家新年快樂~~~
轉載請標明出處,謝謝合作