Фундаментальные алгоритмы и структуры данных в Delphi | страница 67
Второе решение, которое можно считать более удачным, - представить данные в форме нетипизированного указателя. (Для этого имеются все предпосылки - в Delphi подобным образом работает стандартный класс TList.) При добавлении элемента в связный список классу списка передается только значение указателя (скажем, указателя на данные или объект в куче), а все остальное делает сам список: распределяет память под узел, устанавливает значения данных и манипулирует ссылками. Это решение обходит проблему незнания типа данных, поскольку пользователь класса может не беспокоиться об указателях Next, не должен распределять для них память, создавать специальные дочерние классы и т.д.
Но это второе решение имеет свой недостаток. Размер используемых классом узлов всегда будет равен 8 байтам - по 4 байта для указателя и данных.
-------
Обратите внимание, что в приведенных выше рассуждениях считается, что размер указателей составляет 4 байта. Можно предположить, что последующие версии Delphi будут написаны для 64-разрядных операционных систем. В таком случае длина указателей будет составлять 8 байт. Поэтому не основывайтесь на предположении, что длина указателя всегда 4 байта, пользуйтесь функцией sizeof(pointer). В будущем это существенно упростит перенос кода в новые версии Delphi. Тем не менее, в настоящей главе считается, что длина указателя составляет 4 байта, даже несмотря на то, что в коде используется sizeof(pointer). Такое допущение позволяет упростить выкладки, поскольку можно просто сказать "8 байт", а не "удвоенное значение sizeof(pointer)".
-------
Что дает нам постоянный размер узла? При необходимости записи данных в связный список нужно предварительно распределить память под узел. Для этого пришлось бы использовать очень сложный диспетчер кучи Delphi, всего лишь, чтобы распределить 8 байт памяти. Диспетчер кучи содержит код, который может манипулировать кусками памяти, а также распределять и освобождать память любого размера. Все операции выполняются быстро и эффективно. Но мы знаем, что будут использоваться только 8-байтные блоки, и нам нужны только такие блоки. Можно ли, учитывая постоянство размеров блоков, увеличить скорость распределения памяти для новых узлов и освобождения памяти, занимаемой удаляемыми узлами? Конечно же, ответ "да". Мы с помощью диспетчера кучи одновременно распределяем память для нескольких узлов, а затем используем ее по мере необходимости. Таким образом, память распределяется не для одного узла, а, скажем, для 100 узлов. Если потребуется большее количество, будет выделен еще один блок из 100 узлов.