HTML Diff
1 added 97 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>В этом уроке мы начнем изучать структуры данных и связанные с ними алгоритмы. Чтобы разобраться во всех деталях, мы рассмотрим два примера из реальной жизни - склад и библиотеку.</p>
1 <p>В этом уроке мы начнем изучать структуры данных и связанные с ними алгоритмы. Чтобы разобраться во всех деталях, мы рассмотрим два примера из реальной жизни - склад и библиотеку.</p>
2 <p>На складе кладовщик записывает все пришедшие товары в специальный журнал. Рабочий день кладовщика состоит из приема и выдачи товаров. Очень важно записывать прием и выдачу как можно быстрее, поэтому кладовщик просто пишет все операции друг за другом, подряд.</p>
2 <p>На складе кладовщик записывает все пришедшие товары в специальный журнал. Рабочий день кладовщика состоит из приема и выдачи товаров. Очень важно записывать прием и выдачу как можно быстрее, поэтому кладовщик просто пишет все операции друг за другом, подряд.</p>
3 <p>Из-за специфики работы склада кладовщик составляет базу данных, в которой:</p>
3 <p>Из-за специфики работы склада кладовщик составляет базу данных, в которой:</p>
4 <ul><li>Сложно найти товар на складе</li>
4 <ul><li>Сложно найти товар на складе</li>
5 <li>Просто сделать новую запись в журнале</li>
5 <li>Просто сделать новую запись в журнале</li>
6 - </ul><p>Ситуация в библиотеке совсем другая. Основная работа библиотекаря - поиск книг по фамилии автора, по названию книги или по тематике. Для быстрого поиска книг библиотекаи используют картотеку. Для каждой книги заводятся несколько карточек и размещаются в разных ящиках. В одном они упорядочены по фамилии автора, в другом - по названию. Благодаря порядку карточки ищутся очень быстро.</p>
6 + </ul><p>Ситуация в библиотеке совсем другая. Основная работа библиотекаря - поиск книг по фамилии автора, по названию книги или по тематике. Для быстрого поиска книг библиотекари используют картотеку. Для каждой книги заводятся несколько карточек и размещаются в разных ящиках. В одном они упорядочены по фамилии автора, в другом - по названию. Благодаря порядку карточки ищутся очень быстро.</p>
7 <p>Так в библиотеке составляется база данных с совсем другими свойствами:</p>
7 <p>Так в библиотеке составляется база данных с совсем другими свойствами:</p>
8 <ul><li>Просто найти книгу в библиотеке</li>
8 <ul><li>Просто найти книгу в библиотеке</li>
9 <li>Сложно сделать новую запись в картотеке</li>
9 <li>Сложно сделать новую запись в картотеке</li>
10 </ul><p>И на складе, и в библиотеке нам приходится записывать и искать похожую информацию, однако скорость записи и поиска получается разная:</p>
10 </ul><p>И на складе, и в библиотеке нам приходится записывать и искать похожую информацию, однако скорость записи и поиска получается разная:</p>
11 <p>Как видите, мы не можем выбрать один универсальный способ записи, который подойдет для всех случаев. Для склада больше подходит Журнал, а для библиотеки - Картотека.</p>
11 <p>Как видите, мы не можем выбрать один универсальный способ записи, который подойдет для всех случаев. Для склада больше подходит Журнал, а для библиотеки - Картотека.</p>
12 <p>В обоих примерах своя<strong>структура данных</strong>- то есть способ хранения данных в памяти компьютера. Для каждой структуры существует набор основных операций - добавление, поиск, удаление. Из-за особенностей структуры, добавление и поиск могут быть быстрыми или медленными.</p>
12 <p>В обоих примерах своя<strong>структура данных</strong>- то есть способ хранения данных в памяти компьютера. Для каждой структуры существует набор основных операций - добавление, поиск, удаление. Из-за особенностей структуры, добавление и поиск могут быть быстрыми или медленными.</p>
13 <p>Программисты изучают основные структуры данных и запоминают скорость основных операций. Это помогает им выбирать самые подходящие структуры для решения задач пользователя. В этом уроке мы познакомимся со связным списком и сравним его с массивом.</p>
13 <p>Программисты изучают основные структуры данных и запоминают скорость основных операций. Это помогает им выбирать самые подходящие структуры для решения задач пользователя. В этом уроке мы познакомимся со связным списком и сравним его с массивом.</p>
14 <h2>Как устроен массив</h2>
14 <h2>Как устроен массив</h2>
15 <p>Чтобы освоиться с понятием структуры данных и ее операциями, давайте исследуем структуру, которая нам хорошо известна - массив.</p>
15 <p>Чтобы освоиться с понятием структуры данных и ее операциями, давайте исследуем структуру, которая нам хорошо известна - массив.</p>
16 <p>В JavaScript все данные относятся к примитивным или ссылочных типам. Числа и булевы значения хранятся непосредственно в переменных:</p>
16 <p>В JavaScript все данные относятся к примитивным или ссылочных типам. Числа и булевы значения хранятся непосредственно в переменных:</p>
17 - <p><strong>Javascript</strong></p>
 
18 - <p><strong>Python</strong></p>
 
19 - <p><strong>PHP</strong></p>
 
20 - <p><strong>Java</strong></p>
 
21 <p>Массивы и объекты - это ссылочные типы, которые хранятся в памяти отдельно. Область хранения называется кучей, и в начале работы программы она пуста:</p>
17 <p>Массивы и объекты - это ссылочные типы, которые хранятся в памяти отдельно. Область хранения называется кучей, и в начале работы программы она пуста:</p>
22 <p>Название "куча" когда-то было сленговым, но прижилось и сейчас используется как официальный термин. Каждая ячейка в куче - это обычная переменная, которая может хранить одно значение. У каждой ячейки есть адрес - ее порядковый номер. Когда мы создаем новый массив, интерпретатор JavaScript размещает его в свободном месте кучи и записывает в переменную адрес массива:</p>
18 <p>Название "куча" когда-то было сленговым, но прижилось и сейчас используется как официальный термин. Каждая ячейка в куче - это обычная переменная, которая может хранить одно значение. У каждой ячейки есть адрес - ее порядковый номер. Когда мы создаем новый массив, интерпретатор JavaScript размещает его в свободном месте кучи и записывает в переменную адрес массива:</p>
23 - <p><strong>Javascript</strong></p>
 
24 - <p><strong>Python</strong></p>
 
25 - <p><strong>PHP</strong></p>
 
26 - <p><strong>Java</strong></p>
 
27 <p>На рисунке вы видите, как хранится массив в памяти. В ячейках с номерами 00, 01 и 02 уже есть какие-то данные - они "заняты", поэтому массив начинается с ячейки 03.</p>
19 <p>На рисунке вы видите, как хранится массив в памяти. В ячейках с номерами 00, 01 и 02 уже есть какие-то данные - они "заняты", поэтому массив начинается с ячейки 03.</p>
28 <p>В самой первой ячейке массива хранится его длина или количество элементов, то есть 4. Затем последовательно хранятся сами значения 5, 8, 12 и 3.</p>
20 <p>В самой первой ячейке массива хранится его длина или количество элементов, то есть 4. Затем последовательно хранятся сами значения 5, 8, 12 и 3.</p>
29 <p>Поскольку элементы массива хранятся последовательно, процессор легко определяет адрес элемента по его порядковому номеру в массиве:</p>
21 <p>Поскольку элементы массива хранятся последовательно, процессор легко определяет адрес элемента по его порядковому номеру в массиве:</p>
30 - <p><strong>Javascript</strong></p>
 
31 - <p><strong>Python</strong></p>
 
32 - <p><strong>PHP</strong></p>
 
33 - <p><strong>Java</strong></p>
 
34 <p>Массив начинается с адреса 03, где хранится длина массива. Нулевой элемент массива items[0] имеет адрес 04, а второй элемент items[2] - адрес 04 + 2, то есть 06. В этой ячейке находится число 12.</p>
22 <p>Массив начинается с адреса 03, где хранится длина массива. Нулевой элемент массива items[0] имеет адрес 04, а второй элемент items[2] - адрес 04 + 2, то есть 06. В этой ячейке находится число 12.</p>
35 <p>Подобные рассуждения могут запутать, поскольку в ячейках хранятся числа, а адреса ячеек - тоже числа. Если чувствуете, что потеряли нить рассуждений, вернитесь немного назад и повторите.</p>
23 <p>Подобные рассуждения могут запутать, поскольку в ячейках хранятся числа, а адреса ячеек - тоже числа. Если чувствуете, что потеряли нить рассуждений, вернитесь немного назад и повторите.</p>
36 <p>Порядковый номер элемента в массиве обычно называют индексом - это название пришло из математики.</p>
24 <p>Порядковый номер элемента в массиве обычно называют индексом - это название пришло из математики.</p>
37 <p>Определение длины массива и обращение к элементу по индексу - две простые операции, которые мы постоянно используем при работе с массивами. Возьмем для примера функцию, которая вычисляет сумму элементов массива:</p>
25 <p>Определение длины массива и обращение к элементу по индексу - две простые операции, которые мы постоянно используем при работе с массивами. Возьмем для примера функцию, которая вычисляет сумму элементов массива:</p>
38 - <p><strong>Javascript</strong></p>
 
39 - <p><strong>Python</strong></p>
 
40 - <p><strong>PHP</strong></p>
 
41 - <p><strong>Java</strong></p>
 
42 <p>Иногда мы хотим расширить массив и добавить к нему несколько элементов. В JavaScript для этого используют метод push():</p>
26 <p>Иногда мы хотим расширить массив и добавить к нему несколько элементов. В JavaScript для этого используют метод push():</p>
43 - <p><strong>Javascript</strong></p>
 
44 - <p><strong>Python</strong></p>
 
45 - <p><strong>PHP</strong></p>
 
46 - <p><strong>Java</strong></p>
 
47 <p>В простом случае, если сразу за массивом есть свободное место, новые элементы попадут туда:</p>
27 <p>В простом случае, если сразу за массивом есть свободное место, новые элементы попадут туда:</p>
48 <p>Мы видим, что длина массива теперь равна шести, и в его конце появились числа 7 и 20. А теперь представим, что программист создал после массива еще несколько объектов и свободной памяти сразу за массивом нет:</p>
28 <p>Мы видим, что длина массива теперь равна шести, и в его конце появились числа 7 и 20. А теперь представим, что программист создал после массива еще несколько объектов и свободной памяти сразу за массивом нет:</p>
49 - <p><strong>Javascript</strong></p>
 
50 - <p><strong>Python</strong></p>
 
51 - <p><strong>PHP</strong></p>
 
52 - <p><strong>Java</strong></p>
 
53 <p>На рисунке сразу за массивом items в куче находится объект point. Кажется, что в этом случае мы не можем расширить массив, ведь элементы должны располагаться в памяти подряд. На самом деле при вызове метода push() интерпретатор копирует весь массив в свободную область памяти и добавляет к ней несколько элементов. Исходная область памяти помечается как свободная:</p>
29 <p>На рисунке сразу за массивом items в куче находится объект point. Кажется, что в этом случае мы не можем расширить массив, ведь элементы должны располагаться в памяти подряд. На самом деле при вызове метода push() интерпретатор копирует весь массив в свободную область памяти и добавляет к ней несколько элементов. Исходная область памяти помечается как свободная:</p>
54 <p>Расширение массива может привести к копированию большого объема данных и замедлению программы. Есть несколько способов борьбы с таким поведением, но копирование все равно случается. Как быть, если нам предстоит часто добавлять и удалять элементы? Можно применить связный список.</p>
30 <p>Расширение массива может привести к копированию большого объема данных и замедлению программы. Есть несколько способов борьбы с таким поведением, но копирование все равно случается. Как быть, если нам предстоит часто добавлять и удалять элементы? Можно применить связный список.</p>
55 <h2>Связный список</h2>
31 <h2>Связный список</h2>
56 <p>Это структура, которая решает проблему производительности, если нам приходится часто добавлять и удалять данные. Данные в связном списке хранятся не подряд, а вразброс.</p>
32 <p>Это структура, которая решает проблему производительности, если нам приходится часто добавлять и удалять данные. Данные в связном списке хранятся не подряд, а вразброс.</p>
57 <p>Каждое значение хранится в отдельном объекте, который называется<strong>узлом</strong>. Помимо значения, объект хранит ссылку на следующий узел списка. В самом последнем узле вместо ссылки на следующий элемент хранится значение null.</p>
33 <p>Каждое значение хранится в отдельном объекте, который называется<strong>узлом</strong>. Помимо значения, объект хранит ссылку на следующий узел списка. В самом последнем узле вместо ссылки на следующий элемент хранится значение null.</p>
58 <p>Опишем класс, содержащий значение (value) и ссылку на следующий узел (next):</p>
34 <p>Опишем класс, содержащий значение (value) и ссылку на следующий узел (next):</p>
59 - <p><strong>Javascript</strong></p>
 
60 - <p><strong>Python</strong></p>
 
61 - <p><strong>PHP</strong></p>
 
62 - <p><strong>Java</strong></p>
 
63 <p>Список из элементов 5, 8, 12 и 3 может быть создан так:</p>
35 <p>Список из элементов 5, 8, 12 и 3 может быть создан так:</p>
64 - <p><strong>Javascript</strong></p>
 
65 - <p><strong>Python</strong></p>
 
66 - <p><strong>PHP</strong></p>
 
67 - <p><strong>Java</strong></p>
 
68 <p>Оператор new не только создает объект, но и выделяет для него место в памяти. Самый первый элемент односвязного списка часто называют головой (head), поэтому и переменную со ссылкой на голову мы назвали head.</p>
36 <p>Оператор new не только создает объект, но и выделяет для него место в памяти. Самый первый элемент односвязного списка часто называют головой (head), поэтому и переменную со ссылкой на голову мы назвали head.</p>
69 <p>В поле next самого последнего узла находится null - значит, узлов больше нет. В отличие от массива, узлы списка не размещаются в памяти подряд:</p>
37 <p>В поле next самого последнего узла находится null - значит, узлов больше нет. В отличие от массива, узлы списка не размещаются в памяти подряд:</p>
70 <p>На рисунке узлы списка занимают две ячейки. В первой хранится значение, а во второй - адрес следующего узла или null. Иногда узлы могут располагаться рядом (на рисунке это 12 и 3), но в общем случае это не так.</p>
38 <p>На рисунке узлы списка занимают две ячейки. В первой хранится значение, а во второй - адрес следующего узла или null. Иногда узлы могут располагаться рядом (на рисунке это 12 и 3), но в общем случае это не так.</p>
71 <p>Вся работа со списком производится через ссылку на его первый элемент, так что переменная head - единственное, что нам нужно для реализации алгоритмов.</p>
39 <p>Вся работа со списком производится через ссылку на его первый элемент, так что переменная head - единственное, что нам нужно для реализации алгоритмов.</p>
72 <p>Поскольку мы пишем на языке JavaScript, который поддерживает объектно-ориентированное программирование, мы объединим поле head и все наши функции в один класс. Он будет называться LinkedList, что в переводе с английского означает связный список. При создании нового списка в поле head хранится значение null, что означает, что список пустой:</p>
40 <p>Поскольку мы пишем на языке JavaScript, который поддерживает объектно-ориентированное программирование, мы объединим поле head и все наши функции в один класс. Он будет называться LinkedList, что в переводе с английского означает связный список. При создании нового списка в поле head хранится значение null, что означает, что список пустой:</p>
73 - <p><strong>Javascript</strong></p>
 
74 - <p><strong>Python</strong></p>
 
75 - <p><strong>PHP</strong></p>
 
76 - <p><strong>Java</strong></p>
 
77 <h2>Вставка элемента в начало списка</h2>
41 <h2>Вставка элемента в начало списка</h2>
78 <p>В простейшем случае, мы вставляем элемент в пустой список. В самом начале значение поля head равно null:</p>
42 <p>В простейшем случае, мы вставляем элемент в пустой список. В самом начале значение поля head равно null:</p>
79 <p>После вставки head указывает на единственный элемент списка:</p>
43 <p>После вставки head указывает на единственный элемент списка:</p>
80 <p>Мы не рисуем кучу целиком, потому что в реальной программе трудно предугадать, по какому адресу разместится то или иное значение. Конкретные адреса могут сбить с толку.</p>
44 <p>Мы не рисуем кучу целиком, потому что в реальной программе трудно предугадать, по какому адресу разместится то или иное значение. Конкретные адреса могут сбить с толку.</p>
81 <p>Поэтому мы просто отмечаем факт, что для нового узла списка в куче были выделены две ячейки, и head указывает на этот узел. Адрес первого узла мы запишем, как addr(1), это позволит нам отличать адреса друг от друга.</p>
45 <p>Поэтому мы просто отмечаем факт, что для нового узла списка в куче были выделены две ячейки, и head указывает на этот узел. Адрес первого узла мы запишем, как addr(1), это позволит нам отличать адреса друг от друга.</p>
82 <p>После вставки второго узла в начало списка, картина примет такой вид:</p>
46 <p>После вставки второго узла в начало списка, картина примет такой вид:</p>
83 <p>Теперь addr(1), который находился в head, переместился в узел 2, а в head попал адрес второго узла addr(2).</p>
47 <p>Теперь addr(1), который находился в head, переместился в узел 2, а в head попал адрес второго узла addr(2).</p>
84 <p>В обоих случаях (вставка в пустой и непустой список), сначала мы создаем узел, куда, в качестве указателя на следующий элемент, записываем текущее значение head.</p>
48 <p>В обоих случаях (вставка в пустой и непустой список), сначала мы создаем узел, куда, в качестве указателя на следующий элемент, записываем текущее значение head.</p>
85 <p>Взглянем на код:</p>
49 <p>Взглянем на код:</p>
86 - <p><strong>Javascript</strong></p>
 
87 - <p><strong>Python</strong></p>
 
88 - <p><strong>PHP</strong></p>
 
89 - <p><strong>Java</strong></p>
 
90 <p>Метод add принимает параметр value (значение). Он создает новый узел, помещает туда значение и вставляет узел в начало списка.</p>
50 <p>Метод add принимает параметр value (значение). Он создает новый узел, помещает туда значение и вставляет узел в начало списка.</p>
91 <p>Метод состоит из единственной строки:</p>
51 <p>Метод состоит из единственной строки:</p>
92 - <p><strong>Javascript</strong></p>
 
93 - <p><strong>Python</strong></p>
 
94 - <p><strong>PHP</strong></p>
 
95 - <p><strong>Java</strong></p>
 
96 <p>Здесь мы совместили две операции, которые можно было бы записать в две строки:</p>
52 <p>Здесь мы совместили две операции, которые можно было бы записать в две строки:</p>
97 - <p><strong>Javascript</strong></p>
 
98 - <p><strong>Python</strong></p>
 
99 - <p><strong>PHP</strong></p>
 
100 - <p><strong>Java</strong></p>
 
101 <p>Если первый вариант кода кажется вам сложным, вы можете остановиться на втором. Обычно программисты, по мере чтения кода, привыкают к часто встречающимся конструкциям. Знакомые конструкции уже не кажутся сложными.</p>
53 <p>Если первый вариант кода кажется вам сложным, вы можете остановиться на втором. Обычно программисты, по мере чтения кода, привыкают к часто встречающимся конструкциям. Знакомые конструкции уже не кажутся сложными.</p>
102 <p>Насколько быстро работает метод add? Создание объекта может занимать большое время, но у нас простой конструктор с двумя присваиваниями, поэтому работать он будет быстро.</p>
54 <p>Насколько быстро работает метод add? Создание объекта может занимать большое время, но у нас простой конструктор с двумя присваиваниями, поэтому работать он будет быстро.</p>
103 <p>Время добавления узла в начало всегда одно и то же и не зависит от размера списка, поэтому в данном случае речь идет об алгоритмической сложности O(1).</p>
55 <p>Время добавления узла в начало всегда одно и то же и не зависит от размера списка, поэтому в данном случае речь идет об алгоритмической сложности O(1).</p>
104 <h2>Вставка элемента в середину или конец списка</h2>
56 <h2>Вставка элемента в середину или конец списка</h2>
105 <p>Вставка в середину или конец - сложная операция. В отличие от массива, мы не можем сразу получить второй или пятый узел списка. Мы должны перебрать все узлы с начала, чтобы понять, куда вставить новое значение:</p>
57 <p>Вставка в середину или конец - сложная операция. В отличие от массива, мы не можем сразу получить второй или пятый узел списка. Мы должны перебрать все узлы с начала, чтобы понять, куда вставить новое значение:</p>
106 - <p><strong>Javascript</strong></p>
 
107 - <p><strong>Python</strong></p>
 
108 - <p><strong>PHP</strong></p>
 
109 - <p><strong>Java</strong></p>
 
110 <p>Вызов insert(index, value) означает, что узел со значением value будет вставлен в середину списка в позицию index. Если index равен 0, то значение вставится перед первым элементом - так же, как при вызове add:</p>
58 <p>Вызов insert(index, value) означает, что узел со значением value будет вставлен в середину списка в позицию index. Если index равен 0, то значение вставится перед первым элементом - так же, как при вызове add:</p>
111 - <p><strong>Javascript</strong></p>
 
112 - <p><strong>Python</strong></p>
 
113 - <p><strong>PHP</strong></p>
 
114 - <p><strong>Java</strong></p>
 
115 <p>Если список пустой, index не может быть больше нуля, потому что мы можем вставить значение только в начало списка. Как должна поступать в этом случае функция решает ее автор. Мы можем генерировать ошибку или попытаться выполнить какое-то разумное действие.</p>
59 <p>Если список пустой, index не может быть больше нуля, потому что мы можем вставить значение только в начало списка. Как должна поступать в этом случае функция решает ее автор. Мы можем генерировать ошибку или попытаться выполнить какое-то разумное действие.</p>
116 <p>Пойдем вторым путем - если список пустой, при больших значениях index будем вставлять элемент в самое начало:</p>
60 <p>Пойдем вторым путем - если список пустой, при больших значениях index будем вставлять элемент в самое начало:</p>
117 - <p><strong>Javascript</strong></p>
 
118 - <p><strong>Python</strong></p>
 
119 - <p><strong>PHP</strong></p>
 
120 - <p><strong>Java</strong></p>
 
121 <p>А в случае, если index оказывается за концом списка, будем вставлять элемент в самый конец. Для этого будем проверять два условия: либо мы нашли элемент с номером index, и он не в конце, либо мы достигли последнего элемента:</p>
61 <p>А в случае, если index оказывается за концом списка, будем вставлять элемент в самый конец. Для этого будем проверять два условия: либо мы нашли элемент с номером index, и он не в конце, либо мы достигли последнего элемента:</p>
122 - <p><strong>Javascript</strong></p>
 
123 - <p><strong>Python</strong></p>
 
124 - <p><strong>PHP</strong></p>
 
125 - <p><strong>Java</strong></p>
 
126 <p>Нарисуем, что должно происходить при вставке. Пусть в начале у нас есть список из элементов A и C. Мы хотим вставить элемент B после A, но перед C:</p>
62 <p>Нарисуем, что должно происходить при вставке. Пусть в начале у нас есть список из элементов A и C. Мы хотим вставить элемент B после A, но перед C:</p>
127 <p>Когда цикл заканчивается, переменная current указывается на узел A:</p>
63 <p>Когда цикл заканчивается, переменная current указывается на узел A:</p>
128 <p>После вставки мы получим такую картину:</p>
64 <p>После вставки мы получим такую картину:</p>
129 <p>Перед вставкой в current.next хранится ссылка на C, но теперь она должна переехать в узел B, а в current.next мы запишем ссылку на новый узел B:</p>
65 <p>Перед вставкой в current.next хранится ссылка на C, но теперь она должна переехать в узел B, а в current.next мы запишем ссылку на новый узел B:</p>
130 - <p><strong>Javascript</strong></p>
 
131 - <p><strong>Python</strong></p>
 
132 - <p><strong>PHP</strong></p>
 
133 - <p><strong>Java</strong></p>
 
134 <h2>Поиск элемента</h2>
66 <h2>Поиск элемента</h2>
135 <p>При работе с массивом важное значение имеет индекс элементов. При работе со списком индекс практически не используется, хотя формально мы можем найти третий или семнадцатый узел списка.</p>
67 <p>При работе с массивом важное значение имеет индекс элементов. При работе со списком индекс практически не используется, хотя формально мы можем найти третий или семнадцатый узел списка.</p>
136 <p>Если при поиске элемента в массиве, функции часто возвращают индекс элемента, то для списка - логическое значение true или false.</p>
68 <p>Если при поиске элемента в массиве, функции часто возвращают индекс элемента, то для списка - логическое значение true или false.</p>
137 <p>Вместо ответа на вопрос "если такой элемент в массиве есть, где он находится", функция поиска в списке отвечает на вопрос "есть ли такой элемент в списке":</p>
69 <p>Вместо ответа на вопрос "если такой элемент в массиве есть, где он находится", функция поиска в списке отвечает на вопрос "есть ли такой элемент в списке":</p>
138 - <p><strong>Javascript</strong></p>
 
139 - <p><strong>Python</strong></p>
 
140 - <p><strong>PHP</strong></p>
 
141 - <p><strong>Java</strong></p>
 
142 <p>Здесь у нас простой цикл. Мы пробегаем по всем узлам, пока не натыкаемся на null. Если мы встретили null и не нашли значения, значит, в списке его нет - в конце цикла мы возвращаем false.</p>
70 <p>Здесь у нас простой цикл. Мы пробегаем по всем узлам, пока не натыкаемся на null. Если мы встретили null и не нашли значения, значит, в списке его нет - в конце цикла мы возвращаем false.</p>
143 <p>Если значение находится в одном из узлов, мы прерываем цикл и сразу возвращаем true:</p>
71 <p>Если значение находится в одном из узлов, мы прерываем цикл и сразу возвращаем true:</p>
144 - <p><strong>Javascript</strong></p>
 
145 - <p><strong>Python</strong></p>
 
146 - <p><strong>PHP</strong></p>
 
147 - <p><strong>Java</strong></p>
 
148 <p>В конце цикла важно переходить к следующему узлу, иначе цикл станет бесконечным:</p>
72 <p>В конце цикла важно переходить к следующему узлу, иначе цикл станет бесконечным:</p>
149 - <p><strong>Javascript</strong></p>
 
150 - <p><strong>Python</strong></p>
 
151 - <p><strong>PHP</strong></p>
 
152 - <p><strong>Java</strong></p>
 
153 <h2>Определение длины списка</h2>
73 <h2>Определение длины списка</h2>
154 <p>В отличие от массива, длина списка нам неизвестна, ее нужно вычислить. Мы заводим счетчик и пробегаем по всем узлам списка, увеличивая его на каждой итерации. Длина пустого списка считается равной нулю.</p>
74 <p>В отличие от массива, длина списка нам неизвестна, ее нужно вычислить. Мы заводим счетчик и пробегаем по всем узлам списка, увеличивая его на каждой итерации. Длина пустого списка считается равной нулю.</p>
155 <p>В целом, код получается простой:</p>
75 <p>В целом, код получается простой:</p>
156 - <p><strong>Javascript</strong></p>
 
157 - <p><strong>Python</strong></p>
 
158 - <p><strong>PHP</strong></p>
 
159 - <p><strong>Java</strong></p>
 
160 <p>Переменная result - это наш счетчик. Переменная current на каждой итерации указывает на текущий узел списка. Когда она становится равной null, список пройден до конца. Перейдя к следующему узлу, мы увеличиваем счетчик, поэтому в конце цикла его значение равно количеству узлов.</p>
76 <p>Переменная result - это наш счетчик. Переменная current на каждой итерации указывает на текущий узел списка. Когда она становится равной null, список пройден до конца. Перейдя к следующему узлу, мы увеличиваем счетчик, поэтому в конце цикла его значение равно количеству узлов.</p>
161 <h2>Удаление элемента из начала списка</h2>
77 <h2>Удаление элемента из начала списка</h2>
162 <p>Удаление элемента из начала списка такое же простое, как и вставка. Мы будем возвращать значение из удаленного узла в качестве результата.</p>
78 <p>Удаление элемента из начала списка такое же простое, как и вставка. Мы будем возвращать значение из удаленного узла в качестве результата.</p>
163 <p>Если список пустой, мы не будем ничего удалять, и в качестве результата вернем undefined:</p>
79 <p>Если список пустой, мы не будем ничего удалять, и в качестве результата вернем undefined:</p>
164 - <p><strong>Javascript</strong></p>
 
165 - <p><strong>Python</strong></p>
 
166 - <p><strong>PHP</strong></p>
 
167 - <p><strong>Java</strong></p>
 
168 <p>При удалении в this.head попадает ссылка на следующий узел из первого узла. Когда в списке остается один узел, там находится null. После удаления последнего узла this.head становится равным null, что для нас означает пустой список.</p>
80 <p>При удалении в this.head попадает ссылка на следующий узел из первого узла. Когда в списке остается один узел, там находится null. После удаления последнего узла this.head становится равным null, что для нас означает пустой список.</p>
169 <p>Нам не приходится как-то по-особому описывать этот случай в коде - наш код работает для списков любой длины.</p>
81 <p>Нам не приходится как-то по-особому описывать этот случай в коде - наш код работает для списков любой длины.</p>
170 <p>Рисунки помогут разобраться, как удаляются узлы из списка:</p>
82 <p>Рисунки помогут разобраться, как удаляются узлы из списка:</p>
171 <h2>Удаление элемента из середины или конца списка</h2>
83 <h2>Удаление элемента из середины или конца списка</h2>
172 <p>Теперь, когда мы умеем вставлять элементы в начало и середину списка, и удалять их из начала списка, удаление узлов из середины не должно представлять для нас проблемы.</p>
84 <p>Теперь, когда мы умеем вставлять элементы в начало и середину списка, и удалять их из начала списка, удаление узлов из середины не должно представлять для нас проблемы.</p>
173 <p>Мы просто скомбинируем написанный нами ранее код:</p>
85 <p>Мы просто скомбинируем написанный нами ранее код:</p>
174 - <p><strong>Javascript</strong></p>
 
175 - <p><strong>Python</strong></p>
 
176 - <p><strong>PHP</strong></p>
 
177 - <p><strong>Java</strong></p>
 
178 <p>Единственное нововведение по сравнению с предыдущим кодом заключается в том, что при удалении узла из середины, нам нужно просматривать список на два элемента вперед. Если мы хотим удалить последний узел в списке, нам придется вносить изменения в предпоследний - менять там значение ссылки next.</p>
86 <p>Единственное нововведение по сравнению с предыдущим кодом заключается в том, что при удалении узла из середины, нам нужно просматривать список на два элемента вперед. Если мы хотим удалить последний узел в списке, нам придется вносить изменения в предпоследний - менять там значение ссылки next.</p>
179 <p>Поэтому нам приходится, как особый случай, обрабатывать список из одного элемента. Впрочем, эту проверку мы можем совместить с проверкой на удаление из начала:</p>
87 <p>Поэтому нам приходится, как особый случай, обрабатывать список из одного элемента. Впрочем, эту проверку мы можем совместить с проверкой на удаление из начала:</p>
180 - <p><strong>Javascript</strong></p>
 
181 - <p><strong>Python</strong></p>
 
182 - <p><strong>PHP</strong></p>
 
183 - <p><strong>Java</strong></p>
 
184 <p>Меняется и условие в цикле. Если раньше мы проверяли, что current.next не равен null, то теперь мы проверяем current.next.next. Иными словами, вместо ответа на вопрос "есть ли следующий узел в списке", мы отвечаем на вопрос "есть ли узел за следующим узлом".</p>
88 <p>Меняется и условие в цикле. Если раньше мы проверяли, что current.next не равен null, то теперь мы проверяем current.next.next. Иными словами, вместо ответа на вопрос "есть ли следующий узел в списке", мы отвечаем на вопрос "есть ли узел за следующим узлом".</p>
185 <p>В остальном код остается прежним.</p>
89 <p>В остальном код остается прежним.</p>
186 <h2>Сравнение массива и связного списка</h2>
90 <h2>Сравнение массива и связного списка</h2>
187 <p>Осталось разобраться, в каких случаях использовать массив, а в каких связный список. Об этом нам расскажет таблица, где мы сравним производительность операций:</p>
91 <p>Осталось разобраться, в каких случаях использовать массив, а в каких связный список. Об этом нам расскажет таблица, где мы сравним производительность операций:</p>
188 <p>Поиск и в массиве и в списке не очень быстрый, всего O(n).</p>
92 <p>Поиск и в массиве и в списке не очень быстрый, всего O(n).</p>
189 <p>Образно, массив похож на ежедневник, а связный список - на дневник. В ежедневнике нам важно быстро найти дату, а в дневнике - следующую пустую страницу. Если мы захотим найти все записи на заданную тему, нам придется перечитывать что дневник, что ежедневник.</p>
93 <p>Образно, массив похож на ежедневник, а связный список - на дневник. В ежедневнике нам важно быстро найти дату, а в дневнике - следующую пустую страницу. Если мы захотим найти все записи на заданную тему, нам придется перечитывать что дневник, что ежедневник.</p>
190 <h2>Выводы</h2>
94 <h2>Выводы</h2>
191 <p>В этом уроке мы изучили односвязный список. Повторим важные тезисы из урока:</p>
95 <p>В этом уроке мы изучили односвязный список. Повторим важные тезисы из урока:</p>
192 <ul><li>Структура данных - это способ хранения данных в памяти компьютера. Одни и те же операции могут быть быстрыми для одних структур и медленными для других</li>
96 <ul><li>Структура данных - это способ хранения данных в памяти компьютера. Одни и те же операции могут быть быстрыми для одних структур и медленными для других</li>
193 <li>Сложные структуры данных - объекты и массивы - хранятся в куче.</li>
97 <li>Сложные структуры данных - объекты и массивы - хранятся в куче.</li>
194 <li>Массив не очень хорош, если нам приходится добавлять или удалять элементы. Связный список хорош, если необходимо добавлять новые данные в начало</li>
98 <li>Массив не очень хорош, если нам приходится добавлять или удалять элементы. Связный список хорош, если необходимо добавлять новые данные в начало</li>
195 <li>Определение длины и поиск элемента по индексу быстрее в массиве. Массив и связный список похожи на ежедневник и дневник</li>
99 <li>Определение длины и поиск элемента по индексу быстрее в массиве. Массив и связный список похожи на ежедневник и дневник</li>
196 </ul>
100 </ul>