哪种数据结构可以像循环队列一样工作?
Which data structure can act like a circular queue?
上图有 25 个动作点,因此:
- 三层中每一层的四个角各为一个动作点。
- 每层四边的中段为一个动作点
- 垂直线和水平线的交点是一个动作点。
相邻的动作点是由一条线连接并且没有被任何其他动作点分开的任意两个动作点。
动作点的状态可以是1、-1或0。
我需要一个数据结构,或任意数量的数据结构的组合,以有效完成以下任务:
- 存储所有动作点的状态。
- 我应该能够快速交换任意两个相邻动作点的状态。
- 我应该能够快速改变任何动作点的状态。
哪个数据结构可以帮我完成这个?我认为我需要某种循环队列的列表,但我不确定。
有两种主要情况:行动点 (AP) 模式可能会改变/增长,或者不能。
Growable/modifiable 模式
我会使用一个简单的数组来存储每个 AP,一个 AP 被存储为一个包含的结构,对于 each 索引:
- 州,
- 它在模式中的坐标(此处为
-3 ≤ x ≤ 3
和-3 ≤ y ≤ 3
,根据需要进行调整但保持为整数),
- 相邻AP的列表(一个简单的向量,包含这些相邻AP数组中的索引,最好按索引排序)。
数组排序后array[i]<array[j] ⟺ (array[i].x<array[j].x) || ((array[i].x=array[j].x) && (array[i].y<array[j].y))
。因此,从其坐标在数组中找到一个 AP 是在 O(log2(n))
.
中完成的
对于相邻的 AP,如果你保证没有 AP 可以有超过 4 个相邻的 AP,那么你可以通过将其固定为 4 个元素的数组来优化列表,组织为当前 AP 周围的基点(例如:0=North, 1=East, 2=South, 3=West),如果在这个方向上没有相邻的AP,则将“-1”作为索引。否则,使用动态列表。
然后,一旦找到动作点,就可以使用相邻AP列表来检查哪些确实相邻,如果需要检查特定AP是否与另一个AP相邻,再次在[=中完成13=] 如果相邻 AP 列表已排序,或者甚至在 O(1)
中,如果仅限于基本方向并且在搜索此相邻 AP 时方向已知。
这应该足够快,即使您将模式增长到巨大的东西,例如 9999x9999 矩阵,同时不会使用太多内存,因为实际上只存储了现有的 AP。
固定模式
对于如此小的图案,数组可以替换为 7x7 矩阵 - 因此,无需在 AP 结构中存储坐标。然而,相邻的 AP 列表仍然是必需的,但是你需要使用上面的带有基本方向的版本,它只需要一个布尔值(true
=adjacent AP is here, in this direction)。您只需要 add/substract 1 到当前 x
或 y
即可找到相邻的 AP 结构。
你还需要存储NULL
个AP结构,或者用一个特殊的状态值来表示这里没有有效的AP。这确实是内存的“浪费”,但让我们面对现实:您“仅”使用两倍的内存,即 49 个结构,而不是 25 个 - 因此 24 个结构设置为“无效”。没什么大不了的......显然,9999x9999 矩阵和“只有”100,000 个 AP 是不一样的,但在这里浪费内存是值得的。
例如,在此矩阵中,(1,2) 处的结构不是有效的 AP - 而 (1,1) 和 (2,2) 是有效的 AP。当然,中心AP的坐标是(0,0),而外角在这个矩阵中是(±3,±3)。
由于语言限制,您可能需要不断地 add/substract 3 到所有坐标,以保持它们为正或为空(例如,C 和 C++ 需要这样的调整)。
用法
这两种方法都可以快速找到任何可能的 AP 及其相邻 AP,复杂度从 O(1)
到 O(log2(n))
。然后,执行请求的操作现在是微不足道的,并且在 O(1)
.
中完成
在图中表示动作状态所需的基本数据结构是一个简单的 int[25]
。
- Store the states of all action sites.
要存储其中一个网格的状态,您只需要一个包含 25 个整数的数组来保存每个动作点的 -1 或 0 或 +1 值。
- I should be able to quickly swap the states of any two adjacent action points.
交换两个数组元素中的值是 3 个赋值。
- I should be able to quickly change state of any action point.
这是一个单一的任务。
您可以轻松地将数组包装在自定义 class 中,并使用方法来执行 2. 和 3.动作要点。 (这些不需要编码为数据结构......假设它们按照规定的要求是不变的/不可改变的。)
您需要做出的一个设计决定是状态集应该是可变的还是不可变的。
以上假设所有状态集都有3层/25个动作状态。如果层数是可变的,您可以使用相同的方法......使用具有不同数量的插槽的数组来保存状态。
以上处理的是单个状态集。如果您有多个状态集表示一系列(游戏?)状态,那么您可以将它们表示为状态快照的 List
或 Stack
或其他内容,具体取决于您的应用程序更大规模的要求。
不幸的是,您的问题中没有关于那些更大规模要求是什么的真正线索。 (我在想象某种游戏,其中 -1、0 和 +1 代表玩家棋子的存在或不存在。但我可能完全错了。根据对问题的猜测提出建议是 (IMO) 毫无意义的。)
您似乎希望事情变得“快”。对此我有两件事要对你说:
您的问题中没有足够的信息来提供快速的解决方案。问题是我们不了解这些数据结构将如何使用。 “它们将如何使用”将决定...各种操作所需的性能特征。
提防过早优化。让代码“尽可能快”并不是一个明智的设计目标。使其尽可能快需要...并且不要浪费时间和精力使其更快。
当您进行初始设计和实施工作时,您通常无法预测相对于您的性能目标而言它的速度有多快。在此阶段进行优化(通常)是错误的,因为:
- 您根本不知道是否需要任何优化,并且
- 您不知道(也无法可靠地预测)设计/实现的哪些部分会出现性能瓶颈。
我的建议是在尝试让它变得更快之前,先专注于获得有用的东西。
上图有 25 个动作点,因此:
- 三层中每一层的四个角各为一个动作点。
- 每层四边的中段为一个动作点
- 垂直线和水平线的交点是一个动作点。
相邻的动作点是由一条线连接并且没有被任何其他动作点分开的任意两个动作点。
动作点的状态可以是1、-1或0。
我需要一个数据结构,或任意数量的数据结构的组合,以有效完成以下任务:
- 存储所有动作点的状态。
- 我应该能够快速交换任意两个相邻动作点的状态。
- 我应该能够快速改变任何动作点的状态。
哪个数据结构可以帮我完成这个?我认为我需要某种循环队列的列表,但我不确定。
有两种主要情况:行动点 (AP) 模式可能会改变/增长,或者不能。
Growable/modifiable 模式
我会使用一个简单的数组来存储每个 AP,一个 AP 被存储为一个包含的结构,对于 each 索引:
- 州,
- 它在模式中的坐标(此处为
-3 ≤ x ≤ 3
和-3 ≤ y ≤ 3
,根据需要进行调整但保持为整数), - 相邻AP的列表(一个简单的向量,包含这些相邻AP数组中的索引,最好按索引排序)。
数组排序后array[i]<array[j] ⟺ (array[i].x<array[j].x) || ((array[i].x=array[j].x) && (array[i].y<array[j].y))
。因此,从其坐标在数组中找到一个 AP 是在 O(log2(n))
.
对于相邻的 AP,如果你保证没有 AP 可以有超过 4 个相邻的 AP,那么你可以通过将其固定为 4 个元素的数组来优化列表,组织为当前 AP 周围的基点(例如:0=North, 1=East, 2=South, 3=West),如果在这个方向上没有相邻的AP,则将“-1”作为索引。否则,使用动态列表。
然后,一旦找到动作点,就可以使用相邻AP列表来检查哪些确实相邻,如果需要检查特定AP是否与另一个AP相邻,再次在[=中完成13=] 如果相邻 AP 列表已排序,或者甚至在 O(1)
中,如果仅限于基本方向并且在搜索此相邻 AP 时方向已知。
这应该足够快,即使您将模式增长到巨大的东西,例如 9999x9999 矩阵,同时不会使用太多内存,因为实际上只存储了现有的 AP。
固定模式
对于如此小的图案,数组可以替换为 7x7 矩阵 - 因此,无需在 AP 结构中存储坐标。然而,相邻的 AP 列表仍然是必需的,但是你需要使用上面的带有基本方向的版本,它只需要一个布尔值(true
=adjacent AP is here, in this direction)。您只需要 add/substract 1 到当前 x
或 y
即可找到相邻的 AP 结构。
你还需要存储NULL
个AP结构,或者用一个特殊的状态值来表示这里没有有效的AP。这确实是内存的“浪费”,但让我们面对现实:您“仅”使用两倍的内存,即 49 个结构,而不是 25 个 - 因此 24 个结构设置为“无效”。没什么大不了的......显然,9999x9999 矩阵和“只有”100,000 个 AP 是不一样的,但在这里浪费内存是值得的。
例如,在此矩阵中,(1,2) 处的结构不是有效的 AP - 而 (1,1) 和 (2,2) 是有效的 AP。当然,中心AP的坐标是(0,0),而外角在这个矩阵中是(±3,±3)。
由于语言限制,您可能需要不断地 add/substract 3 到所有坐标,以保持它们为正或为空(例如,C 和 C++ 需要这样的调整)。
用法
这两种方法都可以快速找到任何可能的 AP 及其相邻 AP,复杂度从 O(1)
到 O(log2(n))
。然后,执行请求的操作现在是微不足道的,并且在 O(1)
.
在图中表示动作状态所需的基本数据结构是一个简单的 int[25]
。
- Store the states of all action sites.
要存储其中一个网格的状态,您只需要一个包含 25 个整数的数组来保存每个动作点的 -1 或 0 或 +1 值。
- I should be able to quickly swap the states of any two adjacent action points.
交换两个数组元素中的值是 3 个赋值。
- I should be able to quickly change state of any action point.
这是一个单一的任务。
您可以轻松地将数组包装在自定义 class 中,并使用方法来执行 2. 和 3.动作要点。 (这些不需要编码为数据结构......假设它们按照规定的要求是不变的/不可改变的。)
您需要做出的一个设计决定是状态集应该是可变的还是不可变的。
以上假设所有状态集都有3层/25个动作状态。如果层数是可变的,您可以使用相同的方法......使用具有不同数量的插槽的数组来保存状态。
以上处理的是单个状态集。如果您有多个状态集表示一系列(游戏?)状态,那么您可以将它们表示为状态快照的 List
或 Stack
或其他内容,具体取决于您的应用程序更大规模的要求。
不幸的是,您的问题中没有关于那些更大规模要求是什么的真正线索。 (我在想象某种游戏,其中 -1、0 和 +1 代表玩家棋子的存在或不存在。但我可能完全错了。根据对问题的猜测提出建议是 (IMO) 毫无意义的。)
您似乎希望事情变得“快”。对此我有两件事要对你说:
您的问题中没有足够的信息来提供快速的解决方案。问题是我们不了解这些数据结构将如何使用。 “它们将如何使用”将决定...各种操作所需的性能特征。
提防过早优化。让代码“尽可能快”并不是一个明智的设计目标。使其尽可能快需要...并且不要浪费时间和精力使其更快。
当您进行初始设计和实施工作时,您通常无法预测相对于您的性能目标而言它的速度有多快。在此阶段进行优化(通常)是错误的,因为:
- 您根本不知道是否需要任何优化,并且
- 您不知道(也无法可靠地预测)设计/实现的哪些部分会出现性能瓶颈。
我的建议是在尝试让它变得更快之前,先专注于获得有用的东西。