AOI主要有九宮格、燈塔和十字鏈表的算法實現。本文闡述十字鏈表的實現和嘗試。node
根據二維地圖,將其分紅x軸和y軸兩個鏈表。若是是三維地圖,則還須要維護多一個z軸的鏈表。將對象的座標值按照大小相應的排列在相應的座標軸上面。ios
對對象的操做主要有如下三個接口:算法
既然是鏈表,很天然地想到用線性表來實現。由於存在向前和向後找的狀況,因此使用雙鏈表實現。其實實現也是很是簡單,就是兩個雙鏈表(這裏以二維地圖舉例)。那麼咱們的節點須要四個指針,分佈爲x軸的先後指針,y軸的先後指針。優化
// 雙鏈表(對象) class DoubleNode { public: DoubleNode(string key, int x, int y) { this->key = key; this->x = x; this->y = y; xPrev = xNext = NULL; }; DoubleNode * xPrev; DoubleNode * xNext; DoubleNode * yPrev; DoubleNode * yNext; string key; // 只是一個關鍵字 int x; // 位置(x座標) int y; // 位置(y座標) private: };
下面是地圖場景信息和接口。這裏的實現比較粗略,是帶頭尾的的雙鏈表,暫時不考慮空間佔用的問題。類Scene
有分別有一個頭尾指針,初始化的時候會爲其賦值,主要用DoubleNode
類的指針來存儲x軸和y軸的頭尾。初始化的時候,將_head
的next指針指向尾_tail
;將_tail
的prev指針指向_head
。this
// 地圖/場景 class Scene { public: Scene() { this->_head = new DoubleNode("[head]", 0, 0); // 帶頭尾的雙鏈表(可優化去掉頭尾) this->_tail = new DoubleNode("[tail]", 0, 0); _head->xNext = _tail; _head->yNext = _tail; _tail->xPrev = _head; _tail->yPrev = _head; }; // 對象加入(新增) DoubleNode * Add(string name, int x, int y); // 對象離開(刪除) void Leave(DoubleNode * node); // 對象移動 void Move(DoubleNode * node, int x, int y); // 獲取範圍內的AOI (參數爲查找範圍) void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen); private: DoubleNode * _head; DoubleNode * _tail; };
將DoubleNode
對象插入到十字鏈表中。x軸和y軸分別處理,處理方法基本一致。其實就是雙鏈表的數據插入操做,須要從頭開始遍歷線性表,對比相應軸上的值的大小,插入到合適的位置。spa
void _add(DoubleNode * node) { // x軸處理 DoubleNode * cur = _head->xNext; while(cur != NULL) { if((cur->x > node->x) || cur==_tail) // 插入數據 { node->xNext = cur; node->xPrev = cur->xPrev; cur->xPrev->xNext = node; cur->xPrev = node; break; } cur = cur->xNext; } // y軸處理 cur = _head->yNext; while(cur != NULL) { if((cur->y > node->y) || cur==_tail) // 插入數據 { node->yNext = cur; node->yPrev = cur->yPrev; cur->yPrev->yNext = node; cur->yPrev = node; break; } cur = cur->yNext; } }
假設可視範圍爲x軸2之內,y軸2之內,則運行:指針
控制檯結果(前8行):調試
步驟1結果圖示:code
步驟2結果圖示:對象
其實都是雙鏈表的基本操做,斷掉其相應的指針就行了。按理,是須要
move和leave操做如圖,move是將d(3,3)移動到(4,4),而後再打印其AOI範圍。
控制檯結果:
移動後AOI範圍圖示:
#include "stdafx.h" #include "stdio.h" #include <iostream> #include <string> using namespace std; // 雙鏈表(對象) class DoubleNode { public: DoubleNode(string key, int x, int y) { this->key = key; this->x = x; this->y = y; xPrev = xNext = NULL; }; DoubleNode * xPrev; DoubleNode * xNext; DoubleNode * yPrev; DoubleNode * yNext; string key; int x; // 位置(x座標) int y; // 位置(y座標) private: }; // 地圖/場景 class Scene { public: Scene() { this->_head = new DoubleNode("[head]", 0, 0); // 帶頭尾的雙鏈表(可優化去掉頭尾) this->_tail = new DoubleNode("[tail]", 0, 0); _head->xNext = _tail; _head->yNext = _tail; _tail->xPrev = _head; _tail->yPrev = _head; }; // 對象加入(新增) DoubleNode * Add(string name, int x, int y) { DoubleNode * node = new DoubleNode(name, x, y); _add(node); return node; }; // 對象離開(刪除) void Leave(DoubleNode * node) { node->xPrev->xNext = node->xNext; node->xNext->xPrev = node->xPrev; node->yPrev->yNext = node->yNext; node->yNext->yPrev = node->yPrev; node->xPrev = NULL; node->xNext = NULL; node->yPrev = NULL; node->yNext = NULL; }; // 對象移動 void Move(DoubleNode * node, int x, int y) { Leave(node); node->x = x; node->y = y; _add(node); }; // 獲取範圍內的AOI (參數爲查找範圍) void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen) { cout << "Cur is: " << node->key << "(" << node ->x << "," << node ->y << ")" << endl; cout << "Print AOI:" << endl; // 日後找 DoubleNode * cur = node->xNext; while(cur!=_tail) { if((cur->x - node->x) > xAreaLen) { break; } else { int inteval = 0; inteval = node->y - cur->y; if(inteval >= -yAreaLen && inteval <= yAreaLen) { cout << "\t" << cur->key << "(" << cur ->x << "," << cur ->y << ")" << endl; } } cur = cur->xNext; } // 往前找 cur = node->xPrev; while(cur!=_head) { if((node->x - cur->x) > xAreaLen) { break; } else { int inteval = 0; inteval = node->y - cur->y; if(inteval >= -yAreaLen && inteval <= yAreaLen) { cout << "\t" << cur->key << "(" << cur ->x << "," << cur ->y << ")" << endl; } } cur = cur->xPrev; } }; // 調試代碼 void PrintLink() // 打印鏈表(從頭開始) { // 打印x軸鏈表 DoubleNode * cur = _head->xNext; while (cur != _tail) { cout << (cur->key) << "(" << (cur->x) <<"," << (cur->y) << ") -> " ; cur = cur->xNext; } cout << "end" << endl; // 打印y軸鏈表 cur = _head->yNext; while (cur != _tail) { cout << (cur->key) << "(" << (cur->x) <<"," << (cur->y) << ") -> " ; cur = cur->yNext; } cout << "end" << endl; }; private: DoubleNode * _head; DoubleNode * _tail; void _add(DoubleNode * node) { // x軸處理 DoubleNode * cur = _head->xNext; while(cur != NULL) { if((cur->x > node->x) || cur==_tail) // 插入數據 { node->xNext = cur; node->xPrev = cur->xPrev; cur->xPrev->xNext = node; cur->xPrev = node; break; } cur = cur->xNext; } // y軸處理 cur = _head->yNext; while(cur != NULL) { if((cur->y > node->y) || cur==_tail) // 插入數據 { node->yNext = cur; node->yPrev = cur->yPrev; cur->yPrev->yNext = node; cur->yPrev = node; break; } cur = cur->yNext; } } }; // -------------------------------------------- void main() { Scene scene = Scene(); // 增長 scene.Add("a", 1, 5); scene.Add("f", 6, 6); scene.Add("c", 3, 1); scene.Add("b", 2, 2); scene.Add("e", 5, 3); DoubleNode * node = scene.Add("d", 3, 3); scene.PrintLink(); scene.PrintAOI(node, 2, 2); // 移動 cout << endl << "[MOVE]" << endl; scene.Move(node, 4, 4); scene.PrintLink(); scene.PrintAOI(node, 2, 2); // 刪除 cout << endl << "[LEAVE]" << endl; scene.Leave(node); scene.PrintLink(); }