8.5. Основы Kotlin. Графы

Граф — это математическая абстракция, имеющая, тем не менее, очень широкое применение в программировании. Граф состоит из множества так называемых вершин, которые обычно изображаются как точки на плоскости, и рёбер(другое название ребра — дуга), которые эти вершины соединяют. Пример графа приведён на рисунке.

333px 6n graf.svg

Чаще всего графы применяются для описания различных схем, например, соединения узлов в компьютерной сети или городов и других пунктов на карте местности. Типичная решаемая с помощью графа задача — поиск кратчайшего маршрута из одного пункта в другой. Довольно часто граф, помимо информации о своих вершин и рёбрах, содержит вспомогательную информацию. Например, для схемы дорог ей могут быть названия городов, соответствующих вершинам графа, или длины дорог, соответствующих рёбрам графа. Пример:

086 01

Структуры данных, подобные графам, могут возникать в различных задач поиска оптимального решения. Например, в lesson8/task2 имеется задача о поиске наиболее короткой траектории движения шахматного коня. Эту задачу можно описать с помощью графа, вершинами которого являются клетки шахматной доски, а рёбра соединяют те из них, между которыми может двигаться шахматный конь. Такой граф может выглядеть примерно так:

1024px Knight%27s graph showing number of possible moves.svg

Описать граф на языке программирования можно разными способами. В той же задаче о маршруте шахматного коня лучше вообще не хранить информацию о вершинах графа, достаточно лишь уметь по конкретной клетке найти связанные с ней ребром — то есть, те клетки, в которые из данной клетки может прыгнуть конь. В других задачах, тем не менее, информацию о вершинах и рёбрах графа есть смысл сохранить, и тогда следует для этой цели использовать собственный класс. Пример реализации такого класса приведён ниже.

class Graph {
    private data class Vertex(val name: String) {
        val neighbors = mutableSetOf<Vertex>()
    }

    private val vertices = mutableMapOf<String, Vertex>()

    private operator fun get(name: String) = vertices[name] ?: throw IllegalArgumentException()

    fun addVertex(name: String) {
        vertices[name] = Vertex(name)
    }

    private fun connect(first: Vertex, second: Vertex) {
        first.neighbors.add(second)
        second.neighbors.add(first)
    }

    fun connect(first: String, second: String) = connect(this[first], this[second])

    fun neighbors(name: String) = vertices[name]?.neighbors?.map { it.name } ?: listOf()
}

Описанный здесь Graph является довольно сложным классом. Он включает в себя функцию addVertex (добавить вершину) и две функции connect (соединить) с разным набором параметров, причём одна из них является закрытой(private). Для доступа к списку вершин, соседних для данной, в классе имеется функция neighbors, Кроме этого, в классе имеется операторная функция get, которая также является закрытой, свойство (val) vertices (вершины), в котором хранится ассоциативный массив (MutableMap) и которое опять-таки закрыто, и вложенный класс Vertex(вершина) со свойствами name (имя) и neighbors (соседи). Рассмотрим все эти элементы класса Graph подробнее.

Додати коментар