mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-10 21:16:43 +08:00
build
This commit is contained in:
@@ -138,13 +138,13 @@ comments: true
|
||||
|
||||
### 2. Доступ к элементам
|
||||
|
||||
Элементы массива хранятся в непрерывной области памяти, что упрощает вычисление их адресов. Зная адрес массива в памяти (то есть адрес первого элемента) и индекс некоторого элемента, мы можем по формуле с рисунка ниже вычислить адрес этого элемента и напрямую обратиться к нему.
|
||||
Элементы массива хранятся в непрерывной области памяти, что упрощает вычисление их адресов. Зная адрес массива в памяти (то есть адрес первого элемента) и индекс некоторого элемента, мы можем вычислить адрес этого элемента по формуле, показанной на рисунке 4-2, и напрямую обратиться к нему.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Рисунок 4-2 Вычисление адреса элемента массива </p>
|
||||
|
||||
Если посмотреть на рисунок 4-2, можно заметить, что индекс первого элемента массива равен $0$ , и это кажется не слишком интуитивным, ведь естественнее было бы начинать счет с $1$ . Однако с точки зрения формулы адресации **индекс по сути является смещением относительно адреса памяти**. Смещение первого элемента равно $0$ , поэтому индекс $0$ полностью логичен.
|
||||
Как видно на рисунке 4-2, индекс первого элемента массива равен $0$ , и это кажется не слишком интуитивным, ведь естественнее было бы начинать счет с $1$ . Однако с точки зрения формулы адресации **индекс по сути является смещением относительно адреса памяти**. Смещение первого элемента равно $0$ , поэтому индекс $0$ полностью логичен.
|
||||
|
||||
Доступ к элементам массива очень эффективен: любой элемент массива можно получить за $O(1)$ времени.
|
||||
|
||||
@@ -330,7 +330,7 @@ comments: true
|
||||
|
||||
<p align="center"> Рисунок 4-3 Пример вставки элемента в массив </p>
|
||||
|
||||
Стоит отметить, что длина массива фиксирована, поэтому вставка нового элемента неизбежно приведет к потере элемента на конце массива. Решение этой проблемы мы оставим для обсуждения в разделе о "списках".
|
||||
Стоит отметить, что длина массива фиксирована, поэтому вставка нового элемента неизбежно приведет к потере элемента на конце массива. Решение этой проблемы мы оставим для обсуждения в разделе о «списках».
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -692,7 +692,7 @@ comments: true
|
||||
|
||||
- **Высокая временная сложность**: средняя временная сложность и вставки, и удаления равна $O(n)$ , где $n$ - длина массива.
|
||||
- **Потеря элементов**: поскольку длина массива неизменяема, после вставки элементы, выходящие за пределы длины массива, будут потеряны.
|
||||
- **Потери памяти**: можно заранее инициализировать более длинный массив и использовать только его переднюю часть; тогда теряемые при вставке элементы на конце не будут нести смысла, но такой подход приводит к лишнему расходу памяти.
|
||||
- **Потери памяти**: можно заранее инициализировать более длинный массив и использовать только его переднюю часть. Тогда теряемые при вставке элементы на конце не будут нести смысла, но такой подход приводит к лишнему расходу памяти.
|
||||
|
||||
### 5. Обход массива
|
||||
|
||||
@@ -937,7 +937,7 @@ comments: true
|
||||
|
||||
### 6. Поиск элемента
|
||||
|
||||
Чтобы найти заданный элемент в массиве, нужно пройти по массиву и на каждой итерации проверять, совпадает ли значение; если совпадает, вернуть соответствующий индекс.
|
||||
Чтобы найти заданный элемент в массиве, нужно пройти по массиву и на каждой итерации проверять, совпадает ли значение. Если совпадает, вернуть соответствующий индекс.
|
||||
|
||||
Поскольку массив - это линейная структура данных, такая операция поиска называется линейным поиском.
|
||||
|
||||
@@ -1358,7 +1358,7 @@ comments: true
|
||||
Непрерывное хранение данных - это палка о двух концах, и у него есть следующие ограничения.
|
||||
|
||||
- **Низкая эффективность вставки и удаления**: когда элементов в массиве много, вставка и удаление требуют сдвига большого количества элементов.
|
||||
- **Неизменяемая длина**: после инициализации длина массива фиксирована; расширение массива требует копирования всех данных в новый массив, что стоит дорого.
|
||||
- **Неизменяемая длина**: после инициализации длина массива фиксирована. Расширение массива требует копирования всех данных в новый массив, что стоит дорого.
|
||||
- **Потери памяти**: если выделенный массив больше, чем реально необходимо, лишнее пространство пропадает впустую.
|
||||
|
||||
## 4.1.3 Типичные применения массива
|
||||
|
||||
@@ -423,11 +423,11 @@ comments: true
|
||||
|
||||
https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%D1%81%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%D1%83%D0%B7%D0%B5%D0%BB%D0%BA%D0%BB%D0%B0%D1%81%D1%81%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%D0%97%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D1%83%D0%B7%D0%BB%D0%B0%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%D0%A1%D1%81%D1%8B%D0%BB%D0%BA%D0%B0%20%D0%BD%D0%B0%20%D1%81%D0%BB%D0%B5%D0%B4%D1%83%D1%8E%D1%89%D0%B8%D0%B9%20%D1%83%D0%B7%D0%B5%D0%BB%0A%0A%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%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%201%20-%3E%203%20-%3E%202%20-%3E%205%20-%3E%204%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%D0%BA%D0%B0%D0%B6%D0%B4%D1%8B%D0%B9%20%D1%83%D0%B7%D0%B5%D0%BB%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%D0%9F%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B8%D1%82%D1%8C%20%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B8%20%D0%BC%D0%B5%D0%B6%D0%B4%D1%83%20%D1%83%D0%B7%D0%BB%D0%B0%D0%BC%D0%B8%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false
|
||||
|
||||
Массив в целом - это одна переменная: например, массив `nums` содержит элементы `nums[0]` , `nums[1]` и т.д. Связный список же состоит из множества независимых объектов-узлов. **Обычно в качестве обозначения всего связного списка используют головной узел**; например, в приведенном выше коде связный список можно обозначить как `n0` .
|
||||
Массив в целом - это одна переменная: например, массив `nums` содержит элементы `nums[0]` , `nums[1]` и т.д. Связный список же состоит из множества независимых объектов-узлов. **Обычно в качестве обозначения всего связного списка используют головной узел**. Например, в приведенном выше коде связный список можно обозначить как `n0` .
|
||||
|
||||
### 2. Вставка узла
|
||||
|
||||
Вставить узел в связный список очень легко. Как показано на рисунке 4-6, предположим, что мы хотим вставить новый узел `P` между двумя соседними узлами `n0` и `n1` ; **для этого нужно изменить всего две ссылки (указателя)**, а временная сложность будет равна $O(1)$ .
|
||||
Вставить узел в связный список очень легко. Как показано на рисунке 4-6, предположим, что мы хотим вставить новый узел `P` между двумя соседними узлами `n0` и `n1`. **Для этого нужно изменить всего две ссылки (указателя)**, а временная сложность будет равна $O(1)$ .
|
||||
|
||||
Для сравнения: временная сложность вставки элемента в массив составляет $O(n)$ , и при большом объеме данных это менее эффективно.
|
||||
|
||||
@@ -1450,14 +1450,14 @@ comments: true
|
||||
|
||||
Односвязные списки обычно используются для реализации стеков, очередей, хеш-таблиц и графов.
|
||||
|
||||
- **Стеки и очереди**: если операции вставки и удаления выполняются на одном конце связного списка, он проявляет свойства LIFO, соответствующие стеку; если вставка происходит на одном конце, а удаление на другом, он проявляет свойства FIFO, соответствующие очереди.
|
||||
- **Стеки и очереди**: если операции вставки и удаления выполняются на одном конце связного списка, он проявляет свойства LIFO, соответствующие стеку. Если вставка происходит на одном конце, а удаление на другом, он проявляет свойства FIFO, соответствующие очереди.
|
||||
- **Хеш-таблицы**: метод цепочек - один из основных способов разрешения коллизий в хеш-таблицах. В этом подходе все конфликтующие элементы помещаются в связный список.
|
||||
- **Графы**: список смежности - это распространенный способ представления графа, при котором каждой вершине графа соответствует связный список, а каждый элемент этого списка представляет другую вершину, соединенную с данной.
|
||||
|
||||
Двусвязные списки обычно используются там, где нужен быстрый доступ как к предыдущему, так и к следующему элементу.
|
||||
|
||||
- **Продвинутые структуры данных**: например, в красно-черных деревьях и B-деревьях нам нужен доступ к родительскому узлу; этого можно добиться, сохранив в узле ссылку на родителя, по аналогии с двусвязным списком.
|
||||
- **История браузера**: когда пользователь в браузере нажимает кнопки "вперед" или "назад", браузеру нужно знать предыдущую и следующую посещенные страницы. Свойства двусвязного списка делают такую операцию простой.
|
||||
- **Продвинутые структуры данных**: например, в красно-черных деревьях и B-деревьях нам нужен доступ к родительскому узлу. Этого можно добиться, сохранив в узле ссылку на родителя, по аналогии с двусвязным списком.
|
||||
- **История браузера**: когда пользователь в браузере нажимает кнопки «вперед» или «назад», браузеру нужно знать предыдущую и следующую посещенные страницы. Свойства двусвязного списка делают такую операцию простой.
|
||||
- **Алгоритм LRU**: в алгоритмах вытеснения из кэша (LRU) нужно быстро находить наименее недавно использованные данные, а также быстро добавлять и удалять узлы. Для этого двусвязный список подходит очень хорошо.
|
||||
|
||||
Циклические списки часто применяются в сценариях, требующих циклических операций, например при планировании ресурсов в операционной системе.
|
||||
|
||||
@@ -9,11 +9,11 @@ comments: true
|
||||
- Связный список естественным образом можно рассматривать как список: он поддерживает операции добавления, удаления, поиска и изменения элементов и может гибко расширяться динамически.
|
||||
- Массив тоже поддерживает операции добавления, удаления, поиска и изменения элементов, но из-за неизменяемости длины его можно считать лишь списком с ограниченной длиной.
|
||||
|
||||
Когда список реализуется с помощью массива, **неизменяемость длины снижает его практическую полезность**. Причина в том, что мы обычно не можем заранее точно знать, сколько данных нужно хранить, а значит, трудно выбрать подходящую длину списка. Если длина слишком мала, она может не покрыть реальные потребности; если слишком велика, будет зря расходоваться память.
|
||||
Когда список реализуется с помощью массива, **неизменяемость длины снижает его практическую полезность**. Причина в том, что мы обычно не можем заранее точно знать, сколько данных нужно хранить, а значит, трудно выбрать подходящую длину списка. Если длина слишком мала, она может не покрыть реальные потребности. Если слишком велика, будет зря расходоваться память.
|
||||
|
||||
Чтобы решить эту проблему, можно использовать <u>динамический массив (dynamic array)</u> для реализации списка. Он сохраняет все преимущества массива и при этом может динамически расширяться во время выполнения программы.
|
||||
|
||||
На практике **списки из стандартных библиотек многих языков программирования реализованы именно на основе динамических массивов**, например `list` в Python, `ArrayList` в Java, `vector` в C++ и `List` в C#. В дальнейшем обсуждении мы будем считать понятия "список" и "динамический массив" эквивалентными.
|
||||
На практике **списки из стандартных библиотек многих языков программирования реализованы именно на основе динамических массивов**, например `list` в Python, `ArrayList` в Java, `vector` в C++ и `List` в C#. В дальнейшем обсуждении мы будем считать понятия «список» и «динамический массив» эквивалентными.
|
||||
|
||||
## 4.3.1 Основные операции со списком
|
||||
|
||||
@@ -854,7 +854,7 @@ comments: true
|
||||
|
||||
### 6. Сортировка списка
|
||||
|
||||
После сортировки списка мы сможем применять алгоритмы "двоичный поиск" и "два указателя", которые очень часто встречаются в задачах по массивам.
|
||||
После сортировки списка мы сможем применять алгоритмы «двоичный поиск» и «два указателя», которые очень часто встречаются в задачах по массивам.
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ comments: true
|
||||
|
||||
Хотя по объему кэш намного меньше оперативной памяти, он значительно быстрее и играет критически важную роль в скорости выполнения программ. Поскольку объем кэша ограничен и в нем можно хранить только небольшую долю часто используемых данных, когда CPU пытается обратиться к данным, которых в кэше нет, происходит <u>промах кэша (cache miss)</u> , и CPU вынужден загружать нужные данные из более медленной памяти.
|
||||
|
||||
Очевидно, что **чем меньше промахов кэша, тем выше эффективность чтения и записи данных CPU**, а значит, тем лучше производительность программы. Долю обращений, при которых CPU успешно получает данные из кэша, называют <u>коэффициентом попадания в кэш (cache hit rate)</u> ; этот показатель обычно используют для оценки эффективности кэша.
|
||||
Очевидно, что **чем меньше промахов кэша, тем выше эффективность чтения и записи данных CPU**, а значит, тем лучше производительность программы. Долю обращений, при которых CPU успешно получает данные из кэша, называют <u>коэффициентом попадания в кэш (cache hit rate)</u>. Этот показатель обычно используют для оценки эффективности кэша.
|
||||
|
||||
Чтобы добиться как можно большей эффективности, кэш использует следующие механизмы загрузки данных.
|
||||
|
||||
@@ -77,7 +77,7 @@ comments: true
|
||||
|
||||
В целом **массивы имеют более высокий коэффициент попадания в кэш, поэтому по эффективности операций они обычно превосходят связные списки**. Именно поэтому при решении алгоритмических задач структуры данных на основе массивов часто оказываются предпочтительнее.
|
||||
|
||||
Важно понимать, что **высокая эффективность кэша не означает, что массивы во всех случаях лучше связных списков**. В реальных приложениях выбор структуры данных должен определяться конкретными требованиями. Например, и массивы, и списки могут использоваться для реализации "стека" (подробнее об этом будет рассказано в следующей главе), но подходят они для разных сценариев.
|
||||
Важно понимать, что **высокая эффективность кэша не означает, что массивы во всех случаях лучше связных списков**. В реальных приложениях выбор структуры данных должен определяться конкретными требованиями. Например, и массивы, и списки могут использоваться для реализации «стека» (подробнее об этом будет рассказано в следующей главе), но подходят они для разных сценариев.
|
||||
|
||||
- При решении алгоритмических задач мы обычно предпочитаем стек на основе массива, потому что он дает более высокую эффективность операций и поддерживает произвольный доступ, а цена за это - необходимость заранее выделить некоторый объем памяти под массив.
|
||||
- Если объем данных очень велик, структура сильно динамична, а ожидаемый размер стека трудно оценить заранее, то более уместен стек на основе связного списка. Список позволяет распределить большой объем данных по разным участкам памяти и избегает накладных расходов, связанных с расширением массива.
|
||||
|
||||
@@ -7,8 +7,8 @@ comments: true
|
||||
### 1. Ключевые выводы
|
||||
|
||||
- Массивы и связные списки - это две базовые структуры данных, представляющие два способа хранения данных в памяти компьютера: хранение в непрерывном пространстве и хранение в разрозненном пространстве. Их свойства во многом взаимно дополняют друг друга.
|
||||
- Массив поддерживает произвольный доступ и занимает меньше памяти; однако вставка и удаление элементов в нем неэффективны, а длина после инициализации фиксирована.
|
||||
- Связный список позволяет эффективно вставлять и удалять узлы путем изменения ссылок (указателей), а также гибко менять длину; однако доступ к узлам менее эффективен, а памяти он занимает больше. Распространенные типы списков включают односвязные, циклические и двусвязные списки.
|
||||
- Массив поддерживает произвольный доступ и занимает меньше памяти. Однако вставка и удаление элементов в нем неэффективны, а длина после инициализации фиксирована.
|
||||
- Связный список позволяет эффективно вставлять и удалять узлы путем изменения ссылок (указателей), а также гибко менять длину. Однако доступ к узлам менее эффективен, а памяти он занимает больше. Распространенные типы списков включают односвязные, циклические и двусвязные списки.
|
||||
- Список - это упорядоченная коллекция элементов, поддерживающая добавление, удаление, поиск и изменение, и обычно реализуемая на основе динамического массива. Он сохраняет преимущества массива и при этом может гибко менять длину.
|
||||
- Появление списка значительно повысило практическую ценность массива, хотя это и может приводить к потере части памяти.
|
||||
- Во время работы программы данные в основном хранятся в оперативной памяти. Массив обеспечивает более высокую эффективность использования пространства памяти, а связный список дает большую гибкость в использовании памяти.
|
||||
@@ -21,7 +21,7 @@ comments: true
|
||||
|
||||
Массивы, расположенные и в стеке, и в куче, все равно хранятся в непрерывной области памяти, поэтому эффективность операций с данными у них в целом одинакова. Однако у стека и кучи есть собственные особенности, из-за которых возникают следующие различия.
|
||||
|
||||
1. Эффективность выделения и освобождения: стек представляет собой относительно небольшой участок памяти, а выделение в нем обычно выполняется автоматически компилятором; куча же обычно больше, может выделяться динамически из кода и легче фрагментируется. Поэтому выделение и освобождение памяти в куче обычно медленнее, чем в стеке.
|
||||
1. Эффективность выделения и освобождения: стек представляет собой относительно небольшой участок памяти, а выделение в нем обычно выполняется автоматически компилятором. Куча же обычно больше, может выделяться динамически из кода и легче фрагментируется. Поэтому выделение и освобождение памяти в куче обычно медленнее, чем в стеке.
|
||||
2. Ограничение размера: объем стека относительно невелик, а размер кучи обычно ограничивается доступной памятью. Поэтому куча лучше подходит для хранения больших массивов.
|
||||
3. Гибкость: размер массива в стеке должен быть известен во время компиляции, а размер массива в куче может определяться динамически во время выполнения.
|
||||
|
||||
@@ -29,7 +29,7 @@ comments: true
|
||||
|
||||
Связный список состоит из узлов, а узлы соединяются между собой через ссылки (указатели), поэтому каждый узел в принципе может хранить данные разного типа, например `int` , `double` , `string` , `object` и т.д.
|
||||
|
||||
Напротив, элементы массива должны быть одного типа, иначе нельзя будет вычислять адрес элемента через смещение. Например, если массив одновременно содержит `int` и `long` , один элемент занимает 4 байта, а другой - 8 байт ; в этом случае формула ниже уже не позволит вычислить смещение, потому что в массиве будут присутствовать элементы разной длины.
|
||||
Напротив, элементы массива должны быть одного типа, иначе нельзя будет вычислять адрес элемента через смещение. Например, если массив одновременно содержит `int` и `long` , один элемент занимает 4 байта, а другой - 8 байт. В этом случае формула ниже уже не позволит вычислить смещение, потому что в массиве будут присутствовать элементы разной длины.
|
||||
|
||||
```shell
|
||||
# Адрес элемента в памяти = адрес массива в памяти (адрес первого элемента) + длина элемента * индекс элемента
|
||||
@@ -45,9 +45,9 @@ comments: true
|
||||
|
||||
Если сначала искать элемент, а потом удалять его, то временная сложность действительно будет $O(n)$ . Однако преимущество связного списка с $O(1)$ вставкой и удалением проявляется в других сценариях. Например, двустороннюю очередь удобно реализовывать именно на связном списке: мы поддерживаем указатели на голову и хвост, и тогда каждая операция вставки или удаления остается $O(1)$ .
|
||||
|
||||
**Q**: На рисунке "Определение связного списка и способ хранения" светло-голубой блок с указателем узла - это отдельный адрес памяти? Или он делит память пополам со значением узла?
|
||||
**Q**: На рисунке «Определение связного списка и способ хранения» светло-голубой блок с указателем узла - это отдельный адрес памяти? Или он делит память пополам со значением узла?
|
||||
|
||||
Этот рисунок дает только качественное представление; количественно все зависит от конкретных условий.
|
||||
Этот рисунок дает только качественное представление. Количественно все зависит от конкретных условий.
|
||||
|
||||
- Значения узлов разных типов занимают разный объем памяти, например `int` , `long` , `double` и объекты-экземпляры.
|
||||
- Размер памяти, занимаемой переменной-указателем, зависит от операционной системы и среды компиляции и обычно составляет 8 байт или 4 байта.
|
||||
@@ -56,9 +56,9 @@ comments: true
|
||||
|
||||
Если при добавлении элемента длина списка превышается, то сначала приходится расширять список, а уже затем добавлять новый элемент. Система выделяет новый участок памяти и переносит туда все элементы исходного списка, и в этот момент временная сложность становится $O(n)$ .
|
||||
|
||||
**Q**: В утверждении "появление списка сильно повысило практическую полезность массива, но может приводить к потере части памяти" под потерями памяти имеется в виду дополнительная память под такие переменные, как емкость, длина и коэффициент расширения?
|
||||
**Q**: В утверждении «появление списка сильно повысило практическую полезность массива, но может приводить к потере части памяти» под потерями памяти имеется в виду дополнительная память под такие переменные, как емкость, длина и коэффициент расширения?
|
||||
|
||||
Потери памяти здесь в основном имеют два значения: во-первых, список обычно имеет некоторую начальную емкость, которая может быть нам не нужна целиком; во-вторых, чтобы избежать слишком частых расширений, емкость при расширении обычно умножается на некоторый коэффициент, например $\times 1.5$ . Из-за этого появляется много пустых слотов, которые обычно нельзя полностью заполнить.
|
||||
Потери памяти здесь в основном имеют два значения: во-первых, список обычно имеет некоторую начальную емкость, которая может быть нам не нужна целиком. Во-вторых, чтобы избежать слишком частых расширений, емкость при расширении обычно умножается на некоторый коэффициент, например $\times 1.5$ . Из-за этого появляется много пустых слотов, которые обычно нельзя полностью заполнить.
|
||||
|
||||
**Q**: В Python после инициализации `n = [1, 2, 3]` адреса этих трех элементов выглядят непрерывными, но после `m = [2, 1, 3]` можно заметить, что `id` элементов не идут подряд, а совпадают с одинаковыми числами из `n` . Если адреса элементов не непрерывны, остается ли `m` массивом?
|
||||
|
||||
@@ -85,6 +85,6 @@ comments: true
|
||||
|
||||
В этом списке все целые числа `0` являются ссылками на один и тот же объект. Это связано с тем, что Python использует механизм кэш-пула для маленьких целых чисел (обычно от -5 до 256), чтобы максимально переиспользовать объекты и повысить производительность.
|
||||
|
||||
Хотя все элементы указывают на один и тот же объект, мы все равно можем независимо изменять элементы списка, потому что целые числа в Python - это "неизменяемые объекты". Когда мы изменяем некоторый элемент, на самом деле происходит переключение ссылки на другой объект, а не изменение исходного объекта.
|
||||
Хотя все элементы указывают на один и тот же объект, мы все равно можем независимо изменять элементы списка, потому что целые числа в Python - это «неизменяемые объекты». Когда мы изменяем некоторый элемент, на самом деле происходит переключение ссылки на другой объект, а не изменение исходного объекта.
|
||||
|
||||
Однако если элементами списка являются "изменяемые объекты" (например списки, словари или экземпляры классов), то изменение одного элемента прямо меняет сам объект, и все элементы, ссылающиеся на него, увидят одно и то же изменение.
|
||||
Однако если элементами списка являются «изменяемые объекты» (например списки, словари или экземпляры классов), то изменение одного элемента прямо меняет сам объект, и все элементы, ссылающиеся на него, увидят одно и то же изменение.
|
||||
|
||||
Reference in New Issue
Block a user