This commit is contained in:
krahets
2026-04-14 18:06:14 +08:00
parent 065a978848
commit e53a7f2498
93 changed files with 565 additions and 570 deletions
+14 -14
View File
@@ -21,7 +21,7 @@ comments: true
**Q**: Почему хеш-таблица одновременно включает линейные и нелинейные структуры данных?
В основе хеш-таблицы лежит массив, а для разрешения коллизий мы можем использовать "цепочки адресации" (об этом будет рассказано в последующем разделе "Хеш-коллизии"): каждый бакет массива указывает на связный список, а если длина списка превышает некоторый порог, он может быть преобразован в дерево (обычно в красно-черное дерево).
В основе хеш-таблицы лежит массив, а для разрешения коллизий мы можем использовать «цепочки адресации» (об этом будет рассказано в последующем разделе «Хеш-коллизии»): каждый бакет массива указывает на связный список, а если длина списка превышает некоторый порог, он может быть преобразован в дерево (обычно в красно-черное дерево).
С точки зрения хранения данных в основе хеш-таблицы находится массив, где каждый слот бакета может содержать либо отдельное значение, либо связный список, либо дерево. Поэтому хеш-таблица действительно может одновременно включать линейные структуры данных (массивы, списки) и нелинейные структуры данных (деревья).
@@ -29,42 +29,42 @@ comments: true
Длина типа `char` определяется используемым в языке программирования способом кодирования. Например, Java, JavaScript, TypeScript и C# используют кодировку UTF-16 (для хранения кодовых точек Unicode), поэтому длина `char` у них равна 2 байтам.
**Q**: Не является ли двусмысленным утверждение, что структуры данных, реализованные на основе массива, также называются "статическими структурами данных"? Ведь стек тоже поддерживает операции push и pop, а они явно "динамические".
**Q**: Не является ли двусмысленным утверждение, что структуры данных, реализованные на основе массива, также называются «статическими структурами данных»? Ведь стек тоже поддерживает операции push и pop, а они явно «динамические».
Стек действительно может поддерживать динамические операции над данными, но сама структура данных при этом остается "статической" (ее длина неизменна). Хотя структуры на основе массива могут динамически добавлять и удалять элементы, их емкость фиксирована. Если количество данных превышает заранее выделенный размер, приходится создавать новый, более крупный массив и копировать в него содержимое старого.
Стек действительно может поддерживать динамические операции над данными, но сама структура данных при этом остается «статической» (ее длина неизменна). Хотя структуры на основе массива могут динамически добавлять и удалять элементы, их емкость фиксирована. Если количество данных превышает заранее выделенный размер, приходится создавать новый, более крупный массив и копировать в него содержимое старого.
**Q**: При построении стека (очереди) его размер не задается явно, почему же его относят к "статическим структурам данных"?
**Q**: При построении стека (очереди) его размер не задается явно, почему же его относят к «статическим структурам данных»?
В языках высокого уровня нам не нужно вручную задавать начальную емкость стека (очереди): это автоматически делает сама реализация класса. Например, начальная емкость `ArrayList` в Java обычно равна 10. Кроме того, автоматом реализуется и расширение емкости. Подробнее это рассматривается в последующем разделе о "списках".
В языках высокого уровня нам не нужно вручную задавать начальную емкость стека (очереди): это автоматически делает сама реализация класса. Например, начальная емкость `ArrayList` в Java обычно равна 10. Кроме того, автоматом реализуется и расширение емкости. Подробнее это рассматривается в последующем разделе о «списках».
**Q**: Если метод преобразования из прямого кода в дополнительный - это "сначала инвертировать, затем прибавить 1", то обратное преобразование из дополнительного кода в прямой, по идее, должно быть обратной операцией "сначала вычесть 1, затем инвертировать". Почему же дополнительный код также можно перевести в прямой тем же способом "сначала инвертировать, затем прибавить 1"?
**Q**: Если метод преобразования из прямого кода в дополнительный - это «сначала инвертировать, затем прибавить 1», то обратное преобразование из дополнительного кода в прямой, по идее, должно быть обратной операцией «сначала вычесть 1, затем инвертировать». Почему же дополнительный код также можно перевести в прямой тем же способом «сначала инвертировать, затем прибавить 1»?
Это связано с тем, что взаимное преобразование прямого и дополнительного кодов по сути является вычислением "дополнения". Сначала дадим определение дополнения: если $a + b = c$ , то говорят, что $a$ является дополнением числа $b$ до $c$ ; аналогично, $b$ является дополнением числа $a$ до $c$ .
Это связано с тем, что взаимное преобразование прямого и дополнительного кодов по сути является вычислением «дополнения». Сначала дадим определение дополнения: если $a + b = c$ , то говорят, что $a$ является дополнением числа $b$ до $c$. Аналогично, $b$ является дополнением числа $a$ до $c$ .
Для двоичного числа длины $n = 4$ со значением $0010$ , если рассматривать его как прямой код (не учитывая знаковый бит), то его дополнительный код получается правилом "сначала инвертировать, затем прибавить 1":
Для двоичного числа длины $n = 4$ со значением $0010$ , если рассматривать его как прямой код (не учитывая знаковый бит), то его дополнительный код получается правилом «сначала инвертировать, затем прибавить 1»:
$$
0010 \rightarrow 1101 \rightarrow 1110
$$
Мы видим, что сумма прямого и дополнительного кодов равна $0010 + 1110 = 10000$ , то есть дополнительный код $1110$ является "дополнением" прямого кода $0010$ до $10000$ . **Это означает, что описанная выше операция "сначала инвертировать, затем прибавить 1" на самом деле вычисляет дополнение до $10000$ **.
Мы видим, что сумма прямого и дополнительного кодов равна $0010 + 1110 = 10000$ , то есть дополнительный код $1110$ является «дополнением» прямого кода $0010$ до $10000$ . **Это означает, что описанная выше операция «сначала инвертировать, затем прибавить 1» на самом деле вычисляет дополнение до $10000$ **.
Тогда чему равно "дополнение" дополнительного кода $1110$ до $10000$ ? Мы снова можем получить его правилом "сначала инвертировать, затем прибавить 1":
Тогда чему равно «дополнение» дополнительного кода $1110$ до $10000$ ? Мы снова можем получить его правилом «сначала инвертировать, затем прибавить 1»:
$$
1110 \rightarrow 0001 \rightarrow 0010
$$
Иначе говоря, прямой и дополнительный коды являются взаимными "дополнениями" друг друга до $10000$ , поэтому и "прямой код -> дополнительный код", и "дополнительный код -> прямой код" можно реализовать одной и той же операцией (сначала инвертировать, затем прибавить 1).
Иначе говоря, прямой и дополнительный коды являются взаимными «дополнениями» друг друга до $10000$ , поэтому и «прямой код -> дополнительный код», и «дополнительный код -> прямой код» можно реализовать одной и той же операцией (сначала инвертировать, затем прибавить 1).
Разумеется, можно получить прямой код из дополнительного кода $1110$ и обратной операцией, то есть "сначала вычесть 1, затем инвертировать":
Разумеется, можно получить прямой код из дополнительного кода $1110$ и обратной операцией, то есть «сначала вычесть 1, затем инвертировать»:
$$
1110 \rightarrow 1101 \rightarrow 0010
$$
В итоге и "сначала инвертировать, затем прибавить 1", и "сначала вычесть 1, затем инвертировать" - это два эквивалентных способа вычисления дополнения до $10000$ .
В итоге и «сначала инвертировать, затем прибавить 1», и «сначала вычесть 1, затем инвертировать» - это два эквивалентных способа вычисления дополнения до $10000$ .
По сути операция "инвертировать" сама по себе вычисляет дополнение до $1111$ (потому что всегда выполняется `прямой код + обратный код = 1111` ); а дополнительный код, получающийся после добавления 1 к обратному коду, и есть дополнение до $10000$ .
По сути операция «инвертировать» сама по себе вычисляет дополнение до $1111$ (потому что всегда выполняется `прямой код + обратный код = 1111` ). А дополнительный код, получающийся после добавления 1 к обратному коду, и есть дополнение до $10000$ .
Приведенный выше пример использовал $n = 4$ , но его можно обобщить на двоичные числа любой длины.