Python 循环数据结构有什么好处?

Python 循环数据结构有什么好处?,python,data-structures,recursion,cyclic-reference,Python,Data Structures,Recursion,Cyclic Reference,我正在通读: 它被确定为一个循环数据结构 >>> L = ['foo', 'bar'] >>> L.append(L) >>> L ['foo', 'bar', [...]] >>> L[0] 'foo' >>> L[1] 'bar' >>> L[2] ['foo', 'bar', [...]] >>> L[2].append('baz') >>> L

我正在通读:

它被确定为一个循环数据结构

>>> 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', [...]]
所以我想知道,我的问题是:

在现实编程中使用的“循环数据结构”是什么? 这里似乎有点混乱,我认为这源于非常简短的代码示例。。。这里还有几行使用相同的对象L


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


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

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

图结构通常是循环的;非循环性是一个特例。例如,考虑一个包含旅行推销员问题的所有城市和道路的图表。< /P>
好的,这里有一个特别的例子。我在科罗拉多州建立了一个城镇集合:

V=["Boulder", "Denver", "Colorado Springs", "Pueblo", "Limon"]
然后我建立了一对城市,在那里有一条道路将它们连接起来

E=[["Boulder", "Denver"],
   ["Denver", "Colorado Springs"],
   ["Colorado Springs", "Pueblo"],
   ["Denver", "Limon"],
   ["Colorado Springs", "Limon"]]
这有一系列的循环。例如,您可以从科罗拉多斯普林斯开车到利蒙,再到丹佛,再回到科罗拉多斯普林斯


如果您创建的数据结构包含V中的所有城市和E中的所有道路,则这是一个图形数据结构。此图将具有循环。

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

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

我最近创建了一个循环数据结构来表示八个基数和顺序方向。每个方向了解它的邻居都很有用。例如,方向。北方知道那个方向。东北和方向。西北是它的邻居

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

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

注意我们回到了北方

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

公共类方向
{
...
有两个邻居的公共数字
{
得到{
收益回报这一点;
收益率:逆时针返回该值;
按顺时针方向返回;
}
}
}
...
公共无效TryToMove(方向dir)
{
dir=dir.withtwooneights.Where(d=>CanMove(d)).First()
移动(dir);
}

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

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

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

v[end] = a;
end = (end+1) % N;
if (begin == end)
  begin = (begin+1) % N;
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)
您可以以类似的方式插入“旧”数据和删除“旧”或“新”数据。 扫描向量是这样的

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

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

v[end] = a;
end = (end+1) % N;
if (begin == end)
  begin = (begin+1) % N;
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.send("Hi, Bob!")

诚然,这是一个有点做作的例子,但它应该为您提供一个可能希望使用循环数据结构的示例。

任何一种对象层次结构,其中父母了解他们的孩子,孩子了解他们的父母。我总是不得不在ORMs中处理这个问题,因为我想让数据库知道它们的表,让数据库知道它们是哪个数据库的一部分,等等。

这有点让人困惑,因为它是一个包含自身的列表,但我理解它的方式是不把L看作一个列表,而是一个节点,而不是列表中的东西,您可以将其视为该节点可以访问的其他节点

>>> 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', [...]]
举一个更真实的例子,把它们想象成一个城市的飞行路线

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

然后是丹佛=[凤凰城,费城]等等

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

现在您有了来自两个站点的循环数据

芝加哥->芝加哥

而且

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

现在你有:

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

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', [...]]

迭代的数据结构通常是循环的。

让我们看一个实际的例子

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

  • 条目的名称
  • 按下后,我们将进入另一个菜单
  • 按下菜单时将执行的操作
  • 当按下菜单项时,我们将激活菜单项操作,然后进入下一个菜单。因此,我们的菜单将是一个简单的dic列表
    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}
        ]
    
    def menu_item_pressed(item):
        item['action']()
        if (item['menu'] == SelfReferenceMarker):
            set_next_menu(get_previous_menu())
        else:
            set_next_menu(item['menu'])