Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python heapq如何解析相等值?_Python_Priority Queue_Heapq - Fatal编程技术网

Python heapq如何解析相等值?

Python heapq如何解析相等值?,python,priority-queue,heapq,Python,Priority Queue,Heapq,来自Java,我试图用python实现,但在对图中具有相等f分数的顶点进行排序时遇到了问题。我正试图使用heapq来实现这一点,经过一些调试后,我注意到如果我想要推送一个顶点,该顶点的f值等于堆中其他一些预先存在的顶点,那么顺序就会混乱。我现在正在考虑实现自己的优先级队列。我想知道这是怎么回事 这种行为的一个例子如下: >>> mylist = [1, 2, 5, 4, 3] >>> heapq.heapify(mylist) >>> myl

来自Java,我试图用python实现,但在对图中具有相等f分数的顶点进行排序时遇到了问题。我正试图使用heapq来实现这一点,经过一些调试后,我注意到如果我想要推送一个顶点,该顶点的f值等于堆中其他一些预先存在的顶点,那么顺序就会混乱。我现在正在考虑实现自己的优先级队列。我想知道这是怎么回事

这种行为的一个例子如下:

>>> mylist = [1, 2, 5, 4, 3]
>>> heapq.heapify(mylist)
>>> mylist
>>> [1, 2, 3, 4, 5]
>>> heapq.heappush(mylist, 1)
>>> mylist
>>> [1, 2, 1, 4, 5, 3]
下面是我为上下文实现的实际代码:

class Node(object):

def __init__(self, name, x_coordinate, y_coordinate, obstacle_flag=False):
    self.name = name  # possible values should only be ' ', 'A-Z', '*'
    self.coordinates = (x_coordinate, y_coordinate)  # this will uniquely identify the node
    self.obstacle = obstacle_flag  # if the name is '*' the obstacle is set to True
    self.neighbors = {}  # list of neighbors of this node
    self.set_obstacle()

...

class Vertex(Node):
def __init__(self, name, x_coordinate, y_coordinate, obstacle_flag):
    super(Vertex, self).__init__(name, x_coordinate, y_coordinate, obstacle_flag)
    self.g_actual_cost = 10000  
    self.h_cost = 0  # the cost given by the heuristic function
    self.previous_vertex = None
    self.total_cost = self.g_actual_cost + self.h_cost

def __lt__(self, other):
    return self.total_cost < other.total_cost

def __eq__(self, other):
    if isinstance(other, Vertex):
        return self.total_cost == other.total_cost
    return NotImplemented

秩序没有混乱。对于所有索引,堆应具有:

a[i] <= a[2*i + 1]
a[i] <= a[2*i + 2]

秩序没有混乱。对于所有索引,堆应具有:

a[i] <= a[2*i + 1]
a[i] <= a[2*i + 2]

Heap并不意味着排序,如果排序了,就不能及时为任意值构建它。这意味着它满足堆不变量,对于像Python这样的最小堆,这只意味着如果出现平局,最小值位于顶部,任意值获胜,并且每个节点的子节点总是等于或大于该节点。通过查看索引2*i+1和2*i+2,您可以找到索引i处节点的子节点,因此在您的示例中,将P放在每个父节点下,将C放在每个子节点下,我们得到:

[1, 2, 1, 4, 5, 3]
#P  C  C
#0  1  2

[1, 2, 1, 4, 5, 3]
#   P     C  C
#   1     3  4

[1, 2, 1, 4, 5, 3]
#      P        C
#      2        5  (only one child since heap lacks another element)
如您所见,在每种情况下,p值都小于或等于其所有子项;保持堆不变量,这是heappop、heappush等继续工作所必需的

请注意,对于像Vertex类这样的对象,比较基于一个值,但对象具有其他状态,堆是不稳定的;具有相同总成本的两个对象可以按任意顺序出现,而不管哪个对象先放在堆中。为了避免这个问题,您必须通过修饰每个值来添加您自己的回退比较。一个简单的方法是:

 from itertools import count

 original_list = [Vertex(...), Vertex(...), ...]  # Define initial list of vertices
 numbermaker = count()
 decorated_list = [(v, next(numbermaker)) for v in original_list]
 heapq.heapify(decorated_list)

 # When you want to add new elements:
 heapq.heappush(decorated_list, (Vertex(...), next(numbermaker)))

 # When you want to get the top of the heap's value:
 top = decorated_list[0][0]  # First [0] gets decorated top, second strips decoration

 # When you want to pop off the top:
 top = heapq.heappop(decorated_list)[0]

Heap并不意味着排序,如果排序了,就不能及时为任意值构建它。这意味着它满足堆不变量,对于像Python这样的最小堆,这只意味着如果出现平局,最小值位于顶部,任意值获胜,并且每个节点的子节点总是等于或大于该节点。通过查看索引2*i+1和2*i+2,您可以找到索引i处节点的子节点,因此在您的示例中,将P放在每个父节点下,将C放在每个子节点下,我们得到:

[1, 2, 1, 4, 5, 3]
#P  C  C
#0  1  2

[1, 2, 1, 4, 5, 3]
#   P     C  C
#   1     3  4

[1, 2, 1, 4, 5, 3]
#      P        C
#      2        5  (only one child since heap lacks another element)
如您所见,在每种情况下,p值都小于或等于其所有子项;保持堆不变量,这是heappop、heappush等继续工作所必需的

请注意,对于像Vertex类这样的对象,比较基于一个值,但对象具有其他状态,堆是不稳定的;具有相同总成本的两个对象可以按任意顺序出现,而不管哪个对象先放在堆中。为了避免这个问题,您必须通过修饰每个值来添加您自己的回退比较。一个简单的方法是:

 from itertools import count

 original_list = [Vertex(...), Vertex(...), ...]  # Define initial list of vertices
 numbermaker = count()
 decorated_list = [(v, next(numbermaker)) for v in original_list]
 heapq.heapify(decorated_list)

 # When you want to add new elements:
 heapq.heappush(decorated_list, (Vertex(...), next(numbermaker)))

 # When you want to get the top of the heap's value:
 top = decorated_list[0][0]  # First [0] gets decorated top, second strips decoration

 # When you want to pop off the top:
 top = heapq.heappop(decorated_list)[0]

堆不是排序列表。列表未排序这一事实不是问题。堆不是排序列表。列表没有排序这一事实不是问题。我明白了。使用自定义对象时是否仍然满足不变量?我使用的是total_score作为优先级。@Timbwa:如果有两个对象具有相同的total_成本,堆会半任意地对它们排序。一次堆出一个对象并不是一种稳定的排序,但是的,不变量仍然满足要求。如果需要稳定性,则必须使用单调递增的值来修饰它们,例如,创建一个count对象,numbermaker=itertools.count,而不是在堆中使用原始值,使用元组将原始值与nextnumbermaker配对,以便每个新值后面都有一个更大的断开连接的值。^enumerate也可用作tiebreaker@wim:是的。计数的优点是,您可以将对象放在一边,并在以后添加新元素时重用它;enumerate只适用于处理单个输入iterable,然后您就失去了添加更多不相关元素的状态,而在heapify之后OP显然会推动更多的元素。如果你只需要对一个iterable进行heapify,然后再也不推/替换pop,enumerate很好,遗憾的是,你必须对它返回的内容重新排序,因为它首先给出索引,然后给出值。我明白了。使用自定义对象时是否仍然满足不变量?我使用的是total_score作为优先级。@Timbwa:如果有两个对象具有相同的total_成本,堆会半任意地对它们排序。一次堆出一个对象并不是一种稳定的排序,但是的,不变量仍然满足要求。如果需要稳定性,则必须使用单调递增的值来修饰它们,例如,创建一个count对象,numbermaker=itertools.count,而不是在堆中使用原始值,使用元组将原始值与nextnumbermaker配对,以便每个新值后面都有一个更大的断开连接的值。^enumerate也可用作tiebreaker@wim:是的。计数的优点是,您可以将对象放在一边并重用它 以后添加新元素时;enumerate只适用于处理单个输入iterable,然后您就失去了添加更多不相关元素的状态,而在heapify之后OP显然会推动更多的元素。如果您只需要heapify一个iterable,然后再也不推送/替换pop,enumerate很好,遗憾的是,您必须对它返回的内容重新排序,因为它首先给出索引,然后给出值。