Перейти к содержанию

4.3   Список

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

  • Связный список естественным образом можно рассматривать как список: он поддерживает операции добавления, удаления, поиска и изменения элементов и может гибко расширяться динамически.
  • Массив тоже поддерживает операции добавления, удаления, поиска и изменения элементов, но из-за неизменяемости длины его можно считать лишь списком с ограниченной длиной.

Когда список реализуется с помощью массива, неизменяемость длины снижает его практическую полезность. Причина в том, что мы обычно не можем заранее точно знать, сколько данных нужно хранить, а значит, трудно выбрать подходящую длину списка. Если длина слишком мала, она может не покрыть реальные потребности; если слишком велика, будет зря расходоваться память.

Чтобы решить эту проблему, можно использовать динамический массив (dynamic array) для реализации списка. Он сохраняет все преимущества массива и при этом может динамически расширяться во время выполнения программы.

На практике списки из стандартных библиотек многих языков программирования реализованы именно на основе динамических массивов, например list в Python, ArrayList в Java, vector в C++ и List в C#. В дальнейшем обсуждении мы будем считать понятия "список" и "динамический массив" эквивалентными.

4.3.1   Основные операции со списком

1.   Инициализация списка

Обычно мы используем два способа инициализации: "без начальных значений" и "с начальными значениями":

list.py
# Инициализация списка
# Без начальных значений
nums1: list[int] = []
# С начальными значениями
nums: list[int] = [1, 3, 2, 5, 4]
list.cpp
/* Инициализация списка */
// Обрати внимание: в C++ vector соответствует описываемому здесь nums
// Без начальных значений
vector<int> nums1;
// С начальными значениями
vector<int> nums = { 1, 3, 2, 5, 4 };
list.java
/* Инициализация списка */
// Без начальных значений
List<Integer> nums1 = new ArrayList<>();
// С начальными значениями (обрати внимание: элементы массива должны использовать обертку Integer[] вместо int[])
Integer[] numbers = new Integer[] { 1, 3, 2, 5, 4 };
List<Integer> nums = new ArrayList<>(Arrays.asList(numbers));
list.cs
/* Инициализация списка */
// Без начальных значений
List<int> nums1 = [];
// С начальными значениями
int[] numbers = [1, 3, 2, 5, 4];
List<int> nums = [.. numbers];
list_test.go
/* Инициализация списка */
// Без начальных значений
nums1 := []int{}
// С начальными значениями
nums := []int{1, 3, 2, 5, 4}
list.swift
/* Инициализация списка */
// Без начальных значений
let nums1: [Int] = []
// С начальными значениями
var nums = [1, 3, 2, 5, 4]
list.js
/* Инициализация списка */
// Без начальных значений
const nums1 = [];
// С начальными значениями
const nums = [1, 3, 2, 5, 4];
list.ts
/* Инициализация списка */
// Без начальных значений
const nums1: number[] = [];
// С начальными значениями
const nums: number[] = [1, 3, 2, 5, 4];
list.dart
/* Инициализация списка */
// Без начальных значений
List<int> nums1 = [];
// С начальными значениями
List<int> nums = [1, 3, 2, 5, 4];
list.rs
/* Инициализация списка */
// Без начальных значений
let nums1: Vec<i32> = Vec::new();
// С начальными значениями
let nums: Vec<i32> = vec![1, 3, 2, 5, 4];
list.c
// В C нет встроенного динамического массива
list.kt
/* Инициализация списка */
// Без начальных значений
var nums1 = listOf<Int>()
// С начальными значениями
var numbers = arrayOf(1, 3, 2, 5, 4)
var nums = numbers.toMutableList()
list.rb
# Инициализация списка
# Без начальных значений
nums1 = []
# С начальными значениями
nums = [1, 3, 2, 5, 4]
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20%23%20%D0%91%D0%B5%D0%B7%20%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9%0A%20%20%20%20nums1%20%3D%20%5B%5D%0A%20%20%20%20%23%20%D0%A1%20%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

2.   Доступ к элементам

Список по своей сути является массивом, поэтому доступ к элементам и их обновление можно выполнять за \(O(1)\) времени, что очень эффективно.

list.py
# Доступ к элементу
num: int = nums[1]  # Доступ к элементу по индексу 1

# Обновление элемента
nums[1] = 0    # Обновить элемент по индексу 1 значением 0
list.cpp
/* Доступ к элементу */
int num = nums[1];  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0;  // Обновить элемент по индексу 1 значением 0
list.java
/* Доступ к элементу */
int num = nums.get(1);  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums.set(1, 0);  // Обновить элемент по индексу 1 значением 0
list.cs
/* Доступ к элементу */
int num = nums[1];  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0;  // Обновить элемент по индексу 1 значением 0
list_test.go
/* Доступ к элементу */
num := nums[1]  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0     // Обновить элемент по индексу 1 значением 0
list.swift
/* Доступ к элементу */
let num = nums[1] // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0 // Обновить элемент по индексу 1 значением 0
list.js
/* Доступ к элементу */
const num = nums[1];  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0;  // Обновить элемент по индексу 1 значением 0
list.ts
/* Доступ к элементу */
const num: number = nums[1];  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0;  // Обновить элемент по индексу 1 значением 0
list.dart
/* Доступ к элементу */
int num = nums[1];  // Доступ к элементу по индексу 1

/* Обновление элемента */
nums[1] = 0;  // Обновить элемент по индексу 1 значением 0
list.rs
/* Доступ к элементу */
let num: i32 = nums[1];  // Доступ к элементу по индексу 1
/* Обновление элемента */
nums[1] = 0;             // Обновить элемент по индексу 1 значением 0
list.c
// В C нет встроенного динамического массива
list.kt
/* Доступ к элементу */
val num = nums[1]       // Доступ к элементу по индексу 1
/* Обновление элемента */
nums[1] = 0             // Обновить элемент по индексу 1 значением 0
list.rb
# Доступ к элементу
num = nums[1] # Доступ к элементу по индексу 1
# Обновление элемента
nums[1] = 0 # Обновить элемент по индексу 1 значением 0
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%0A%20%20%20%20%23%20%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C%20%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%20%D0%BA%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D1%83%0A%20%20%20%20num%20%3D%20nums%5B1%5D%20%20%23%20%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%B8%D1%82%D1%8C%D1%81%D1%8F%20%D0%BA%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%201%20%D0%BF%D0%BE%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%0A%0A%20%20%20%20%23%20%D0%9E%D0%B1%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%0A%20%20%20%20nums%5B1%5D%20%3D%200%20%20%20%20%23%20%D0%9E%D0%B1%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BF%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D1%83%201%20%D0%B4%D0%BE%200&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

3.   Вставка и удаление элементов

По сравнению с массивами список позволяет свободно добавлять и удалять элементы. Добавление элемента в конец списка имеет временную сложность \(O(1)\) , но операции вставки и удаления по-прежнему имеют ту же эффективность, что и у массива, то есть \(O(n)\) .

list.py
# Очистить список
nums.clear()

# Добавить элементы в конец
nums.append(1)
nums.append(3)
nums.append(2)
nums.append(5)
nums.append(4)

# Вставить элемент в середину
nums.insert(3, 6)  # Вставить число 6 по индексу 3

# Удалить элемент
nums.pop(3)        # Удалить элемент по индексу 3
list.cpp
/* Очистить список */
nums.clear();

/* Добавить элементы в конец */
nums.push_back(1);
nums.push_back(3);
nums.push_back(2);
nums.push_back(5);
nums.push_back(4);

/* Вставить элемент в середину */
nums.insert(nums.begin() + 3, 6);  // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.erase(nums.begin() + 3);      // Удалить элемент по индексу 3
list.java
/* Очистить список */
nums.clear();

/* Добавить элементы в конец */
nums.add(1);
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);

/* Вставить элемент в середину */
nums.add(3, 6);  // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.remove(3);  // Удалить элемент по индексу 3
list.cs
/* Очистить список */
nums.Clear();

/* Добавить элементы в конец */
nums.Add(1);
nums.Add(3);
nums.Add(2);
nums.Add(5);
nums.Add(4);

/* Вставить элемент в середину */
nums.Insert(3, 6);  // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.RemoveAt(3);  // Удалить элемент по индексу 3
list_test.go
/* Очистить список */
nums = nil

/* Добавить элементы в конец */
nums = append(nums, 1)
nums = append(nums, 3)
nums = append(nums, 2)
nums = append(nums, 5)
nums = append(nums, 4)

/* Вставить элемент в середину */
nums = append(nums[:3], append([]int{6}, nums[3:]...)...) // Вставить число 6 по индексу 3

/* Удалить элемент */
nums = append(nums[:3], nums[4:]...) // Удалить элемент по индексу 3
list.swift
/* Очистить список */
nums.removeAll()

/* Добавить элементы в конец */
nums.append(1)
nums.append(3)
nums.append(2)
nums.append(5)
nums.append(4)

/* Вставить элемент в середину */
nums.insert(6, at: 3) // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.remove(at: 3) // Удалить элемент по индексу 3
list.js
/* Очистить список */
nums.length = 0;

/* Добавить элементы в конец */
nums.push(1);
nums.push(3);
nums.push(2);
nums.push(5);
nums.push(4);

/* Вставить элемент в середину */
nums.splice(3, 0, 6); // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.splice(3, 1);  // Удалить элемент по индексу 3
list.ts
/* Очистить список */
nums.length = 0;

/* Добавить элементы в конец */
nums.push(1);
nums.push(3);
nums.push(2);
nums.push(5);
nums.push(4);

/* Вставить элемент в середину */
nums.splice(3, 0, 6); // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.splice(3, 1);  // Удалить элемент по индексу 3
list.dart
/* Очистить список */
nums.clear();

/* Добавить элементы в конец */
nums.add(1);
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);

/* Вставить элемент в середину */
nums.insert(3, 6); // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.removeAt(3); // Удалить элемент по индексу 3
list.rs
/* Очистить список */
nums.clear();

/* Добавить элементы в конец */
nums.push(1);
nums.push(3);
nums.push(2);
nums.push(5);
nums.push(4);

/* Вставить элемент в середину */
nums.insert(3, 6);  // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.remove(3);    // Удалить элемент по индексу 3
list.c
// В C нет встроенного динамического массива
list.kt
/* Очистить список */
nums.clear();

/* Добавить элементы в конец */
nums.add(1);
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);

/* Вставить элемент в середину */
nums.add(3, 6);  // Вставить число 6 по индексу 3

/* Удалить элемент */
nums.remove(3);  // Удалить элемент по индексу 3
list.rb
# Очистить список
nums.clear

# Добавить элементы в конец
nums << 1
nums << 3
nums << 2
nums << 5
nums << 4

# Вставить элемент в середину
nums.insert(3, 6) # Вставить число 6 по индексу 3

# Удалить элемент
nums.delete_at(3) # Удалить элемент по индексу 3
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%A1%20%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%9E%D1%87%D0%B8%D1%81%D1%82%D0%B8%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums.clear%28%29%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%94%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B2%20%D0%BA%D0%BE%D0%BD%D0%B5%D1%86%0A%20%20%20%20nums.append%281%29%0A%20%20%20%20nums.append%283%29%0A%20%20%20%20nums.append%282%29%0A%20%20%20%20nums.append%285%29%0A%20%20%20%20nums.append%284%29%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%92%D1%81%D1%82%D0%B0%D0%B2%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B2%20%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D1%83%0A%20%20%20%20nums.insert%283%2C%206%29%20%20%23%20%D0%92%D1%81%D1%82%D0%B0%D0%B2%D0%B8%D1%82%D1%8C%20%D1%87%D0%B8%D1%81%D0%BB%D0%BE%206%20%D0%BF%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D1%83%203%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%A3%D0%B4%D0%B0%D0%BB%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%0A%20%20%20%20nums.pop%283%29%20%20%20%20%20%20%20%20%23%20%D0%A3%D0%B4%D0%B0%D0%BB%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BF%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D1%83%203&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

4.   Обход списка

Как и массив, список можно обходить как по индексам, так и напрямую по элементам.

list.py
# Обход списка по индексам
count = 0
for i in range(len(nums)):
    count += nums[i]

# Прямой обход элементов списка
for num in nums:
    count += num
list.cpp
/* Обход списка по индексам */
int count = 0;
for (int i = 0; i < nums.size(); i++) {
    count += nums[i];
}

/* Прямой обход элементов списка */
count = 0;
for (int num : nums) {
    count += num;
}
list.java
/* Обход списка по индексам */
int count = 0;
for (int i = 0; i < nums.size(); i++) {
    count += nums.get(i);
}

/* Прямой обход элементов списка */
for (int num : nums) {
    count += num;
}
list.cs
/* Обход списка по индексам */
int count = 0;
for (int i = 0; i < nums.Count; i++) {
    count += nums[i];
}

/* Прямой обход элементов списка */
count = 0;
foreach (int num in nums) {
    count += num;
}
list_test.go
/* Обход списка по индексам */
count := 0
for i := 0; i < len(nums); i++ {
    count += nums[i]
}

/* Прямой обход элементов списка */
count = 0
for _, num := range nums {
    count += num
}
list.swift
/* Обход списка по индексам */
var count = 0
for i in nums.indices {
    count += nums[i]
}

/* Прямой обход элементов списка */
count = 0
for num in nums {
    count += num
}
list.js
/* Обход списка по индексам */
let count = 0;
for (let i = 0; i < nums.length; i++) {
    count += nums[i];
}

/* Прямой обход элементов списка */
count = 0;
for (const num of nums) {
    count += num;
}
list.ts
/* Обход списка по индексам */
let count = 0;
for (let i = 0; i < nums.length; i++) {
    count += nums[i];
}

/* Прямой обход элементов списка */
count = 0;
for (const num of nums) {
    count += num;
}
list.dart
/* Обход списка по индексам */
int count = 0;
for (var i = 0; i < nums.length; i++) {
    count += nums[i];
}

/* Прямой обход элементов списка */
count = 0;
for (var num in nums) {
    count += num;
}
list.rs
// Обход списка по индексам
let mut _count = 0;
for i in 0..nums.len() {
    _count += nums[i];
}

// Прямой обход элементов списка
_count = 0;
for num in &nums {
    _count += num;
}
list.c
// В C нет встроенного динамического массива
list.kt
/* Обход списка по индексам */
var count = 0
for (i in nums.indices) {
    count += nums[i]
}

/* Прямой обход элементов списка */
for (num in nums) {
    count += num
}
list.rb
# Обход списка по индексам
count = 0
for i in 0...nums.length
    count += nums[i]
end

# Прямой обход элементов списка
count = 0
for num in nums
    count += num
end
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%9E%D0%B1%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20%D0%BF%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0%D0%BC%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%0A%20%20%20%20%23%20%D0%9D%D0%B5%D0%BF%D0%BE%D1%81%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%20%D0%BE%D0%B1%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D1%8B%20%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

5.   Конкатенация списков

Если дан новый список nums1 , мы можем присоединить его к хвосту исходного списка.

list.py
# Конкатенация двух списков
nums1: list[int] = [6, 8, 7, 10, 9]
nums += nums1  # Присоединить список nums1 к концу nums
list.cpp
/* Конкатенация двух списков */
vector<int> nums1 = { 6, 8, 7, 10, 9 };
// Присоединить список nums1 к концу nums
nums.insert(nums.end(), nums1.begin(), nums1.end());
list.java
/* Конкатенация двух списков */
List<Integer> nums1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 }));
nums.addAll(nums1);  // Присоединить список nums1 к концу nums
list.cs
/* Конкатенация двух списков */
List<int> nums1 = [6, 8, 7, 10, 9];
nums.AddRange(nums1);  // Присоединить список nums1 к концу nums
list_test.go
/* Конкатенация двух списков */
nums1 := []int{6, 8, 7, 10, 9}
nums = append(nums, nums1...)  // Присоединить список nums1 к концу nums
list.swift
/* Конкатенация двух списков */
let nums1 = [6, 8, 7, 10, 9]
nums.append(contentsOf: nums1) // Присоединить список nums1 к концу nums
list.js
/* Конкатенация двух списков */
const nums1 = [6, 8, 7, 10, 9];
nums.push(...nums1);  // Присоединить список nums1 к концу nums
list.ts
/* Конкатенация двух списков */
const nums1: number[] = [6, 8, 7, 10, 9];
nums.push(...nums1);  // Присоединить список nums1 к концу nums
list.dart
/* Конкатенация двух списков */
List<int> nums1 = [6, 8, 7, 10, 9];
nums.addAll(nums1);  // Присоединить список nums1 к концу nums
list.rs
/* Конкатенация двух списков */
let nums1: Vec<i32> = vec![6, 8, 7, 10, 9];
nums.extend(nums1);
list.c
// В C нет встроенного динамического массива
list.kt
/* Конкатенация двух списков */
val nums1 = intArrayOf(6, 8, 7, 10, 9).toMutableList()
nums.addAll(nums1)  // Присоединить список nums1 к концу nums
list.rb
# Конкатенация двух списков
nums1 = [6, 8, 7, 10, 9]
nums += nums1
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%9E%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B8%D1%82%D1%8C%20%D0%B4%D0%B2%D0%B0%20%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0%0A%20%20%20%20nums1%20%3D%20%5B6%2C%208%2C%207%2C%2010%2C%209%5D%0A%20%20%20%20nums%20%2B%3D%20nums1%20%20%23%20%D0%9F%D1%80%D0%B8%D1%81%D0%BE%D0%B5%D0%B4%D0%B8%D0%BD%D0%B8%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20nums1%20%D0%BA%20nums&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

6.   Сортировка списка

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

list.py
# Отсортировать список
nums.sort()  # После сортировки элементы списка идут по возрастанию
list.cpp
/* Отсортировать список */
sort(nums.begin(), nums.end());  // После сортировки элементы списка идут по возрастанию
list.java
/* Отсортировать список */
Collections.sort(nums);  // После сортировки элементы списка идут по возрастанию
list.cs
/* Отсортировать список */
nums.Sort(); // После сортировки элементы списка идут по возрастанию
list_test.go
/* Отсортировать список */
sort.Ints(nums)  // После сортировки элементы списка идут по возрастанию
list.swift
/* Отсортировать список */
nums.sort() // После сортировки элементы списка идут по возрастанию
list.js
/* Отсортировать список */
nums.sort((a, b) => a - b);  // После сортировки элементы списка идут по возрастанию
list.ts
/* Отсортировать список */
nums.sort((a, b) => a - b);  // После сортировки элементы списка идут по возрастанию
list.dart
/* Отсортировать список */
nums.sort(); // После сортировки элементы списка идут по возрастанию
list.rs
/* Отсортировать список */
nums.sort(); // После сортировки элементы списка идут по возрастанию
list.c
// В C нет встроенного динамического массива
list.kt
/* Отсортировать список */
nums.sort() // После сортировки элементы списка идут по возрастанию
list.rb
# Отсортировать список
nums = nums.sort { |a, b| a <=> b } # После сортировки элементы списка идут по возрастанию
Визуализация выполнения

https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%D0%9E%D1%82%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%0A%20%20%20%20nums.sort%28%29%20%20%23%20%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%2C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D1%80%D0%B0%D1%81%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D1%8B%20%D0%BF%D0%BE%20%D0%B2%D0%BE%D0%B7%D1%80%D0%B0%D1%81%D1%82%D0%B0%D0%BD%D0%B8%D1%8E&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

4.3.2   Реализация списка

Во многих языках программирования списки встроены в стандартную библиотеку, например в Java, C++ и Python. Их реализация довольно сложна, а настройки параметров тщательно продуманы: начальная емкость, коэффициент расширения и так далее. Если тебе интересно, стоит заглянуть в исходный код.

Чтобы лучше понять принцип работы списка, попробуем реализовать его упрощенную версию, в которой есть три ключевых аспекта проектирования.

  • Начальная емкость: выбрать разумную начальную емкость внутреннего массива. В этом примере мы берем 10.
  • Учет количества элементов: объявить переменную size , которая будет хранить текущее число элементов в списке и обновляться в реальном времени при вставке и удалении элементов. С помощью этой переменной можно находить конец списка и понимать, требуется ли расширение.
  • Механизм расширения: если при вставке элементов емкость списка исчерпана, нужно выполнить расширение. Для этого сначала создается больший массив с учетом коэффициента расширения, а затем все элементы текущего массива по порядку переносятся в новый. В этом примере мы считаем, что каждый раз массив расширяется в 2 раза.
my_list.py
class MyList:
    """Класс списка"""

    def __init__(self):
        """Конструктор"""
        self._capacity: int = 10  # Вместимость списка
        self._arr: list[int] = [0] * self._capacity  # Массив (для хранения элементов списка)
        self._size: int = 0  # Длина списка (текущее число элементов)
        self._extend_ratio: int = 2  # Коэффициент увеличения списка при каждом расширении

    def size(self) -> int:
        """Получить длину списка (текущее число элементов)"""
        return self._size

    def capacity(self) -> int:
        """Получить вместимость списка"""
        return self._capacity

    def get(self, index: int) -> int:
        """Доступ к элементу"""
        # Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if index < 0 or index >= self._size:
            raise IndexError("индекс выходит за границы")
        return self._arr[index]

    def set(self, num: int, index: int):
        """Обновление элемента"""
        if index < 0 or index >= self._size:
            raise IndexError("индекс выходит за границы")
        self._arr[index] = num

    def add(self, num: int):
        """Добавление элемента в конец"""
        # При превышении вместимости по числу элементов запускается расширение
        if self.size() == self.capacity():
            self.extend_capacity()
        self._arr[self._size] = num
        self._size += 1

    def insert(self, num: int, index: int):
        """Вставка элемента в середину"""
        if index < 0 or index >= self._size:
            raise IndexError("индекс выходит за границы")
        # При превышении вместимости по числу элементов запускается расширение
        if self._size == self.capacity():
            self.extend_capacity()
        # Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for j in range(self._size - 1, index - 1, -1):
            self._arr[j + 1] = self._arr[j]
        self._arr[index] = num
        # Обновить число элементов
        self._size += 1

    def remove(self, index: int) -> int:
        """Удаление элемента"""
        if index < 0 or index >= self._size:
            raise IndexError("индекс выходит за границы")
        num = self._arr[index]
        # Сдвинуть все элементы после индекса index на одну позицию вперед
        for j in range(index, self._size - 1):
            self._arr[j] = self._arr[j + 1]
        # Обновить число элементов
        self._size -= 1
        # Вернуть удаленный элемент
        return num

    def extend_capacity(self):
        """Расширение списка"""
        # Создать новый массив длиной в _extend_ratio раз больше исходного массива и скопировать в него исходный массив
        self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1)
        # Обновить вместимость списка
        self._capacity = len(self._arr)

    def to_array(self) -> list[int]:
        """Вернуть список фактической длины"""
        return self._arr[: self._size]
my_list.cpp
/* Класс списка */
class MyList {
  private:
    int *arr;             // Массив (для хранения элементов списка)
    int arrCapacity = 10; // Вместимость списка
    int arrSize = 0;      // Длина списка (текущее число элементов)
    int extendRatio = 2;   // Коэффициент увеличения списка при каждом расширении

  public:
    /* Конструктор */
    MyList() {
        arr = new int[arrCapacity];
    }

    /* Метод-деструктор */
    ~MyList() {
        delete[] arr;
    }

    /* Получить длину списка (текущее число элементов) */
    int size() {
        return arrSize;
    }

    /* Получить вместимость списка */
    int capacity() {
        return arrCapacity;
    }

    /* Доступ к элементу */
    int get(int index) {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= size())
            throw out_of_range("индекс выходит за границы");
        return arr[index];
    }

    /* Обновление элемента */
    void set(int index, int num) {
        if (index < 0 || index >= size())
            throw out_of_range("индекс выходит за границы");
        arr[index] = num;
    }

    /* Добавление элемента в конец */
    void add(int num) {
        // При превышении вместимости по числу элементов запускается расширение
        if (size() == capacity())
            extendCapacity();
        arr[size()] = num;
        // Обновить число элементов
        arrSize++;
    }

    /* Вставка элемента в середину */
    void insert(int index, int num) {
        if (index < 0 || index >= size())
            throw out_of_range("индекс выходит за границы");
        // При превышении вместимости по числу элементов запускается расширение
        if (size() == capacity())
            extendCapacity();
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (int j = size() - 1; j >= index; j--) {
            arr[j + 1] = arr[j];
        }
        arr[index] = num;
        // Обновить число элементов
        arrSize++;
    }

    /* Удаление элемента */
    int remove(int index) {
        if (index < 0 || index >= size())
            throw out_of_range("индекс выходит за границы");
        int num = arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (int j = index; j < size() - 1; j++) {
            arr[j] = arr[j + 1];
        }
        // Обновить число элементов
        arrSize--;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    void extendCapacity() {
        // Создать новый массив длиной в extendRatio раз больше исходного массива
        int newCapacity = capacity() * extendRatio;
        int *tmp = arr;
        arr = new int[newCapacity];
        // Скопировать все элементы исходного массива в новый массив
        for (int i = 0; i < size(); i++) {
            arr[i] = tmp[i];
        }
        // Освободить память
        delete[] tmp;
        arrCapacity = newCapacity;
    }

    /* Преобразовать список в Vector для вывода */
    vector<int> toVector() {
        // Преобразовывать только элементы списка в пределах фактической длины
        vector<int> vec(size());
        for (int i = 0; i < size(); i++) {
            vec[i] = arr[i];
        }
        return vec;
    }
};
my_list.java
/* Класс списка */
class MyList {
    private int[] arr; // Массив (для хранения элементов списка)
    private int capacity = 10; // Вместимость списка
    private int size = 0; // Длина списка (текущее число элементов)
    private int extendRatio = 2; // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    public MyList() {
        arr = new int[capacity];
    }

    /* Получить длину списка (текущее число элементов) */
    public int size() {
        return size;
    }

    /* Получить вместимость списка */
    public int capacity() {
        return capacity;
    }

    /* Доступ к элементу */
    public int get(int index) {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("индекс выходит за границы");
        return arr[index];
    }

    /* Обновление элемента */
    public void set(int index, int num) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("индекс выходит за границы");
        arr[index] = num;
    }

    /* Добавление элемента в конец */
    public void add(int num) {
        // При превышении вместимости по числу элементов запускается расширение
        if (size == capacity())
            extendCapacity();
        arr[size] = num;
        // Обновить число элементов
        size++;
    }

    /* Вставка элемента в середину */
    public void insert(int index, int num) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("индекс выходит за границы");
        // При превышении вместимости по числу элементов запускается расширение
        if (size == capacity())
            extendCapacity();
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (int j = size - 1; j >= index; j--) {
            arr[j + 1] = arr[j];
        }
        arr[index] = num;
        // Обновить число элементов
        size++;
    }

    /* Удаление элемента */
    public int remove(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("индекс выходит за границы");
        int num = arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (int j = index; j < size - 1; j++) {
            arr[j] = arr[j + 1];
        }
        // Обновить число элементов
        size--;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    public void extendCapacity() {
        // Создать новый массив длиной в extendRatio раз больше исходного и скопировать в него исходный массив
        arr = Arrays.copyOf(arr, capacity() * extendRatio);
        // Обновить вместимость списка
        capacity = arr.length;
    }

    /* Преобразовать список в массив */
    public int[] toArray() {
        int size = size();
        // Преобразовывать только элементы списка в пределах фактической длины
        int[] arr = new int[size];
        for (int i = 0; i < size; i++) {
            arr[i] = get(i);
        }
        return arr;
    }
}
my_list.cs
/* Класс списка */
class MyList {
    private int[] arr;           // Массив (для хранения элементов списка)
    private int arrCapacity = 10;    // Вместимость списка
    private int arrSize = 0;         // Длина списка (текущее число элементов)
    private readonly int extendRatio = 2;  // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    public MyList() {
        arr = new int[arrCapacity];
    }

    /* Получить длину списка (текущее число элементов) */
    public int Size() {
        return arrSize;
    }

    /* Получить вместимость списка */
    public int Capacity() {
        return arrCapacity;
    }

    /* Доступ к элементу */
    public int Get(int index) {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= arrSize)
            throw new IndexOutOfRangeException("индекс выходит за границы");
        return arr[index];
    }

    /* Обновление элемента */
    public void Set(int index, int num) {
        if (index < 0 || index >= arrSize)
            throw new IndexOutOfRangeException("индекс выходит за границы");
        arr[index] = num;
    }

    /* Добавление элемента в конец */
    public void Add(int num) {
        // При превышении вместимости по числу элементов запускается расширение
        if (arrSize == arrCapacity)
            ExtendCapacity();
        arr[arrSize] = num;
        // Обновить число элементов
        arrSize++;
    }

    /* Вставка элемента в середину */
    public void Insert(int index, int num) {
        if (index < 0 || index >= arrSize)
            throw new IndexOutOfRangeException("индекс выходит за границы");
        // При превышении вместимости по числу элементов запускается расширение
        if (arrSize == arrCapacity)
            ExtendCapacity();
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (int j = arrSize - 1; j >= index; j--) {
            arr[j + 1] = arr[j];
        }
        arr[index] = num;
        // Обновить число элементов
        arrSize++;
    }

    /* Удаление элемента */
    public int Remove(int index) {
        if (index < 0 || index >= arrSize)
            throw new IndexOutOfRangeException("индекс выходит за границы");
        int num = arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (int j = index; j < arrSize - 1; j++) {
            arr[j] = arr[j + 1];
        }
        // Обновить число элементов
        arrSize--;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    public void ExtendCapacity() {
        // Создать новый массив длиной arrCapacity * extendRatio и скопировать в него исходный массив
        Array.Resize(ref arr, arrCapacity * extendRatio);
        // Обновить вместимость списка
        arrCapacity = arr.Length;
    }

    /* Преобразовать список в массив */
    public int[] ToArray() {
        // Преобразовывать только элементы списка в пределах фактической длины
        int[] arr = new int[arrSize];
        for (int i = 0; i < arrSize; i++) {
            arr[i] = Get(i);
        }
        return arr;
    }
}
my_list.go
/* Класс списка */
type myList struct {
    arrCapacity int
    arr         []int
    arrSize     int
    extendRatio int
}

/* Конструктор */
func newMyList() *myList {
    return &myList{
        arrCapacity: 10,              // Вместимость списка
        arr:         make([]int, 10), // Массив (для хранения элементов списка)
        arrSize:     0,               // Длина списка (текущее число элементов)
        extendRatio: 2,               // Коэффициент увеличения списка при каждом расширении
    }
}

/* Получить длину списка (текущее число элементов) */
func (l *myList) size() int {
    return l.arrSize
}

/* Получить вместимость списка */
func (l *myList) capacity() int {
    return l.arrCapacity
}

/* Доступ к элементу */
func (l *myList) get(index int) int {
    // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
    if index < 0 || index >= l.arrSize {
        panic("индекс выходит за границы")
    }
    return l.arr[index]
}

/* Обновление элемента */
func (l *myList) set(num, index int) {
    if index < 0 || index >= l.arrSize {
        panic("индекс выходит за границы")
    }
    l.arr[index] = num
}

/* Добавление элемента в конец */
func (l *myList) add(num int) {
    // При превышении вместимости по числу элементов запускается расширение
    if l.arrSize == l.arrCapacity {
        l.extendCapacity()
    }
    l.arr[l.arrSize] = num
    // Обновить число элементов
    l.arrSize++
}

/* Вставка элемента в середину */
func (l *myList) insert(num, index int) {
    if index < 0 || index >= l.arrSize {
        panic("индекс выходит за границы")
    }
    // При превышении вместимости по числу элементов запускается расширение
    if l.arrSize == l.arrCapacity {
        l.extendCapacity()
    }
    // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
    for j := l.arrSize - 1; j >= index; j-- {
        l.arr[j+1] = l.arr[j]
    }
    l.arr[index] = num
    // Обновить число элементов
    l.arrSize++
}

/* Удаление элемента */
func (l *myList) remove(index int) int {
    if index < 0 || index >= l.arrSize {
        panic("индекс выходит за границы")
    }
    num := l.arr[index]
    // Сдвинуть все элементы после индекса index на одну позицию вперед
    for j := index; j < l.arrSize-1; j++ {
        l.arr[j] = l.arr[j+1]
    }
    // Обновить число элементов
    l.arrSize--
    // Вернуть удаленный элемент
    return num
}

/* Расширение списка */
func (l *myList) extendCapacity() {
    // Создать новый массив длиной в extendRatio раз больше исходного и скопировать в него исходный массив
    l.arr = append(l.arr, make([]int, l.arrCapacity*(l.extendRatio-1))...)
    // Обновить вместимость списка
    l.arrCapacity = len(l.arr)
}

/* Вернуть список фактической длины */
func (l *myList) toArray() []int {
    // Преобразовывать только элементы списка в пределах фактической длины
    return l.arr[:l.arrSize]
}
my_list.swift
/* Класс списка */
class MyList {
    private var arr: [Int] // Массив (для хранения элементов списка)
    private var _capacity: Int // Вместимость списка
    private var _size: Int // Длина списка (текущее число элементов)
    private let extendRatio: Int // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    init() {
        _capacity = 10
        _size = 0
        extendRatio = 2
        arr = Array(repeating: 0, count: _capacity)
    }

    /* Получить длину списка (текущее число элементов) */
    func size() -> Int {
        _size
    }

    /* Получить вместимость списка */
    func capacity() -> Int {
        _capacity
    }

    /* Доступ к элементу */
    func get(index: Int) -> Int {
        // Если индекс выходит за границы, выбросить ошибку; далее аналогично
        if index < 0 || index >= size() {
            fatalError("индекс выходит за границы")
        }
        return arr[index]
    }

    /* Обновление элемента */
    func set(index: Int, num: Int) {
        if index < 0 || index >= size() {
            fatalError("индекс выходит за границы")
        }
        arr[index] = num
    }

    /* Добавление элемента в конец */
    func add(num: Int) {
        // При превышении вместимости по числу элементов запускается расширение
        if size() == capacity() {
            extendCapacity()
        }
        arr[size()] = num
        // Обновить число элементов
        _size += 1
    }

    /* Вставка элемента в середину */
    func insert(index: Int, num: Int) {
        if index < 0 || index >= size() {
            fatalError("индекс выходит за границы")
        }
        // При превышении вместимости по числу элементов запускается расширение
        if size() == capacity() {
            extendCapacity()
        }
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for j in (index ..< size()).reversed() {
            arr[j + 1] = arr[j]
        }
        arr[index] = num
        // Обновить число элементов
        _size += 1
    }

    /* Удаление элемента */
    @discardableResult
    func remove(index: Int) -> Int {
        if index < 0 || index >= size() {
            fatalError("индекс выходит за границы")
        }
        let num = arr[index]
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for j in index ..< (size() - 1) {
            arr[j] = arr[j + 1]
        }
        // Обновить число элементов
        _size -= 1
        // Вернуть удаленный элемент
        return num
    }

    /* Расширение списка */
    func extendCapacity() {
        // Создать новый массив длиной в extendRatio раз больше исходного и скопировать в него исходный массив
        arr = arr + Array(repeating: 0, count: capacity() * (extendRatio - 1))
        // Обновить вместимость списка
        _capacity = arr.count
    }

    /* Преобразовать список в массив */
    func toArray() -> [Int] {
        Array(arr.prefix(size()))
    }
}
my_list.js
/* Класс списка */
class MyList {
    #arr = new Array(); // Массив (для хранения элементов списка)
    #capacity = 10; // Вместимость списка
    #size = 0; // Длина списка (текущее число элементов)
    #extendRatio = 2; // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    constructor() {
        this.#arr = new Array(this.#capacity);
    }

    /* Получить длину списка (текущее число элементов) */
    size() {
        return this.#size;
    }

    /* Получить вместимость списка */
    capacity() {
        return this.#capacity;
    }

    /* Доступ к элементу */
    get(index) {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= this.#size) throw new Error('индекс выходит за границы');
        return this.#arr[index];
    }

    /* Обновление элемента */
    set(index, num) {
        if (index < 0 || index >= this.#size) throw new Error('индекс выходит за границы');
        this.#arr[index] = num;
    }

    /* Добавление элемента в конец */
    add(num) {
        // Если длина равна вместимости, требуется расширение
        if (this.#size === this.#capacity) {
            this.extendCapacity();
        }
        // Добавить новый элемент в конец списка
        this.#arr[this.#size] = num;
        this.#size++;
    }

    /* Вставка элемента в середину */
    insert(index, num) {
        if (index < 0 || index >= this.#size) throw new Error('индекс выходит за границы');
        // При превышении вместимости по числу элементов запускается расширение
        if (this.#size === this.#capacity) {
            this.extendCapacity();
        }
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (let j = this.#size - 1; j >= index; j--) {
            this.#arr[j + 1] = this.#arr[j];
        }
        // Обновить число элементов
        this.#arr[index] = num;
        this.#size++;
    }

    /* Удаление элемента */
    remove(index) {
        if (index < 0 || index >= this.#size) throw new Error('индекс выходит за границы');
        let num = this.#arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (let j = index; j < this.#size - 1; j++) {
            this.#arr[j] = this.#arr[j + 1];
        }
        // Обновить число элементов
        this.#size--;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    extendCapacity() {
        // Создать новый массив длиной в extendRatio раз больше исходного и скопировать в него исходный массив
        this.#arr = this.#arr.concat(
            new Array(this.capacity() * (this.#extendRatio - 1))
        );
        // Обновить вместимость списка
        this.#capacity = this.#arr.length;
    }

    /* Преобразовать список в массив */
    toArray() {
        let size = this.size();
        // Преобразовывать только элементы списка в пределах фактической длины
        const arr = new Array(size);
        for (let i = 0; i < size; i++) {
            arr[i] = this.get(i);
        }
        return arr;
    }
}
my_list.ts
/* Класс списка */
class MyList {
    private arr: Array<number>; // Массив (для хранения элементов списка)
    private _capacity: number = 10; // Вместимость списка
    private _size: number = 0; // Длина списка (текущее число элементов)
    private extendRatio: number = 2; // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    constructor() {
        this.arr = new Array(this._capacity);
    }

    /* Получить длину списка (текущее число элементов) */
    public size(): number {
        return this._size;
    }

    /* Получить вместимость списка */
    public capacity(): number {
        return this._capacity;
    }

    /* Доступ к элементу */
    public get(index: number): number {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= this._size) throw new Error('индекс выходит за границы');
        return this.arr[index];
    }

    /* Обновление элемента */
    public set(index: number, num: number): void {
        if (index < 0 || index >= this._size) throw new Error('индекс выходит за границы');
        this.arr[index] = num;
    }

    /* Добавление элемента в конец */
    public add(num: number): void {
        // Если длина равна вместимости, требуется расширение
        if (this._size === this._capacity) this.extendCapacity();
        // Добавить новый элемент в конец списка
        this.arr[this._size] = num;
        this._size++;
    }

    /* Вставка элемента в середину */
    public insert(index: number, num: number): void {
        if (index < 0 || index >= this._size) throw new Error('индекс выходит за границы');
        // При превышении вместимости по числу элементов запускается расширение
        if (this._size === this._capacity) {
            this.extendCapacity();
        }
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (let j = this._size - 1; j >= index; j--) {
            this.arr[j + 1] = this.arr[j];
        }
        // Обновить число элементов
        this.arr[index] = num;
        this._size++;
    }

    /* Удаление элемента */
    public remove(index: number): number {
        if (index < 0 || index >= this._size) throw new Error('индекс выходит за границы');
        let num = this.arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (let j = index; j < this._size - 1; j++) {
            this.arr[j] = this.arr[j + 1];
        }
        // Обновить число элементов
        this._size--;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    public extendCapacity(): void {
        // Создать новый массив длиной size и скопировать в него исходный массив
        this.arr = this.arr.concat(
            new Array(this.capacity() * (this.extendRatio - 1))
        );
        // Обновить вместимость списка
        this._capacity = this.arr.length;
    }

    /* Преобразовать список в массив */
    public toArray(): number[] {
        let size = this.size();
        // Преобразовывать только элементы списка в пределах фактической длины
        const arr = new Array(size);
        for (let i = 0; i < size; i++) {
            arr[i] = this.get(i);
        }
        return arr;
    }
}
my_list.dart
/* Класс списка */
class MyList {
  late List<int> _arr; // Массив (для хранения элементов списка)
  int _capacity = 10; // Вместимость списка
  int _size = 0; // Длина списка (текущее число элементов)
  int _extendRatio = 2; // Коэффициент увеличения списка при каждом расширении

  /* Конструктор */
  MyList() {
    _arr = List.filled(_capacity, 0);
  }

  /* Получить длину списка (текущее число элементов) */
  int size() => _size;

  /* Получить вместимость списка */
  int capacity() => _capacity;

  /* Доступ к элементу */
  int get(int index) {
    if (index >= _size) throw RangeError('индекс выходит за границы');
    return _arr[index];
  }

  /* Обновление элемента */
  void set(int index, int _num) {
    if (index >= _size) throw RangeError('индекс выходит за границы');
    _arr[index] = _num;
  }

  /* Добавление элемента в конец */
  void add(int _num) {
    // При превышении вместимости по числу элементов запускается расширение
    if (_size == _capacity) extendCapacity();
    _arr[_size] = _num;
    // Обновить число элементов
    _size++;
  }

  /* Вставка элемента в середину */
  void insert(int index, int _num) {
    if (index >= _size) throw RangeError('индекс выходит за границы');
    // При превышении вместимости по числу элементов запускается расширение
    if (_size == _capacity) extendCapacity();
    // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
    for (var j = _size - 1; j >= index; j--) {
      _arr[j + 1] = _arr[j];
    }
    _arr[index] = _num;
    // Обновить число элементов
    _size++;
  }

  /* Удаление элемента */
  int remove(int index) {
    if (index >= _size) throw RangeError('индекс выходит за границы');
    int _num = _arr[index];
    // Сдвинуть все элементы после индекса index на одну позицию вперед
    for (var j = index; j < _size - 1; j++) {
      _arr[j] = _arr[j + 1];
    }
    // Обновить число элементов
    _size--;
    // Вернуть удаленный элемент
    return _num;
  }

  /* Расширение списка */
  void extendCapacity() {
    // Создать новый массив длиной в _extendRatio раз больше исходного массива
    final _newNums = List.filled(_capacity * _extendRatio, 0);
    // Скопировать исходный массив в новый массив
    List.copyRange(_newNums, 0, _arr);
    // Обновить ссылку на _arr
    _arr = _newNums;
    // Обновить вместимость списка
    _capacity = _arr.length;
  }

  /* Преобразовать список в массив */
  List<int> toArray() {
    List<int> arr = [];
    for (var i = 0; i < _size; i++) {
      arr.add(get(i));
    }
    return arr;
  }
}
my_list.rs
/* Класс списка */
#[allow(dead_code)]
struct MyList {
    arr: Vec<i32>,       // Массив (для хранения элементов списка)
    capacity: usize,     // Вместимость списка
    size: usize,         // Длина списка (текущее число элементов)
    extend_ratio: usize, // Коэффициент увеличения списка при каждом расширении
}

#[allow(unused, unused_comparisons)]
impl MyList {
    /* Конструктор */
    pub fn new(capacity: usize) -> Self {
        let mut vec = vec![0; capacity];
        Self {
            arr: vec,
            capacity,
            size: 0,
            extend_ratio: 2,
        }
    }

    /* Получить длину списка (текущее число элементов) */
    pub fn size(&self) -> usize {
        return self.size;
    }

    /* Получить вместимость списка */
    pub fn capacity(&self) -> usize {
        return self.capacity;
    }

    /* Доступ к элементу */
    pub fn get(&self, index: usize) -> i32 {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if index >= self.size {
            panic!("индекс выходит за границы")
        };
        return self.arr[index];
    }

    /* Обновление элемента */
    pub fn set(&mut self, index: usize, num: i32) {
        if index >= self.size {
            panic!("индекс выходит за границы")
        };
        self.arr[index] = num;
    }

    /* Добавление элемента в конец */
    pub fn add(&mut self, num: i32) {
        // При превышении вместимости по числу элементов запускается расширение
        if self.size == self.capacity() {
            self.extend_capacity();
        }
        self.arr[self.size] = num;
        // Обновить число элементов
        self.size += 1;
    }

    /* Вставка элемента в середину */
    pub fn insert(&mut self, index: usize, num: i32) {
        if index >= self.size() {
            panic!("индекс выходит за границы")
        };
        // При превышении вместимости по числу элементов запускается расширение
        if self.size == self.capacity() {
            self.extend_capacity();
        }
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for j in (index..self.size).rev() {
            self.arr[j + 1] = self.arr[j];
        }
        self.arr[index] = num;
        // Обновить число элементов
        self.size += 1;
    }

    /* Удаление элемента */
    pub fn remove(&mut self, index: usize) -> i32 {
        if index >= self.size() {
            panic!("индекс выходит за границы")
        };
        let num = self.arr[index];
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for j in index..self.size - 1 {
            self.arr[j] = self.arr[j + 1];
        }
        // Обновить число элементов
        self.size -= 1;
        // Вернуть удаленный элемент
        return num;
    }

    /* Расширение списка */
    pub fn extend_capacity(&mut self) {
        // Создать новый массив длиной в extend_ratio раз больше исходного и скопировать в него исходный массив
        let new_capacity = self.capacity * self.extend_ratio;
        self.arr.resize(new_capacity, 0);
        // Обновить вместимость списка
        self.capacity = new_capacity;
    }

    /* Преобразовать список в массив */
    pub fn to_array(&self) -> Vec<i32> {
        // Преобразовывать только элементы списка в пределах фактической длины
        let mut arr = Vec::new();
        for i in 0..self.size {
            arr.push(self.get(i));
        }
        arr
    }
}
my_list.c
/* Класс списка */
typedef struct {
    int *arr;        // Массив (для хранения элементов списка)
    int capacity;    // Вместимость списка
    int size;        // Размер списка
    int extendRatio; // Коэффициент расширения списка при каждом увеличении
} MyList;

/* Конструктор */
MyList *newMyList() {
    MyList *nums = malloc(sizeof(MyList));
    nums->capacity = 10;
    nums->arr = malloc(sizeof(int) * nums->capacity);
    nums->size = 0;
    nums->extendRatio = 2;
    return nums;
}

/* Деструктор */
void delMyList(MyList *nums) {
    free(nums->arr);
    free(nums);
}

/* Получить длину списка */
int size(MyList *nums) {
    return nums->size;
}

/* Получить вместимость списка */
int capacity(MyList *nums) {
    return nums->capacity;
}

/* Доступ к элементу */
int get(MyList *nums, int index) {
    assert(index >= 0 && index < nums->size);
    return nums->arr[index];
}

/* Обновление элемента */
void set(MyList *nums, int index, int num) {
    assert(index >= 0 && index < nums->size);
    nums->arr[index] = num;
}

/* Добавление элемента в конец */
void add(MyList *nums, int num) {
    if (size(nums) == capacity(nums)) {
        extendCapacity(nums); // Расширение емкости
    }
    nums->arr[size(nums)] = num;
    nums->size++;
}

/* Вставка элемента в середину */
void insert(MyList *nums, int index, int num) {
    assert(index >= 0 && index < size(nums));
    // При превышении вместимости по числу элементов запускается расширение
    if (size(nums) == capacity(nums)) {
        extendCapacity(nums); // Расширение емкости
    }
    for (int i = size(nums); i > index; --i) {
        nums->arr[i] = nums->arr[i - 1];
    }
    nums->arr[index] = num;
    nums->size++;
}

/* Удаление элемента */
// Внимание: stdio.h уже использует ключевое слово remove
int removeItem(MyList *nums, int index) {
    assert(index >= 0 && index < size(nums));
    int num = nums->arr[index];
    for (int i = index; i < size(nums) - 1; i++) {
        nums->arr[i] = nums->arr[i + 1];
    }
    nums->size--;
    return num;
}

/* Расширение списка */
void extendCapacity(MyList *nums) {
    // Сначала выделить память
    int newCapacity = capacity(nums) * nums->extendRatio;
    int *extend = (int *)malloc(sizeof(int) * newCapacity);
    int *temp = nums->arr;

    // Скопировать старые данные в новые
    for (int i = 0; i < size(nums); i++)
        extend[i] = nums->arr[i];

    // Освободить старые данные
    free(temp);

    // Обновить новые данные
    nums->arr = extend;
    nums->capacity = newCapacity;
}

/* Преобразовать список в Array для вывода */
int *toArray(MyList *nums) {
    return nums->arr;
}
my_list.kt
/* Класс списка */
class MyList {
    private var arr: IntArray = intArrayOf() // Массив (для хранения элементов списка)
    private var capacity: Int = 10 // Вместимость списка
    private var size: Int = 0 // Длина списка (текущее число элементов)
    private var extendRatio: Int = 2 // Коэффициент увеличения списка при каждом расширении

    /* Конструктор */
    init {
        arr = IntArray(capacity)
    }

    /* Получить длину списка (текущее число элементов) */
    fun size(): Int {
        return size
    }

    /* Получить вместимость списка */
    fun capacity(): Int {
        return capacity
    }

    /* Доступ к элементу */
    fun get(index: Int): Int {
        // Если индекс выходит за границы, выбрасывается исключение; далее аналогично
        if (index < 0 || index >= size)
            throw IndexOutOfBoundsException("индекс выходит за границы")
        return arr[index]
    }

    /* Обновление элемента */
    fun set(index: Int, num: Int) {
        if (index < 0 || index >= size)
            throw IndexOutOfBoundsException("индекс выходит за границы")
        arr[index] = num
    }

    /* Добавление элемента в конец */
    fun add(num: Int) {
        // При превышении вместимости по числу элементов запускается расширение
        if (size == capacity())
            extendCapacity()
        arr[size] = num
        // Обновить число элементов
        size++
    }

    /* Вставка элемента в середину */
    fun insert(index: Int, num: Int) {
        if (index < 0 || index >= size)
            throw IndexOutOfBoundsException("индекс выходит за границы")
        // При превышении вместимости по числу элементов запускается расширение
        if (size == capacity())
            extendCapacity()
        // Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
        for (j in size - 1 downTo index)
            arr[j + 1] = arr[j]
        arr[index] = num
        // Обновить число элементов
        size++
    }

    /* Удаление элемента */
    fun remove(index: Int): Int {
        if (index < 0 || index >= size)
            throw IndexOutOfBoundsException("индекс выходит за границы")
        val num = arr[index]
        // Сдвинуть все элементы после индекса index на одну позицию вперед
        for (j in index..<size - 1)
            arr[j] = arr[j + 1]
        // Обновить число элементов
        size--
        // Вернуть удаленный элемент
        return num
    }

    /* Расширение списка */
    fun extendCapacity() {
        // Создать новый массив длиной в extendRatio раз больше исходного и скопировать в него исходный массив
        arr = arr.copyOf(capacity() * extendRatio)
        // Обновить вместимость списка
        capacity = arr.size
    }

    /* Преобразовать список в массив */
    fun toArray(): IntArray {
        val size = size()
        // Преобразовывать только элементы списка в пределах фактической длины
        val arr = IntArray(size)
        for (i in 0..<size) {
            arr[i] = get(i)
        }
        return arr
    }
}
my_list.rb
### Класс списка ###
class MyList
  attr_reader :size       # Получить длину списка (текущее число элементов)
  attr_reader :capacity   # Получить вместимость списка

  ### Конструктор ###
  def initialize
    @capacity = 10
    @size = 0
    @extend_ratio = 2
    @arr = Array.new(capacity)
  end

  ### Доступ к элементу ###
  def get(index)
    # Если индекс выходит за границы, выбрасывается исключение; далее аналогично
    raise IndexError, "индекс выходит за границы" if index < 0 || index >= size
    @arr[index]
  end

  ### Доступ к элементу ###
  def set(index, num)
    raise IndexError, "индекс выходит за границы" if index < 0 || index >= size
    @arr[index] = num
  end

  ### Добавление элемента в конец ###
  def add(num)
    # При превышении вместимости по числу элементов запускается расширение
    extend_capacity if size == capacity
    @arr[size] = num

    # Обновить число элементов
    @size += 1
  end

  ### Вставка элемента в середину ###
  def insert(index, num)
    raise IndexError, "индекс выходит за границы" if index < 0 || index >= size

    # При превышении вместимости по числу элементов запускается расширение
    extend_capacity if size == capacity

    # Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
    for j in (size - 1).downto(index)
      @arr[j + 1] = @arr[j]
    end
    @arr[index] = num

    # Обновить число элементов
    @size += 1
  end

  ### Удаление элемента ###
  def remove(index)
    raise IndexError, "индекс выходит за границы" if index < 0 || index >= size
    num = @arr[index]

    # Сдвинуть все элементы после индекса index на одну позицию вперед
    for j in index...size
      @arr[j] = @arr[j + 1]
    end

    # Обновить число элементов
    @size -= 1

    # Вернуть удаленный элемент
    num
  end

  ### Расширение списка ###
  def extend_capacity
    # Создать новый массив длиной в extend_ratio раз больше исходного и скопировать в него исходный массив
    arr = @arr.dup + Array.new(capacity * (@extend_ratio - 1))
    # Обновить вместимость списка
    @capacity = arr.length
  end

  ### Преобразование списка в массив ###
  def to_array
    sz = size
    # Преобразовывать только элементы списка в пределах фактической длины
    arr = Array.new(sz)
    for i in 0...sz
      arr[i] = get(i)
    end
    arr
  end
end
Визуализация кода

Оставляйте свои идеи, вопросы и предложения в комментариях