AOI主要有九宫格、灯塔和十字链表的算法实现。本文阐述十字链表的实现和尝试。

1. 基本原理

根据二维地图,将其分成x轴和y轴两个链表。如果是三维地图,则还需要维护多一个z轴的链表。将对象的坐标值按照大小相应的排列在相应的坐标轴上面。

2. 基本接口

对对象的操作主要有以下三个接口:

  • add:对象进入地图;
  • leave:对象离开地图;
  • move:对象在地图内移动。

2. 算法实现

既然是链表,很自然地想到用线性表来实现。因为存在向前和向后找的情况,所以使用双链表实现。其实实现也是非常简单,就是两个双链表(这里以二维地图举例)。那么我们的节点需要四个指针,分布为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

// 地图/场景
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;
};

2.1. add(进入地图)

DoubleNode对象插入到十字链表中。x轴和y轴分别处理,处理方法基本一致。其实就是双链表的数据插入操作,需要从头开始遍历线性表,对比相应轴上的值的大小,插入到合适的位置。

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以内,则运行:

  1. 分别插入以下数据a(1,5)、f(6,6)、c(3,1)、b(2,2)、e(5,3),然后插入d(3,3),按照x轴和y轴打印其双链表结果;
  2. 插入d(3,3)数据,求其可视AOI范围(如图,除了f(6,6),其它对象都在d的可视范围内)。

控制台结果(前8行):

步骤1结果图示:

步骤2结果图示:

2.2. leave(离开地图)和move(移动)

其实都是双链表的基本操作,断掉其相应的指针就好了。按理,是需要

move和leave操作如图,move是将d(3,3)移动到(4,4),然后再打印其AOI范围。

控制台结果:

移动后AOI范围图示:

3. 完整代码实例

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

[game]十字链表的AOI算法实现的更多相关文章

  1. 数据结构之BF算法,kmp算法,三元组,十字链表总结

    在这一章中,老师教了我们四种数据结构:BF算法,kmp算法,三元组和十字链表:还给我们讲了2019年团体天体赛中T1-8的AI题 1.对于BF和kmp算法,老师除了在课堂上讲解算法的主要核心思想外,还 ...

  2. 数据结构C语言版 有向图的十字链表存储表示和实现

    /*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...

  3. 利用十字链表压缩稀疏矩阵(c++)-- 数据结构

    题目: 7-1 稀疏矩阵 (30 分)   如果一个矩阵中,0元素占据了矩阵的大部分,那么这个矩阵称为“稀疏矩阵”.对于稀疏矩阵,传统的二维数组存储方式,会使用大量的内存来存储0,从而浪费大量内存.为 ...

  4. 十字链表 Codeforces Round #367 E Working routine

    // 十字链表 Codeforces Round #367 E Working routine // 题意:给你一个矩阵,q次询问,每次交换两个子矩阵,问最后的矩阵 // 思路:暴力肯定不行.我们可以 ...

  5. 图->存储结构->十字链表

    文字描述 十字链表是有向图的另一种链式存储结构. 在十字链表中,对应于有向图中每一条弧有一个结点,对应于每个顶点也有一个结点.这些结点的结构如下所示: 在弧结点中有5个域: 尾域tailvex和头域h ...

  6. 稀疏矩阵的加法(用十字链表实现A=A+B)

    描写叙述: 输入两个稀疏矩阵A和B,用十字链表实现A=A+B,输出它们相加的结果. 输入: 第一行输入四个正整数,各自是两个矩阵的行m.列n.第一个矩阵的非零元素的个数t1和第二个矩阵的非零元素的个数 ...

  7. javascript实现数据结构:稀疏矩阵的十字链表存储表示

    当矩阵的非零个数和位置在操作过程中变化大时,就不宜采用顺序存储结构来表示三元组的线性表.例如,在作“将矩阵B加到矩阵A上”的操作时,由于非零元的插入或删除将会引起A.data中元素的移动.为此,对这种 ...

  8. 数据结构之---C++语言实现图的十字链表存储表示

    近期一直忙着考研复习,非常久都没有更新博客了.今天写一篇数据结构的存储. //有向图的十字链表存储表示 //杨鑫 #include <iostream> #include <cstd ...

  9. 利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现

    #include <stdio.h> #include<conio.h> #include<stdlib.h> /* 利用十字链表存储有向图,可用于同时查找某个顶点 ...

随机推荐

  1. div水平居中且垂直居中

    <style> .vertical-center{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, ...

  2. CAN总线(一)

    原文出处:http://www.cnblogs.com/jacklu/p/4729638.html 嵌入式的工程师一般都知道CAN总线广泛应用到汽车中,其实船舰电子设备通信也广泛使用CAN,随着国家对 ...

  3. 利用jQuery内置的data()方法存储数据

    jQuery提供了内置的data()方法,与DOM元素不同的是,它可以用来存储key/value类型的数据.数据的存储是很容易的: $('#myDiv').data('currentState', ' ...

  4. java -json()

    json-lib和org.json的使用几乎是相同的,我总结出的区别有两点: 两种包 1. List集合转换成json方法 List list = new ArrayList(); list.add( ...

  5. python批量处理excel文件数据

    https://www.zhihu.com/question/39299070?sort=created 作者:水中柳影链接:https://www.zhihu.com/question/392990 ...

  6. php多条件搜索

    PHP多条件查询 December : Tuesdayby 小屋 在我们的网站设计过程中,经常会用到多条件查询,本文的源码是一个二手房屋查询的例子.在本例中,我们要实现能够通过地理位置,物业类型,房屋 ...

  7. iOS高效开发必备的10款Objective-C类库

    http://blog.csdn.net/yhawaii/article/details/7392988

  8. centos7安装数据库

    centos7的yum源中貌似没有正常安装MySQL时的mysql-server. 那么就需要从官网下载了. 下面是安装mysql的命令: # wget http://dev.mysql.com/ge ...

  9. js/jstl/el的区别

    JavaScript 学习的路径:http://www.w3school.com.cn/js/js_intro.asp 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服 ...

  10. ViewPager的简单使用

    1.布局文件 a.主布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xml ...