Вектори

У Scheme вектор — це ще одна фундаментальна структура даних для групування значень. На відміну від списків, вектори — це індексовані колекції елементів фіксованого розміру, які забезпечують швидший довільний доступ і оновлення. Кожен елемент у векторі може бути будь-якого типу, включно з іншим вектором. Вектори позначаються символом #, за яким йдуть дужки: #(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)  ; Отримати елемент з індексом 0
(vector-ref my-vector 1)  ; Отримати елемент з індексом 1

Ітерація: обробка кожного елемента вектора

Вектор можна перебирати циклом або рекурсією. Scheme надає vector-length для визначення розміру вектора. Ось простий цикл для друку кожного елемента вектора:

(define (print-elements vec)
  (let loop ((i 0))
    (if (< i (vector-length vec))
      (begin
        (lumi-message (number->string (vector-ref vec i))) ; Вивести елемент
        (loop (+ i 1)))                                    ; Перейти до наступного індексу
      (lumi-message "done"))))                             ; Кінець циклу
  • Базовий випадок: якщо індекс i досягає довжини вектора, зупинити цикл.
  • Рекурсивний випадок: вивести елемент з індексом i, потім збільшити i.

Приклад використання

(print-elements (vector 1 2 3))

Результат:

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

Результат: "done"

Змішані вектори

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

(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)  ; Встановити другий елемент як 42
my-vector

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

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

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

(vector? (vector 1 2 3))  ; Перевірити, чи #(1 2 3) є вектором
(vector? 42)              ; Перевірити, чи 42 є вектором

Результат:

  • (vector? (vector 1 2 3)) повертає #t (істина)
  • (vector? 42) повертає #f (хибність)

Вектори та передавання за посиланням

У Scheme вектори є змінними та передаються за посиланням. Це означає, що коли ви передаєте вектор функції, функція може безпосередньо змінювати вихідний вектор. Будь-які зміни, внесені до вектора всередині функції, також відображатимуться поза нею. Така поведінка корисна для ефективного обміну й оновлення даних між функціями, але вимагає обережності, щоб уникнути небажаних побічних ефектів.

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

Ось приклад, який демонструє, як вектори передаються за посиланням і змінюються:

(define (modify-vector vec index new-value)
  (vector-set! vec index new-value))  ; Оновити вектор за вказаним індексом

(define my-vector (vector 10 20 30))
(modify-vector my-vector 1 99)         ; Змінити другий елемент на 99
my-vector                              ; Вихідний вектор тепер оновлено

Результат: #(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))         ; Повертає 3
(vector->list (vector 1 2 3))          ; Перетворити вектор на список: (1 2 3)
(list->vector (list 1 2 3))            ; Перетворити список на вектор: #(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)              ; Отримати перший елемент: #(1 2)
(vector-ref (vector-ref nested-vector 0) 1) ; Отримати другий елемент першого вектора: 2

Резюме

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