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(); }