3

我有一个无向的彩色(相邻节点有不同的颜色)图,我需要计算一个散列,以便如果两个图是同构的,它们具有相同的散列(图也是平面的,我不知道它是否可以有所作为)。

我的数据结构是这样的:

class Node:
    def __init__(self, id, color):
        self.id = id # int
        self.color = color # string
        self.adjacentNodes = set()

id属性用于程序逻辑,因此在比较图形时不应考虑它。

我的想法是对图的节点进行排序,然后从第一个节点开始探索相邻节点以生成图的树。然后我从树中生成一个唯一的字符串(实际上我是在探索期间生成的字符串)。所以,我想做的是找到一种图的规范化。

描述

我首先按度数对节点进行排序,然后按颜色属性名称升序排列。我采用第一个节点并开始探索相邻节点,深度优先搜索以相同的方式对它们进行排序。我跟踪已经访问过的节点以避免扩展旧节点。

我的字符串是这样生成的:使用深度优先搜索,每次我到达一个新节点时,我都会将以下内容附加到图形字符串中:

  • 节点颜色
  • 节点度
  • 访问节点列表中的索引

也许这是多余的,但我认为这些信息足以保证正确的规范化。

真正的问题是两个节点在排序过程中具有相同的度数和相同的颜色。我所做的应该保证规范化,但效率不高。取一组相似的节点(相同的度数和颜色),我为每个节点生成一个子树,并为子树生成一个关联的字符串,并在节点排序中选择最大的一个(按降序排序)作为下一个。然后我删除最后一个节点并重复操作,直到该组为空。我需要这样做,因为在选择第一个节点后,我可能已经更改了访问节点的列表,然后新的字符串可能会有所不同。

目前这种实现效率很低:

# actually this function return the unique string associated with the graph
# that will be hashed with the function hash() in a second moment
def new_hash(graph, queue=[]): # graph: list of Node
    if not queue: # first call: find the root of the tree
        graph.sort(key = lambda x: (len(x.adjacentNodes), x.color), reverse=True)
        groups = itertools.groupby(graph, key = lambda x: (len(x.adjacentNodes), x.color))
        roots = []
        result_hash = ''

        for _, group in groups:
            roots  = [x for x in group]
            break # I just need the first (the candidates roots)

        temp_hashes = []

        for node in roots:
            temp_queue = [node.id]
            temp_hash = node.color + str(len(node.adjacentNodes)) + str(temp_queue.index(node.id))
            temp_hash += new_hash(list(node.adjacentNodes), temp_queue)
            temp_hashes.append((node, temp_hash, temp_queue))

        temp_hashes.sort(key = lambda x: x[1], reverse=True)
        queue = temp_hashes[0][2]        
        result_hash += temp_hashes[0][1]
        result_hash += new_hash(list(temp_hashes[0][0].adjacentNodes), queue=queue)
    else:
        graph.sort(key = lambda x: (len(x.adjacentNodes), x.color), reverse=True)
        groups = itertools.groupby(graph, key = lambda x: (len(x.adjacentNodes), x.color))
        grouped_nodes = []
        result_hash = ''

        for _, group in groups:
            grouped_nodes.append([x for x in group])

        for group in grouped_nodes:
            while len(group) > 0:
                temp_hashes = []

                for node in group:
                    if node.id in queue:
                        temp_hash = node.color + str(len(node.adjacentNodes)) + str(queue.index(node.id))
                        temp_hashes.append((node, temp_hash, queue))
                    else:
                        temp_queue = queue[:]
                        temp_queue.append(node.id)
                        temp_hash = node.color + str(len(node.adjacentNodes)) + str(temp_queue.index(node.id))
                        temp_hash += new_hash(list(node.adjacentNodes), queue=temp_queue)
                        temp_hashes.append((node, temp_hash, temp_queue))

                temp_hashes.sort(key = lambda x: x[1], reverse=True)
                queue = temp_hashes[0][2]
                result_hash += temp_hashes[0][1]
                group.remove(temp_hashes[0][0])

    return result_hash

问题

因此我有两个问题:

  • 我的算法真的有效吗(我的意思是,它似乎有效,但我没有任何数学证明)?
  • 是否有更快的算法(复杂性更低)来计算哈希?
4

0 回答 0