循环数据结构有啥用?

Posted

技术标签:

【中文标题】循环数据结构有啥用?【英文标题】:What is a cyclic data structure good for?循环数据结构有什么用? 【发布时间】:2010-09-29 03:57:42 【问题描述】:

我只是在阅读"Learning Python" by Mark Lutz and came across this code sample:


>>> L = ['grail']
>>> L.append(L)
>>> L
['grail', [...]]

它被识别为循环数据结构。

所以我想知道,这是我的问题:

什么是在现实生活中的编程中使用的“循环数据结构”?

似乎有点混乱,我认为这源于非常简短的代码示例......这里还有几行使用相同的对象 L


>>> L[0]
'grail'
>>> L[1][0]
'grail'
>>> L[1][1][0]
'grail'

【问题讨论】:

呃,我不确定,因为我在现实生活中根本没有使用过它们,但它可以用来模拟嵌套数据结构吗?见this链接 我不认为这是“循环的”,我认为这是“递归的”。很多答案似乎都是关于循环结构而没有真正阅读问题。 这本书的正下方说“除非你真的需要,否则不要使用循环引用。创建循环有充分的理由,但除非你有知道如何处理它们的代码,否则你可能不想让你的对象在实践中经常引用自己。” @endolith,如果你构建一个如图所示的集合图,那么该图将有一个循环。因此,根据定义,它是循环的。事实上,它也是一种递归数据结构。 【参考方案1】:

一个例子是最后一项指向第一项的链表。这将允许您创建固定数量的项目,但始终能够获得下一个项目。

【讨论】:

['grail', [...]] 不是循环缓冲区 问题是循环数据结构可以用于现实生活中的编程。它们不能用于循环缓冲区吗?【参考方案2】:

很多东西。循环缓冲区,例如:您有一些前后数据集合,但节点的数量是任意的,最后的“下一个”项目应该带您回到第一个。

图结构通常是循环的;非周期性是一种特殊情况。例如,考虑一个包含旅行商问题中所有城市和道路的图。


好的,这是给您的一个特殊示例。我在科罗拉多州建立了一系列城镇:

V=["Boulder", "Denver", "Colorado Springs", "Pueblo", "Limon"]

然后,我设置了成对的城市,它们之间有一条公路连接。

E=[["Boulder", "Denver"],
   ["Denver", "Colorado Springs"],
   ["Colorado Springs", "Pueblo"],
   ["Denver", "Limon"],
   ["Colorado Springs", "Limon"]]

这有一堆循环。例如,您可以从科罗拉多斯普林斯驾车前往利蒙、丹佛,然后再返回科罗拉多斯普林斯。

如果您创建一个包含 V 中的所有城市和 E 中的所有道路的数据结构,这就是 graph 数据结构。这个图会有循环。

【讨论】:

问题中描述的东西不是循环缓冲区。它是一个递归地包含自身的列表。 但是循环缓冲区是循环数据结构。 循环数据结构具有通过指针或引用形成循环的元素。它们通常需要垃圾收集或强/弱指针来正确维护所有权。尽管图可以形成概念循环,但邻接矩阵或列表的常见实现不是技术上循环(与基于节点的变体相反)。任何合理的循环缓冲区实现都是带有头尾索引的平面数组,根本不是循环的。【参考方案3】:

在进行晶格模拟时,经常使用循环/环形边界条件。通常一个简单的lattice[i%L] 就足够了,但我想可以创建循环的晶格。

【讨论】:

【参考方案4】:

可以在垃圾收集器的测试用例中使用嵌套结构。

【讨论】:

【参考方案5】:

我最近创建了一个循环数据结构来表示八个基数和序数方向。它对每个方向了解其邻居很有用。例如,Direction.North 知道 Direction.NorthEast 和 Direction.NorthWest 是它的邻居。

这是循环的,因为每个邻居都知道它的邻居,直到它完全旋转(“->”代表顺时针):

北 -> 东北 -> 东 -> 东南 -> 南 -> 西南 -> 西 -> 西北 -> 北 -> ...

注意我们回到了北方。

这让我可以做这样的事情(在 C# 中):

public class Direction

    ...
    public IEnumerable<Direction> WithTwoNeighbors
    
        get 
           yield return this;
           yield return this.CounterClockwise;
           yield return this.Clockwise;
        
    

...
public void TryToMove (Direction dir)

    dir = dir.WithTwoNeighbors.Where (d => CanMove (d)).First ()
    Move (dir);

事实证明这非常方便,并且使很多事情变得不那么复杂。

【讨论】:

这不是问题所在。它询问包含自身的对象。【参考方案6】:

假设您的存储空间有限,并且数据不断累积。在许多现实生活中,您不介意删除旧数据,但您不想移动数据。您可以使用循环向量;使用大小为 N 的向量 v 实现,该向量具有两个特殊索引:开始和结束,从 0 开始。

“新”数据的插入现在如下所示:

v[end] = a;
end = (end+1) % N;
if (begin == end)
  begin = (begin+1) % N;

您可以以类似的方式插入“旧”数据并删除“旧”或“新”数据。 扫描向量是这样的

for (i=begin; i != end; i = (i+1) % N) 
 // do stuff

【讨论】:

这不是他所问的循环;它不包含(引用)自身。 认为就问题而言,这是一个可以接受的数据结构,但这是一个很难理解的例子。【参考方案7】:

循环数据结构通常用于表示循环关系。这听起来很明显,但它发生的次数比你想象的要多。我想不出任何时候我使用过非常复杂的循环数据结构,但双向关系相当普遍。例如,假设我想做一个 IM 客户端。我可以这样做:

class Client(object):
    def set_remote(self, remote_client):
        self.remote_client = remote_client

    def send(self, msg):
        self.remote_client.receive(msg)

    def receive(self, msg):
        print msg

Jill = Client()
Bob = Client()
Bob.set_remote(Jill)    
Jill.set_remote(Bob)

如果 Bob 想给 Jill 发送消息,你可以这样做:

Bob.send("Hi, Jill!")

当然,Jill 可能想发回一条消息,所以她可以这样做:

Jill.send("Hi, Bob!")

诚然,这是一个人为的例子,但它应该为您提供一个示例,说明何时可能需要使用循环数据结构。

【讨论】:

【参考方案8】:

父母了解他们的孩子,孩子了解他们的父母的任何类型的对象层次结构。我总是不得不在 ORM 中处理这个问题,因为我希望数据库知道它们的表和表以知道它们是哪个数据库的一部分,等等。

【讨论】:

【参考方案9】:

这有点令人困惑,因为它是一个包含自身的列表,但我理解它的方式是不要将 L 视为一个列表,而是一个节点,而不是列表中的事物,你会想到它作为该节点可访问的其他节点。

举一个更真实的例子,把它们想象成一个城市的飞行路径。

所以芝加哥 = [丹佛,洛杉矶,纽约市,芝加哥](实际上你不会列出芝加哥本身,但为了举例,你可以从芝加哥到达芝加哥)

然后你有 denver = [phoenix, philedelphia] 等等。

凤凰 = [芝加哥,纽约市]

现在你有来自

的循环数据

芝加哥 -> 芝加哥

还有

芝加哥 -> 丹佛 -> 凤凰城 -> 芝加哥

现在你有:

chicago[0] == denver
chicago[0][0] == phoenix
chicago[0][0][0] == chicago

【讨论】:

【参考方案10】:

L 仅包含对其自身的引用作为其元素之一。这没什么特别的。

循环结构有一些明显的用途,其中最后一个元素知道第一个元素。但是这个功能已经被常规的 python 列表覆盖了。

您可以使用[-1] 获取L 的最后一个元素。您可以将 python 列表用作带有append()pop() 的队列。您可以拆分 python 列表。以下是循环数据结构的常规用法。

>>> L = ['foo', 'bar']
>>> L.append(L)
>>> L
['foo', 'bar', [...]]
>>> L[0]
'foo'
>>> L[1]
'bar'
>>> L[2]
['foo', 'bar', [...]]
>>> L[2].append('baz')
>>> L
['foo', 'bar', [...], 'baz']
>>> L[2]
['foo', 'bar', [...], 'baz']
>>> L[2].pop()
'baz'
>>> L
['foo', 'bar', [...]]
>>> L[2]
['foo', 'bar', [...]]

【讨论】:

【参考方案11】:

deterministic finite automata 迭代的数据结构往往是循环的。

【讨论】:

【参考方案12】:

让我们看一个实际的例子。

假设我们正在为游戏编写菜单导航。我们要为每个菜单项存储

    条目的名称 按下后我们将到达的另一个菜单。 按下菜单时将执行的操作。

当一个菜单项被按下时,我们将激活菜单项动作,然后移动到下一个菜单。所以我们的菜单将是一个简单的字典列表,如下所示:

options,start_menu,about = [],[],[]

def do_nothing(): pass

about += [
    'name':"copyright by...",'action':None,'menu':about,
    'name':"back",'action':do_nothing,'menu':start_menu
    ]
options += [
    'name':"volume up",'action':volumeUp,'menu':options,
    'name':"save",'action':save,'menu':start_menu,
    'name':"back without save",'action':do_nothing,'menu':start_menu
    ]
start_menu += [
    'name':"Exit",'action':f,'menu':None, # no next menu since we quite
    'name':"Options",'action':do_nothing,'menu':options,
    'name':"About",'action':do_nothing,'menu':about
    ]

看看about是如何循环的:

>>> print about
['action': None, 'menu': [...], 'name': 'copyright by...',#etc.
# see the ellipsis (...)

当一个菜单项被按下时,我们将发出以下点击功能:

def menu_item_pressed(item):
    log("menu item '%s' pressed" % item['name'])
    item['action']()
    set_next_menu(item['menu'])

现在,如果我们没有循环数据结构,我们将无法拥有指向自身的菜单项,例如,在按下音量增大功能后,我们将不得不离开选项菜单。

如果循环数据结构不可能,我们必须自己实现它,例如菜单项是:

class SelfReferenceMarkerClass: pass
#singleton global marker for self reference
SelfReferenceMarker = SelfReferenceMarkerClass()
about += [
    'name':"copyright by...",'action':None,'menu':srm,
    'name':"back",'action':do_nothing,'menu':start_menu
    ]

menu_item_pressed 函数是:

def menu_item_pressed(item):
    item['action']()
    if (item['menu'] == SelfReferenceMarker):
        set_next_menu(get_previous_menu())
    else:
        set_next_menu(item['menu'])

第一个例子稍微好一点,但是是的,恕我直言,不支持自我引用并不是什么大不了的事,因为很容易克服这个限制。

菜单示例就像一个带有自引用的图,我们通过顶点指针列表存储图(每个顶点都是指向其他顶点的指针列表)。在这个例子中,我们需要自边(一个指向自身的顶点),因此 python 对循环数据结构的支持很有用。

【讨论】:

以上是关于循环数据结构有啥用?的主要内容,如果未能解决你的问题,请参考以下文章

spring中的依赖注入有啥用?

python with语句有啥用

JavaScript continue语句有啥用?

将 null 定义为数据类型有啥用?

PostgreSQL 中 JSONB[] (JSONB ARRAY) 数据类型有啥用?

python数据可视化有啥用