【问题标题】:Design data structure for simple greedy snake game during interview面试时设计简单贪吃蛇游戏的数据结构
【发布时间】:2015-12-09 08:39:09
【问题描述】:

这不是一个实际问题,我只是想在这里讨论和学习数据结构设计,我在现场面试时听说谷歌问过这个问题。请告诉我如何改进我的设计,谢谢!

一开始我想使用双端队列来存储蛇身体部位的 x,y 坐标对。

deque<pair<x, y>> snakeBodyParts;

因为蛇移动时很容易向前推 - 根据旧的头部位置和当前方向创建新的坐标对作为新的头部,然后弹回以移除尾巴。这样move,eat,check head hit wall都是O(1)操作,用deque很容易实现。但是检查新的头部位置是否与蛇的身体重叠将需要遍历所有身体部位的位置 - O(L) 时间复杂度,L 是身体部位的数量。

为了改进它,我考虑将所有坐标放入 unordered_set(C++) 或 hashset(Java) 中,同时仍然保留我的旧双端队列,它可以给我 O(1) 来检查头部是否撞到身体。但我不知道这是否是个好主意,因为它几乎使内存和代码量翻了一番,每当我添加/删除到双端队列时,我都需要对我的哈希集执行此操作。

unordered_set<pair<int, int>, pair_hash> bodyPartsSet;

我也想过创建自己的结构,类似于链表,只是它指向上一个节点:

SnakeBodyNode {
    int x;
    int y;
    SnakeBodyNode * prev;
}

那我还需要两个指向头部和尾部的指针以及一个方向变量。

SnakeBodyNode * head;
SnakeBodyNode * tail;
char dir;

但是我看不出这有什么好处,仍然需要散列来获得 O(1) 来检查头部是否撞到身体..

我的双端队列 + 哈希设计是否有任何缺陷,或者任何人有更好的想法可以分享?

【问题讨论】:

  • 上次写蛇游戏我只存储了两个坐标,头部的位置(将蛇的头部向前移动)和尾部的位置(通过删除它来向后移动蛇)。我通过蛇头移动到的单元格中的像素颜色检测到碰撞。虽然这是一个失败的有限设计。但是在8-bit micro 上非常
  • @Galik 因此,您通过存储整个棋盘的二维数组并标记单元格是否被蛇占据来保存蛇体的位置。检查蛇是否会撞到它的身体是O(1),我认为这是一个很好的设计,这种方式不需要使用哈希表,而且除非板子超级大,否则不会占用太多内存。
  • 您的网格有多大?我宁愿选择更简单的队列实现。即使线性搜索代价高昂,您也只需要遍历一个只有几百个节点的队列。
  • 它比这更原始,我没有存储 2D 板阵列,我在屏幕缓冲区中逐字测试像素颜色,确保没有其他游戏对象使用与蛇的身体相同的颜色. :)
  • @Galik 嗯...我真的不明白删除尾部是如何工作的,一旦你使用指向尾部的指针删除它,你如何更新尾部指针?

标签: java c++ data-structures


【解决方案1】:

我只会使用 unordered_set。您的担忧是:

  • 新磁头的快速插入 - 对于 unordered_set,这是 O(1)。
  • 快速删除现有尾部 - 对于 unordered_set,这是 O(1)。
  • 没有重复(检查头部是否与身体相交) - 这是有保证的 对于 unordered_set(它不允许重复)。

当插入一个新的头部时,你不需要做任何特别的事情来检查它是否与身体相交;如果是这样,你会得到一个错误。

【讨论】:

  • 只有 unordered_set,没有类似结构的链表?那么你如何跟踪tail,一旦你删除了一个tail,你如何找到下一个要删除的tail?
  • 噢!我要睡觉了 :) 带有指向前一个节点的想法的 unordered_set 可以工作,不是吗?
  • 是的,应该可以,只是想知道是否有更好的设计;)
猜你喜欢
  • 1970-01-01
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多