八叉樹算法的改進

1、八叉樹的定義(熟悉的直接跳到第二步)
 
你有一個立方體,按照如下方法給它三刀:

橫切一刀,豎劈一刀,在與之前豎劈方向垂直的方向再砍一刀,這樣就分成八個大小相同的立方體;

對小立方體重複砍劈。。。。。

2、分析
(1) 
構建規則的八叉樹 
如果構建規則的八叉樹 ,則結構所佔的空間將非常大,而且很多情況下這些結構都是無用的;
常規構建方法:
struct OctTreeNode{
    LHLONG tag;//對於葉節點,爲統計的顏色數;對於非葉節點,恆爲-1。
    struct OctTreeNode *pChild[8];//下一級節點
};

 //創建八叉樹
int depth = 6; 
OctTreeNode *pRootNode = NULL;
m_depth = depth;
m_nodeNum = 1;
for(LHINT i=1; i<=m_depth; i++){
    m_nodeNum += (1 << ((i << 2) - i));
}

pRootNode = (OctTreeNode *)LHMalloc((m_nodeNum << 5) + (m_nodeNum << 2));//OctTreeNode的大小爲36字節,分解爲32(2的5次方)+ 4(2的平方)
if(pRootNode == NULL){
    goto initialize_octTree_fail;
}
memset(pRootNode, 0, sizeof(OctTreeNode));
pRootNode->tag = -1;
ret = createOctTree(1, pRootNode);


//遞歸函數
int createOctTree(int  depth, OctTreeNode *pParent){

    static LHDWORD _nodeIndex = 1;
    if(depth < (m_depth)){
        for(int  i=0; i<8; i++){
            pParent->pChild[i] = &pRootNode[_nodeIndex];
            memset(pParent->pChild[i], 0, sizeof(OctTreeNode));
            pParent->pChild[i]->tag = -1;

            _nodeIndex ++;
            createOctTree(depth + 1, pParent->pChild[i]);
        }
    }else{
        for(int  i=0; i<8; i++){
            pParent->pChild[i] = &pRootNode[_nodeIndex];
            memset(pParent->pChild[i], 0, sizeof(OctTreeNode));

            _nodeIndex ++;
        }
        if(_nodeIndex >= m_nodeNum){
            _nodeIndex = 1;
        }
    }
    return 0;
} 

(2) 運行上面的程序,你將會發現你的內存狂漲!!!
解決辦法:優化。
只使用葉節點,其餘的都丟棄!
struct _node{
DWORD num;
};

void Test()
{
DWORD r = 0;
DWORD g = 0;
DWORD b = 0;
DWORD ret = 0;

DWORD size = 400000;
_node *pList = (_node *)malloc(size * sizeof(_node));//這個就是簡化之後的八叉樹!!!
memset(pList, 0, size * sizeof(_node));

FILE *fd = fopen("data.dat", "wb");
char info[128] = {0};

BYTE depth = 6;
for(r=0; r<256; r++){
for(g=0; g<256; g++){
for(b=0; b<256; b++){
ret = (((r >> (8 - depth)) << (depth << 1)) | ((g >> (8 - depth)) << depth) | (b >> (8 - depth)));
pList[ret].num ++;
}
}
}

for(DWORD i=0; i<size; i++){
if(pList[i].num != 0){
sprintf(info, "%08lu      %lu\n", i, pList[i]);
fwrite(info, 1, strlen(info), fd);
}else{
break;
}
}

fclose(fd);
free(pList);
}  
記錄的文件如下:
00000000      64
00000001      64
00000002      64
00000003      64
00000004      64
00000005      64
00000006      64
00000007      64
00000008      64
00000009      64
00000010      64
00000011      64
00000012      64
。。。。 
 
。。。。 
00130949      64
00130950      64
00130951      64
00130952      64
00130953      64
00130954      64
00130955      64
00130956      64
00130957      64
00130958      64
00130959      64 
。。。。  
。。。。 
 
00262131      64
00262132      64
00262133      64
00262134      64
00262135      64
00262136      64
00262137      64
00262138      64
00262139      64
00262140      64
00262141      64
00262142      64
00262143      64
設置的是六級的深度,一共是262144條數據,佔用內存爲1M!而
構建規則的六級深度的八叉樹,一共有299592個節點(不算根節點,只算子節點和葉節點),按照每個葉節點佔用32字節,結構內存將達到9.142822265625M,難以接受!
 
至於查找、修改等操作,上面的代碼演示的很清楚了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章