билет 2
.pdf
|
Каталог |
|
Блоки бакетов |
||||||
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
Глубина |
|
|
|
|
2 |
|
- локальная глубина; первые два бита |
||
|
3 |
|
|
||||||
|
|
|
|
|
|
|
псевдокода = 00 |
||
|
|
|
|
||||||
Уровень 000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уровень 001 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уровень 010 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уровень 011 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уровень 100 |
|
|
|
|
3 |
|
- локальная глубина; первые три бита |
||
Уровень 101 |
|
|
|
|
|
|
|
|
псевдокода = 010 |
|
|
|
|
|
|
|
|
|
|
Уровень 110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уровень 111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
3 |
|
- локальная глубина; первые три бита |
||
|
|
|
|
|
|
|
|
|
псевдокода = 011 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
- локальная глубина; |
первый бит |
|
|
|
|
псевдокода = 1 |
|
|
|
|
|
|
|
|
Рисунок 6 – Динамическое хеширование
1.6 Операции над хешированными файлами
Для поиска записи с ключом v необходимо вычислить значение h(v) и считать соответствующий заголовок бакета. Затем необходимо проверить блоки бакета как блоки в файле, организованном в виде кучи. Если на каком либо шаге рассматриваемый блок имеет пустой указатель, а запись все еще не найдена, то нет необходимости просматривать остальные блоки файла, так как они не соответствуют значению хешфункции указанного ключа.
Для вставки записи со значением ключа v необходимо вычислить значение h(v) и найти нужный бакет. Пустое место для вставки новой записи имеет только последний блок бакета. Поэтому необходимо просматривать блоки бакета, пока не дойдем до блока с пустым указателем. Существует две ситуации, в которых нет необходимости просматривать блоки бакета:
1.Если записи должны быть уникальны, то операции вставки будет предшествовать операция поиска. В случае если запись не найдена, то на момент завершения поиска считанным уже будет последний блок соответствующего бакета.
2.Если уникальность записей не важна, то каталог бакетов можно усилить, введя дополнительный массив указателей, содержащих указатели на последние блоки бакетов.
После того как нужный блок был найден, в него помещается новая запись и он
записывается обратно на диск. Если последний блок не имеет свободного места под
запись, то выделяется еще блок, в него помещается новая запись, а пустой указатель предыдущего блока меняется на адрес нового, и оба блока перезаписываются.
Если заголовок бакета уже содержит пустой указатель, то просто выделяется новый блок, и указатель на него помещается в заголовок бакета.
При удалении производится поиск записи в блоках бакета. Если искомая запись найдена, то она удаляется. Так как внутри бакета блоки организованы в виде кучи, то может производиться, характерное для кучи уплотнение блоков.
При модификации производиться поиск блока с соответствующей записью, если такой блок найден, то искомая запись в этом блоке модифицируется, и блок перезаписывается на диск.
1.7 Эффективность хешированных файлов
Основное положение эффективности хешированных файлов следующее. Все операции на хешированных файлах производятся в В раз быстрее (В – число бакетов), чем на файлах, организованных в виде кучи.
Пусть в файле храниться n записей, помещающихся в R блоков. Хеш-функция выбрана так, что число бакетов равняется B. Если при этом таблица бакетов находится в оперативной памяти, то потребуется следующее число доступов:
1)n/2BR при успешном поиске, а также удалении и модификации существующей
записи;
2)n/BR при неудачном поиске, а также при проверке бакета перед вставкой, удалением и модификацией, если искомая запись отсутствует.
Основанием для таких расчетов служит тот факт, что в бакетах находится по n/R записей. Функция хеширования выбрана так, что записи в бакеты размещаются равномерно.
Если каталог бакетов находится на диске, то все количество доступов по всем операциям увеличивается на единицу, а в том случае, когда требуется внести изменения в каталог бакетов, на два.
Хорошо продуманная организация файлов с хешированным доступом требует лишь незначительного числа обращений к блокам при выполнении каждой операции с файлами. Если функция хеширования выбрана правильно и количество сегментов приблизительно равно количеству записей в файле, деленному на количество записей, которые могут уместиться в одном блоке, тогда средний сегмент состоит из одного блока. Если не учитывать обращения к блокам, которые требуются для просмотра таблицы бакетов, то типичная операция поиска данных по ключу потребует лишь одного обращения к блоку, а операции вставки, удаления или изменения потребуют двух обращений к блокам. Если среднее количество записей в бакете намного превосходит количество записей, которые могут уместиться в одном блоке, можно периодически реорганизовывать таблицу сегментов, удваивая количество бакетов и деля каждый из них на две части.
Индексированные файлы
Еще одним распространенным способом организации файла записей является поддержание файла в отсортированном (по значениям ключей) порядке. Поля целого или десятичного типа сортируются обычным образом. Если поле имеет строковый тип, то используется лексикографическая сортировка.
Пример,
пусть существуют две последовательности символов X1X2…Xk и Y1Y2…Ym. Где каждый X и Y – отдельный символ. Можно утверждать, что X1X2…Xk < Y1Y2…Ym в двух случаях:
1)k<m и X1X2…Xk = Y1Y2…Yk
2)для некоторого i min(k,m) будет иметь место X1=Y1, X2=Y2,…,Xi-1=Yi-1 и код Xi
меньше кода Yi. При этом в качестве кода может быть взят ASCII код символов. Согласно этому принципу «свет» < «светлый» или «луг» < «лук».
Часто ключ состоит более чем из одного поля. В этом случае сортировка выполняется следующим образом. Производится упорядочивание по первому полю ключа. В результате получиться последовательность, состоящую из групп с одинаковыми значениями начала ключа. Затем внутри каждой группы производится упорядочивание по следующему полю ключа. При этом получаются большее количество более мелких групп. Процесс продолжается до тех пор, пока не образуются группы, включающие по одной записи.
В этом случае файл можно просматривать как обычный словарь или телефонный справочник, когда просматриваются лишь заглавные слова или фамилии на каждой странице. Чтобы облегчить процедуру поиска, можно создать второй файл, называемый разреженным индексом, который состоит из пар (x, b), где x - значение ключа, а b - физический адрес блока, в котором значение ключа первой записи равняется х. Разреженный индекс должен быть отсортирован по значениям ключей.
Пример,
на рисунке 7 показан основной файл, а так же соответствующий ему файл разреженного индекса.
Предполагается, что три записи основного файла (или три пары индексного файла) умещаются в один блок. Записи основного файла представлены только значениями ключей, которые в данном случае является целочисленными величинами.
Рисунок 7 – Основной файл и его разреженный индекс
Чтобы отыскать запись с заданным ключом х, надо сначала просмотреть индексный файл, отыскивая в нем пару (x, b). В действительности отыскивается наибольшее z, такое, что z
x и далее находится пара (z, b). В этом случае ключ х оказывается в блоке b (если такой ключ вообще присутствует в данном файле).
1.9 Операции над индексированными файлами
Инициализация. Пусть имеются записи со следующими значениями ключей: 16, 2,
5, 37, 79, 56, 4, 25, 54, 68
Процесс состоит из трех этапов:
1. Записи в исходном файле сортируются, после чего распределяются по блокам. Обычно файлы БД имеют тенденцию к увеличению, поэтому при инициализации блоки оставляют незаполненными на 20%. Таким образом, основной файл имеет вид упорядоченных записей, размещенных в упорядоченные блоки.
Пример,
Пусть в блок вмещается по пять записей, тогда схема организации основного файла будет иметь вид представленный на рисунке 8.
2 |
4 |
5 |
|
16 |
|
|
25 |
37 |
54 |
56 |
|
|
68 |
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
В1 |
|
|
|
В2 |
|
|
|
|
|
В3 |
||||
Рисунок 8 – Организация основного файла
2. Создание индексного файла. При этом берутся первые записи каждого блока и составляются пары (<значение ключа первой записи блока>, <адрес блока>). Исключение
– первый блок. Для него в индексный файл записывается пара (- , адрес первого блока). Это необходимо, чтобы не описывать отдельные алгоритмы для работы со значениями ключа, меньшими, чем все существующие в файле на данный момент. Схема организации индексного файла представлена на рисунке 9.
-
25 68
2 |
4 |
5 |
16 |
|
|
25 |
37 |
54 |
56 |
|
|
68 |
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рисунок 9 – Организация индексного файла
3. Организация блоков индексного файла. Так как индекс может потребовать пространство большее, чем один блок, то необходимо выбрать организацию этого файла. Будем считать, что индексный файл организован в виде кучи.
Поиск.
Пусть v1 значение ключа искомой записи. Тогда в индексе необходимо найти запись (v2, b), такую что, v2 v1. И либо v2 – последняя запись в индексе, либо следующие записи имеют вид (v3, b), причем v1<v3. В этом случае говорят, v2 покрывает v1. Таким образом, находится блок, в котором может находиться запись со значение ключа v1. Согласно адресу в записи (v2, b) извлекается блок основного файла. Искомая запись находится либо в этом блоке, либо она вовсе отсутствует в файле.
Таким образом, в целом скорость поиска зависит от скорости поиска в индексном файле записи, покрывающей ключ. Существует три основных вида поиска:
1.Линейный поиск. При данном виде поиска, последовательно перебираются все блоки и все записи индекса. Даже при такой организации поиска в индексе получается выигрыш в скорости доступа по сравнению с остальными видами файлов. Так, если в главном файле содержится R записей в блоке, то по сравнению с организацией его в виде кучи, поиск будет происходить в R раз быстрее.
2.Двоичный поиск. Основой для применения этого метода служит никогда не нарушаемое упорядочивание записей не только в основном файле, но и в индексе.
Пусть В1, В2,…, Вm – блоки индексного файла. Первые записи в этих блоках (индекса) V1, V2, …, Vm. Необходимо найти запись с ключом V. Сначала извлекается блок Bm/2. Необходимо сравнить значение Vm/2 со значением V.
Если V<Vm/2, то продолжается поиск, в блоках В1-Вm.2-1, если V Vm/2, то поиск
необходимо провести в блоках Bm/2…Bm. Процесс деления продолжается пока не останется один блок. Далее в этом блоке ищется запись, покрывающая V, с использованием линейного поиска. В результате потребуется Log2M обращений к индексному файлу.
3.Интерполирующий поиск. В этом случае кроме упорядочивания записей в индексе важную роль играет знание статистики распределения значений ключей. При работе этого метода должна существовать функция f(V1, V2, V3). Эта функция возвращает в качестве результата блок, в котором может находиться запись со значением ключа равной V1, если известно, что V1 находится между значениями V2 и V3. Поиск продолжается пока не останется один блок, затем в нем перебором ищется покрывающая V1 запись. Потребуется 1+ Log2Log2M доступов к индексу.
Модификация.
Если изменяется не ключевое поле записи основного файла, то выполняется операция поиска, в результате которой буден считан блок основного файла, в котором должна располагаться искомая запись, в случай ее наличия производиться ее модификация, и блок основного файла перезаписывается на диск. Если необходимо произвести модификацию ключевого поля, то необходимо выполнить операции, характерные для операций вставки и удаления, так как операция модификации не должна нарушать сортировки ни в основном, ни в индексном файле.
Вставка.
Для вставки записи с ключом V1 в индексированный файл выполняется операция поиска блока Bi, в который должна быть помещена новая запись. После чего, необходимо определить позицию записи в нутрии найденного блока. Это выражается в сохранении сортировки после выполнения операции вставки. Поэтому все записи блока, имеющие ключи больше V1 сдвигаются вправо. При этом освобождается место под V1. Если в блоке Bi нет свободного места, то необходимо проверить блок Bi+1. Найти этот блок можно, используя запись в индексном файле (она следует за записью, покрывающую v1).
Если в Bi+1 блоке есть свободное место, то последняя запись блока Bi переносится в качестве первой в блок Bi+1, после чего в обоих блоках записи сдвигаются вправо, и запись V1 помещается в требуемую позицию в блоке Bi. Также в этом случае необходимо произвести изменение в блоке индексного файла, так как изменилось значение ключа первой записи блока Bi+1.
Если в блоке Bi+1 много свободного места, то все записи (вместе с новой) двух блоков, делятся пополам и размещаются в них поровну. При этом также необходимо перезаписать оба блока и внести изменения в файл индекса.
Если блок Bi+1 заполнен, или не существует (то есть Bi – последний), то аналогичную последовательность действий производят с блоком Bi-1.
Если Bi – первый, или Bi-1 также заполнен, то к файлу добавляют новый блок. После чего записи Bi распределяют поровну между Bi и новым блоком и в индексный файл добавляют новую запись для нового блока, при этом не нарушается сортировка в индексном файле. Таким же производится сдвиг всех записей индекса и на освободившееся место записывается новое значение. Если индекс занимает более чем один блок, то также могут потребоваться операции перемещения записей индекса между блоками и присоединения нового блока к файлу.
При организации вставки в индексированный файл можно принять единую стратегию, когда при заполнении блока i, не проверяется ни i+1, ни i-1 блоки, а сразу захватывается новый блок. Это упрощает и несколько ускоряет процедуру вставки. Однако такая стратегия увеличивает общее число блоков и нарушает их порядок.
Удаление.
При удалении производится процедура поиска записи, в результате которого искомая запись удаляется, и все записи блока смещаются влево. Если после удаления блок
остается пустым, то его возвращают файловой системе. Если удаляется первая запись блока, то необходимо модифицировать соответствующую запись индекса. Если операция удаления записи завершилась удалением блока основного файла, то соответствующую запись в индексе также необходимо удалить, сдвинув все записи индекса влево.
Эффективность индексированных файлов
Пусть блок главного файла максимально вмещает E записей. Тогда в худшем случае блок будет вмещать e равное (E+1)/2 записей. Эта ситуация складывается при делении блока при вставке новой записи. Аналогично если блок индекса максимально вмещает D, тогда в худшем случае он будет содержать d равное (D+1)/2 записей. Если в файле содержится n записей, то можно сделать следующие выводы об эффективности индексированных файлов.
При двоичном поиске в индексированном файле потребуется 2+Log2(n/de) обращений к диску. Где n/de – максимальное количество блоков в индексе (логарифм из эффективности двоичного поиска). Еще два обращения для чтения и записи блока
основного файла. При интерполирующем |
поиске потребуется 3+Log2Log2(n\de) |
обращений к диску. |
|
1.11 Плотное индексирование
Индексирование, рассмотренное выше, называется разреженным индексированием. Существует другой вид индексирования широко распространенный в реальных СУБД – плотное индексирование. В этом случае индексные файлы содержат пары вида (v,p), где первый элемент – значение ключа, а второй – адрес записи в основном файле с этим ключом. Такой подход не требует обязательного упорядочивания записей по индексируемому полю, а так же не обязательна уникальность ключа. Поэтому подход плотного индекса применим для ускорения поиска по любым полям, позволяя построить несколько независимых индексов.
При организации таких файлов скорость доступа будет 2+время поиска в файле индекса.
Вопрос 3
Библиотека визуальных компонентов VCL и ее базовые классы
Все классы библиотеки визуальных компонентов произошли от группы базовых классов, которые лежат в основе иерархии VCL. Самый общий предок компонентов — это
класс TObject, инкапсулирующий простейший объект. Как известно, каждый объект наследует свойства и методы родительского класса. К объекту можно добавить новые свойства и методы, но нельзя удалить унаследованные. Объект-наследник в свою очередь может стать родительским для нового класса, который унаследует возможности всех своих предков.
Поэтому иерархия базовых классов VCL продумана чрезвычайно тщательно — ведь на их основе создано все множество компонентов, используемых в Delphi. Особое место среди базовых классов, помимо TObject, занимают TComponent (от него происходят все компоненты) и TControl (от него происходят все элементы управления).
Рассматрим иерархию базовых классов и их возможности. Представленные здесь сведения помогут разобраться с основными механизмами функционирования компонентов. Настоящая глава послужит справочным материалом для тех, кто создает собственные объекты и элементы управления.
Иерархия базовых классов
В основе всего многообразия классов и компонентов, используемых в Delphi, лежат всего лишь пять базовых классов (рис. 2.1). Они обеспечивают выполнение основных функций любого объекта — будь это стандартный компонент VCL или специализированный объект, выполняющий некоторые операции в приложении.
Рис. 2.1. Иерархия базовых классов VCL
Благодаря механизму наследования свойств и методов, потомки базовых классов умеют "общаться" друг с другом; работают в среде разработки, взаимодействуя с Палитрой компонентов и Инспектором объектов; распознаются операционной системой как элементы управления и окна.
В основе иерархии классов лежит класс TObject. Он обеспечивает выполнение важнейших функций "жизнедеятельности" любого объекта. Благодаря ему, каждый класс получает в наследство механизмы создания экземпляра объекта и его уничтожения.
Невизуальный компонент — это компонент, который не виден пользователю в процессе проектирования программы.
Невизуальные компоненты работают "за кулисами" и выполняют специфические задачи. Примеры таких компонентов: системные таймеры, компоненты для работы с базами данных, списки изображений. Стандартные диалоговые панели, такие как File Open, File Save, Font и другие, также представлены невизуальными компонентами. Они не видны на этапе проектирования и отображаются только во время выполнения программы. Когда вы помещаете невизуальный компонент на форму, Delphi показывает его в виде значка. Этот значок используется только для изменения свойств компонента на этапе проектирования и не выводится на экран при выполнении программы. Невизуальные компоненты, как и визуальные, имеют свойства, методы и события.
Невизуальные компоненты представлены классами TDataSource, TDatabase, TTable и TQuery. Эти классы инкапсулируют фоновые операции с базами данных.
DataSource
Невизуальный компонент DataSource представляет собой источник данных, который обеспечивает связь между набором данных и компонентами отображения и редактирования данных.
Все наборы данных должны быть связаны с компонентом источника данных, если требуется редактирование данных. Основное свойство источника данных – DataSet. Оно указывает на компонент набора данных (Table, Query и др), с которыми связан источник. Свойство State дает информацию о текущем состоянии набора данных: находится ли он в состоянии редактирования, вставки данных и так далее.
Основные методы
Edit – подтверждает возможность редактирования набора данных (не путать этот метод с методом Edit из набора TDataSet). Объявление: procedure Edit; IslinkedTo – проверяет связь источника с указанным набором данных. Обычно напрямую не используется, а применяется при разработке новых компонентов.
Объявление: function IslinkedTo(DataSet: TDataSet):Boolean;
События
OnDataChange – наступает при перемещении на новое поле или новую запись, если текущая запись редактировалась.
OnStateChange – наступает при изменении состояния набора данных, связанного с данным источником.
OnUpdateData – наступает, когда намечается обновление текущей записи.
Основные свойства
AutoEdit определяет, вызывается ли автоматически метод редактирования данныхEdit.
DataSet набор данных, с которым связан компонент.
Enabled определяет, отображается ли данные в компонентах отображения, связанных с этим источником.
State – указывает текущее состояние набора данных, связанного с источником данных.
Визуальные компоненты (visual components) — это управляющие элементы пользовательского интерфейса (controls), т. е. кнопки, метки, блоки списков и др. Они видны на экране и выглядят одинаково на стадии проектирования и во время работы приложения. В этом их главное достоинство.
Класс TControl
Класс TControl (управление) - наследник класса TComponent. Это базовый класс
для визуальных компонентов Delphi. Он содержит собственные свойства (более 50) и методы (около 100), имеющиеся у всех визуальных компонентов. Описан в
модуле Controls.
Это абстрактный класс. Нельзя создать объект этого класса. Он используется для порождения классов-потомков, из которых определены два стандартных класса:
TWinControl. Базовый для оконных компонентов.
TGraphicControl. Базовый для графических компонентов.
Свойства класса TControl
Основные свойства класса TControl приведены в следующей таблице.
Таблица 1. Свойства класса TControl
Свойство
property Action: TBasicAction;
property Align: TAlign; TAlign=(alNone, alTop, alBottom, alLeft, alRight, alClient);
property Anchors: TAnchors;
property AutoSize: Boolean;
property BoundsRect: TRect;
property Caption: String;
property ClientHeight: Integer;
Описание
Определяет действие, связанное с данным управляющим элементом.
Определяет способ выравнивания компонента в контейнере (родительском компоненте).
Определяет привязку данного компонента к родительскому при изменении размеров последнего.
Определяет, будет ли высота элемента автоматически адаптироваться к размеру символов текста.
Определяет координаты углов компонента в координатах содержащего его контейнера.
Строка текста, идентифицирующая компонент для пользователя. Обычно это надпись на метке, кнопке и других компонентах.

Высота клиентской области в пикселях.
