построение списка смежности - PullRequest
1 голос
/ 24 марта 2019

У меня проблемы с пониманием окончательного результата

for i in edgeList:
    adjacencyList[i[0]].append(i[0])

в коде ниже. Я пытался распечатать утверждения в каждой строке, чтобы попытаться понять, но все еще в замешательстве.

    vertexList = ["0","1","2","3","4","5","6"]
    edgeList = [(0,1), (0,2),(1,0), (1,3), (2,0), (2,4), (2,5), (3,1), (4,2), (4,6), (5,2), (6,4)]

    adjacencyList = [[] for vertex in vertexList]

    for i in edgeList:
        adjacencyList[i[0]].append(i[1])

    print(adjacencyList)

Output: [[1, 2], [0, 3], [0, 4, 5], [1], [2, 6], [2], [4]]

Считается ли это циклом for, возникающим внутри цикла for из-за понимания списка? Цените, если кто-то мог разобрать, что здесь происходит. (это связано с BFS в теории графов)

Ответы [ 2 ]

2 голосов
/ 24 марта 2019

Хорошим инструментом для визуализации проблем с графами является graphviz, который поставляется с командой dot. Сначала создайте edgelist.dot, содержащий все ребра из вашей переменной edgeList:

digraph G {
    0 -> 1
    0 -> 2
    1 -> 0
    1 -> 3
    2 -> 0
    2 -> 4
    2 -> 5
    3 -> 1
    4 -> 2
    4 -> 6
    5 -> 2
    6 -> 4
}

(есть более короткие способы написать это, что вы можете посмотреть). Тогда кормите его через dot:

c:\srv\tmp> dot -Tsvg -o edgelist.svg edgelist.dot

, а затем откройте созданный edgelist.svg файл:

graph created by graphviz

Списки смежности - это списки узлов, к которым можно обратиться из определенного узла, например, для узла 0 имеются стрелки к узлам 1 и 2, поэтому adjacencyList[0], т. е. список смежности для узла 0 должен быть [1, 2].

Аналогично, стрелки-выходы из узла 2 достигают узлов 0, 4 и 5, поэтому adjacencyList[2] должно быть [0, 4, 5].

Вручную, проходя каждый узел по порядку, список смежности заканчивается:

            [[1, 2], [0, 3], [0, 4, 5], [1], [2, 6], [2], [4]]
             ^       ^       ^          ^    ^       ^    ^
item/index:  0       1       2          3    4       5    6

В вашем коде эта строка:

adjacencyList = [[] for vertex in vertexList]

просто создает adjacencyList как список пустых списков ([]) с длиной, равной количеству вершин.

Тогда это для цикла:

for i in edgeList:
    adjacencyList[i[0]].append(i[0])

пытается заполнить его. Чтобы увидеть, что не так, мы можем переписать цикл for, чтобы он распаковывал ребра в edgeList:

for (start, end) in edgeList:
    adjacencyList[start].append(..?..)

очевидно, что ..?.. должно быть end и не начинаться:

for start, end in edgeList:
    adjacencyList[start].append(end)

Теперь вы можете видеть, что цикл for выполняет то, что мы делали выше, для каждого ребра (start, end) добавляет end в список смежности start.

Приложение: Ваш код хорошо работает для случаев, когда вершины (0, 1 и т. Д.) Имеют те же значения, что и индексы в массиве. Хотя это эффективно, оно не может быть педагогически предпочтительным (или, может быть, я не знаю ;-) В любом случае, если мы переименуем ваши вершины так, что 0 станет "A", 1 станет "B" и т.д., вам нужно будет использовать другую структуру данных для списка смежности, например:

from collections import defaultdict

edgeList = [("A", "B"),
            ("A", "C"),
            ("B","A"), ("B","D"),
            ("C","A"), ("C","E"), ("C","F"),
            ("D","B"),
            ("E","C"), ("E","G"),
            ("F","C"),
            ("G","E")]

adjacencyList = defaultdict(list)

for start, end in edgeList:
    adjacencyList[start].append(end)

print(sorted(adjacencyList.items()))

который печатает:

[('A', ['B', 'C']), ('B', ['A', 'D']), ('C', ['A', 'E', 'F']), ('D', ['B']), ('E', ['C', 'G']), ('F', ['C']), ('G', ['E'])]

означает, что список смежности для 'A' равен ['B', 'C'] и т. Д.

возможно (и, возможно, полезно для времени выполнения) перевести эту версию в первую версию (особенно в языках, более статичных, чем Python).

2 голосов
/ 24 марта 2019

Ваша adjacencyList конструкция неверна.

Заменить adjacencyList[i[0]].append(i[0]) с adjacencyList[i[0]].append(i[1]). Я не вижу никаких петель внутри другого. Ваша сложность времени составляет O(n).

Цель adjacencyList - сохранить все смежные узлы для данного узла. В вашем случае это индекс списка.

После изменения ваш вывод должен быть

[[1, 2], [0, 3], [0, 4, 5], [1], [2, 6], [2], [4]]

Отсюда вы можете интерпретировать, что 0 имеет 1 и 2 как соседей. 2 имеет 0 и 3 соседей, 3 имеет 0,4 и 5 в качестве соседей и т. Д.

Обратите внимание, что этот подход не работает, если у вас есть такие узлы, как {2, 60, 1000, 4}. В этом случае лучше использовать словарь узлов и список соседей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...