Векторы

В схеме вектор — это еще одна фундаментальная структура данных, используемая для группировки значений. В отличие от списков, векторы представляют собой индексированные коллекции элементов фиксированного размера, обеспечивающие более быстрый произвольный доступ и обновления. Каждый элемент вектора может быть любого типа, включая другой вектор. Векторы обозначаются знаком #, за которым следуют круглые скобки. #(1 2 3)

Хотя векторы и списки могут показаться похожими, в программировании на Scheme они служат разным целям:

  • Списки чаще используются для рекурсивных операций и динамических структур, поскольку их реализация со связанными узлами позволяет эффективно манипулировать их началом и обходом посредством рекурсивной декомпозиции.

С другой стороны, векторы оптимизированы для сценариев, в которых требуется произвольный доступ к элементам или обновления определенных индексов, что делает их более подходящими для таких случаев использования, как таблицы поиска, конфигурации фиксированного размера или индексированные операции, критичные к производительности.

По сути, списки являются естественным выбором для рекурсивных алгоритмов и данных динамического размера, в то время как векторы прекрасно подходят, когда первостепенное значение имеют шаблоны доступа фиксированного размера или индексированные.

Простые векторы

(vector 1 2 3)
  • Создает вектор из трех элементов: 1, 2 и 3.

Результат: #(1 2 3)

Доступ к векторным элементам

Доступ к элементам вектора осуществляется с помощью процедуры vector-ref, она извлекает элемент по указанному индексу (начиная с 0).

(define my-vector (vector 1 2 3))
(vector-ref my-vector 0)  ; Retrieves the element at index 0
(vector-ref my-vector 1)  ; Retrieves the element at index 1

Итерация: обработка каждого элемента вектора

Вы можете перебирать вектор, используя цикл или рекурсию. Схема предоставляет vector-length для определения размера вектора. Вот простой цикл для печати каждого элемента вектора:

(define (print-elements vec)
  (let loop ((i 0))
    (if (< i (vector-length vec))
      (begin
        (lumi-message (number->string (vector-ref vec i))) ; Print the element
        (loop (+ i 1)))                                    ; Process the next index
      (lumi-message "done"))))                             ; End loop
  • Базовый случай: Если индекс i достигает длины вектора, остановите цикл.
  • Рекурсивный случай: Распечатайте элемент с индексом i, затем увеличьте i.

Пример использования

(print-elements (vector 1 2 3))

Результат:

  • "1"
  • "2"
  • "3"

Результат: «готово»

Смешанные векторы

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

(vector 42 "hello" #t (vector 1 2) (+ 3 4))

Это создает вектор с:

  • Номер (42)
  • Строка ("hello")
  • Логическое значение (#t)
  • Другой вектор (#(1 2))
  • Результат выражения ((+ 3 4), которое оценивается как 7)

Результат: #(42 "hello" #t #(1 2) 7)

Построение векторов

Векторы создаются с помощью vector или с помощью make-vector для создания вектора фиксированного размера с начальным значением.

(make-vector 5 0)

Создает вектор размера 5 со всеми элементами, инициализированными как 0.

Результат: #(0 0 0 0 0)

Обновление векторов

Процедура vector-set! обновляет элемент вектора по указанному индексу.

(define my-vector (vector 1 2 3))
(vector-set! my-vector 1 42)  ; Sets the second element to 42
my-vector

Результат: #(1 42 3)

Проверка векторов

Процедура vector? проверяет, является ли данное значение вектором.

(vector? (vector 1 2 3))  ; Checks if #(1 2 3) is a vector
(vector? 42)              ; Checks if 42 is a vector

Результат:

  • (vector? (vector 1 2 3)) возвращает #t (истина)
  • (vector? 42) возвращает #f (ложь)

Векторы и передача по ссылкеВ Scheme векторы изменяемы и передаются по ссылке. Это означает, что когда вы передаете вектор функции, функция может напрямую изменить исходный вектор. Любые изменения, внесенные в вектор внутри функции, будут отражены и за ее пределами. Такое поведение полезно для эффективного обмена и обновления данных в нескольких функциях, но оно также требует осторожности, чтобы избежать непредвиденных побочных эффектов.

Пример: изменение вектора в функции

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

(define (modify-vector vec index new-value)
  (vector-set! vec index new-value))  ; Updates the vector at the specified index

(define my-vector (vector 10 20 30))
(modify-vector my-vector 1 99)         ; Modifies the second element to 99
my-vector                              ; The original vector is now updated

Результат: #(10 99 30)

Пошаговое объяснение

  1. Создайте вектор: my-vector инициализируется значениями 10, 20 и 30.
  2. Передача функции: my-vector передается modify-vector вместе с индексом и новым значением для обновления.
  3. Изменить в функции: Процедура vector-set! обновляет значение по указанному индексу непосредственно в исходном векторе.
  4. Отражение изменений. Поскольку векторы передаются по ссылке, изменения, внесенные внутри функции, отражаются в исходном векторе.

Последствия передачи по ссылке

  • Производительность. Передача векторов по ссылке эффективна, поскольку позволяет избежать копирования больших структур.
  • Побочные эффекты: Будьте осторожны при совместном использовании векторов между функциями, чтобы избежать непреднамеренного изменения общих данных.

Операции с векторами

Scheme предоставляет несколько встроенных процедур для работы с векторами, в том числе:

  • vector-length: возвращает количество элементов в векторе.
  • vector->list: преобразует вектор в список.
  • list->vector: преобразует список в вектор.
(vector-length (vector 1 2 3))         ; Returns 3
(vector->list (vector 1 2 3))          ; Converts vector to list: (1 2 3)
(list->vector (list 1 2 3))            ; Converts list to vector: #(1 2 3)

Результат:

  • (vector-length (vector 1 2 3)) возвращает 3
  • (vector->list (vector 1 2 3)) возвращает (1 2 3)
  • (list->vector (list 1 2 3)) возвращает #(1 2 3)

Вложенные векторы

Векторы в Scheme могут содержать другие векторы в качестве элементов, создавая вложенную структуру.

(define nested-vector (vector (vector 1 2) (vector 3 4) (vector 5)))

Создает вектор из трех элементов, каждый из которых сам является вектором.

Результат: #(#(1 2) #(3 4) #(5))

Доступ к вложенным данным

Чтобы получить доступ к элементам внутри вложенного вектора, используйте vector-ref несколько раз для навигации по структуре.

Пример: доступ к элементам

(vector-ref nested-vector 0)              ; Retrieves the first element: #(1 2)
(vector-ref (vector-ref nested-vector 0) 1) ; Retrieves the second element of the first vector: 2

Резюме

  • Векторы в Scheme представляют собой индексированные структуры данных фиксированного размера.
  • Используйте vector для создания вектора, vector-ref для доступа к элементам и vector-set! для обновления элементов.
  • Встроенные процедуры, такие как vector-length, vector->list и list->vector, обеспечивают гибкость операций.
  • Вложенные векторы позволяют создавать сложные иерархические структуры данных.