为了方便后期的热更新需求,项目基本上全部逻辑都使用了纯lua实现,最近遇到一个大地图寻路的算法问题,有两百多个城市的拓扑结构图,寻找最短路径,算法本身没有什么好讲的,A*的广度优先算法,但在lua层照搬A*的实现逻辑,会有极大的性能压力,要求算法本身做些有利于脚本的优化。

优化思路如下:
1.A*需要开放节点列表,关闭节点列表,涉及大量的链表操作,在lua里从表结构里删除和向表结构里添加节点都是非常耗费性能的操作,基本思路是用一个表结构来同时实现开放节点列表和关闭节点列表。local searchNodes = {}
searchNodes[Node2] = 权重  --开放节点
searchNodes[Node3] = false --关闭节点 2.A*查找最优子节点时,需要遍历开放节点列表,选取当前最优扩展节点,通常采取的做法是对开放节点列表做一次排序(也有算法在插入时维护开放节点的有序性),选取最优节点。但对lua而言,排序是很耗性能的操作,并切要求必须维持开放节点列表是一个数组,这样不管删除和插入都会导致数组的后续元素更新,所以采用筛取法来获取最优节点。local function onSearchGood()local cNode = nillocal cStep = 10000000000for cityId,cityStep in pairs(searchNodes) doif cityStep and cStep > cityStep thencNode = cityIdcStep = cityStependendif cNode thensearchNodes[cNode] = falseendreturn cNode
end3.路径缓存,根据以上两步基本能处理节点扩展的问题,剩下的就是当前路径的缓存问题,c++的常规实现是通过一个链表实现,让当前节点指向其父节点,就可以反向根据某个节点推导出其从开始节点到当前节点的路径。最近在参照别的算法实现时,发现一个在脚本中非常巧妙的实现方式,就是用一个字符串巧妙地实现路径缓存的问题。local searchPathes = {}
searchPathes[child] = searchPathes[parent]..">"..child这样通过查找这个searchPathes就可以方便地知道当前节点来源路径 n1>n2>n3... ,通过字符串的分割,就可以获得整个完整的路径。

– 寻找最短路径

function WorldUtils.findPath2(startId,endId)if not startId or not endId thenreturnendlocal path = {}local pathInfo = {}local openPoints = {}local curNation = xxx --当前阵营local cityListInfo = xxx -- 城市附属数据path[startId] = 0pathInfo[startId] = startIdlocal function onSearchNode2(start)if not start thenreturnendlocal cityInfo = _cc_config:getMapCityById(start) --城市联通数据local childs = cityInfo.connect_city -- childsfor _,child in ipairs(childs) dolocal childId = child[1]if childId == endId thenopenPoints = {}pathInfo[childId] = pathInfo[start].." "..childIdreturnendlocal currCityInfo = cityListInfo:getCityBaseInfo(childId)if currCityInfo thenif curNation == currCityInfo.nation thenlocal distance = 1if currCityInfo.state == 2 thendistance = 1000endlocal oldStep = path[childId]local newStep = path[start] + distance -- 之前设置的距离大于新计算出来的距离if not oldStep or oldStep > newStep  thenoldStep = newSteppath[childId] = newSteppathInfo[childId] = pathInfo[start].." "..childIdend if false ~= openPoints[childId] thenopenPoints[childId] = oldStependendendend end local function onSearchGood()  --最优节点local cNode = nillocal cStep = 10000000000for cityId,cityStep in pairs(openPoints) doif cityStep and cStep > cityStep thencNode = cityIdcStep = cityStependendif cNode thenopenPoints[cNode] = falseendreturn cNodeendlocal function onSearchNereast(start)  --扩展节点openPoints[start] = 0while true dolocal city = onSearchGood()if not city thenbreakelseonSearchNode2(city)endendend--local currTime = socket.gettime()onSearchNereast(startId)--dump(socket.gettime() - currTime)if pathInfo[endId] thenreturn string.split(pathInfo[endId]," ")end return nil
end

纯lua脚本搜索算法优化相关推荐

  1. Redis中使用Lua脚本(续)- Linux下Lua-cjson开源库的安装和使用

    Redis中使用Lua脚本(续)- Lua-cjson开源库的安装和使用 问题 原因 解决方案 在Redis的lua脚本编写中,我们可能会用到json的序列化和反序列化. Json序列化: -- Re ...

  2. redis+lua脚本

    1.lua+java 第一种形式直接在代码中 @Autowiredprivate RedisTemplate<String,String> redisTemplate;@PostMappi ...

  3. 基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性

    为了保证数据的争用安全,通常要采用锁机制控制. 如果是单应用部署,直接通过synchronized关键字修改方法,就能解决,但是如果是分布式的部署 该方法就不能解决这个问题啦,此时就引出了一个分布式锁 ...

  4. Redis 中 Lua 脚本的应用和实践

    引言 前段时间组内有个投票的产品,上线前考虑欠缺,导致被刷票严重.后来,通过研究,发现可以通过 redis lua 脚本实现限流,这里将 redis lua 脚本相关的知识分享出来,讲的不到位的地方还 ...

  5. Spring Redis中使用Lua脚本实现高并发原子操作

    1. 前言 在上一文中我对 Lua 语言的一些简单的语法及其在 Redis 中的操作进行了介绍,但是在 Java 开发中我们还需要进一步的学习才能使这种技术落地.今天就结合Spring Data Re ...

  6. 插件使用之加载自定义lua脚本

    为什么80%的码农都做不了架构师?>>>    xmake里面的lua脚本加载插件,可以让你方便调试和编写一些自定义的lua脚本,这个时候xmake就是一个纯lua的加载引擎.. 例 ...

  7. lua脚本在redis集群中执行报错--Lua script attempted to access a non local key in a cluster node...

    EVAL.EVALSHA命令 Redis从2.6.0版本开始提供了eval命令,通过内置的Lua解释器,可以让用户执行一段Lua脚本并返回数据.因为Redis单线程模型的特点,可以保证多个命令的原子性 ...

  8. Redis分布式锁—SETNX+Lua脚本实现篇

    前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...

  9. Redis:18---常用功能之(Lua脚本)

    为了保证多条命令组合的原子性,Redis提供了简单的事务功能以及集成Lua脚本来解决这个问题,本文介绍Lua,事务已经在前一篇文章介绍过了 一.Lua概述 Lua语言是在1993年由巴西一个大学研究小 ...

最新文章

  1. libuvc介绍及简单使用
  2. Android中TimePicker时间选择器的使用和获取选择的时和分
  3. gRPC客户端创建和调用原理解析
  4. a b*c的C语言表达式为,在C语言的if语句中,用作判断的表达式为 ______
  5. Vue — 第四天(components组件)
  6. Web项目练习总结(错误校正篇)
  7. SQLite CodeFirst、Migration 的趟坑过程 [附源码]
  8. 服务器ip算是虚拟资产吗,云服务器算资产吗
  9. python 京东签到在哪里_python 使用selenium登陆京东签到哪京豆
  10. 关系抽取---(二)卷积神经网络
  11. Learn RxJava
  12. 查看电脑的s/n序列号信息方式
  13. macOS IKPictureTaker 图片选择器
  14. 青县计算机学校,青县将建设新学校(中小学各一所)今年3月开工,明年即可完工!...
  15. KB、kb和MB、mb有什么区别
  16. [跑步] 跑步者的力量训练
  17. 工业界和学术界最大区别是什么?
  18. 2019年 支付宝集福攻略
  19. web课程设计网页规划与设计:个人毕设网站设计 —— 二手书籍(11个页面) HTML+CSS+JavaScript
  20. 如何获取sha1值和MD5值

热门文章

  1. C Primer Plus学习 十四 使用snitch进行多重选择
  2. 【Java 8 新特性】Java Comparator | 比较器
  3. 【Java 8 新特性】Java Comparator.nullsFirst | 将空元素被认为小于非空元素
  4. clock_nanosleep()
  5. 谷歌联手印度首富开发智能手机 小米Ov受威胁?
  6. Go构建项目的时候,解决missing go.sum entry for module providing package <package_name>
  7. 红光光浴每天照,健康美丽两不误。
  8. 使用Node.JS进行谷歌地图定位
  9. C 语言:#endif 指令
  10. AOP学习之一 -- CGLIB使用介绍