Рисунок6.36 а..h Удаление узлов из сбалансированого дерева.
Удаление элемента из сбалансированного дерева удобнее разбить на 4 отдельных процедуры:
1. Delete - осуществляет рекурсивный поиск по дереву удаляемого элемента, вызывает процедуры удаления и балансировки. 2. Del - осуществляет собственно удаление элемента и вызов при необходимости процедуры балансировки. 3. Balance_L и Balance_R - производят балансировку и коррекцию показателей сбалансированности после удаления элемента из левого (правого) поддерева.
Классификация структур данных
Рисунок 1.1. Классификация структур данных
Важный признак структуры данных - характер упорядоченности ее элементов. По этому признаку структуры можно делить на ЛИНЕЙНЫЕ И НЕЛИНЕЙНЫЕ структуры.
В зависимости от характера взаимного расположения элементов в памяти линейные структуры можно разделить на структуры с ПОСЛЕДОВАТЕЛЬНЫМ распределением элементов в памяти (векторы, строки, массивы, стеки, очереди) и структуры с ПРОИЗВОЛЬНЫМ СВЯЗНЫМ распределением элементов в памяти ( односвязные, двусвязные списки). Пример нелинейных структур - многосвязные списки, деревья, графы.
В языках программирования понятие "структуры данных" тесно связано с понятием "типы данных". Любые данные, т.е. константы, переменные, значения функций или выражения, характеризуются своими типами.
Информация по каждому типу однозначно определяет :
1) структуру хранения данных указанного типа, т.е. выделение памяти и представление данных в ней, с одной стороны, и интерпретирование двоичного представления, с другой; 2) множество допустимых значений, которые может иметь тот или иной объект описываемого типа; 3) множество допустимых операций, которые применимы к объекту описываемого типа.
В последующих главах данного пособия рассматриваются структуры данных и соответствующие им типы данных. При описании базовых (простых) типов и при конструировании сложных типов мы ориентировались в основном на язык PASCAL. Этот язык использовался и во всех иллюстративных примерах. PASCAL был создан Н.Виртом специально для иллюстрирования структур данных и алгоритмов и традиционно используется для этих целей. Читатель знакомый с любым другим процедурным языком программирования общего назначения (C, FORTRAN, ALGOL, PL/1 и т.д.), без труда найдет аналогичные средства в известном ему языке.
Рисунок 2.2. Формат машинного представления беззнаковых чисел
Формат машинного представления чисел типа WORD приведен на рис. 2.2. б).
Например: 1). Машинное представление числа 258: 257=2^8+2^1 = 00000010 00000001. 2). Машинное представление границ: 0: 00000000 00000000; 65535: 11111111 11111111.
Формат машинного представления чисел со знаком
Рисунок 2.3. Формат машинного представления чисел со знаком
На рис 2.3 s-знаковый бит числа. При этом, если s=0, то число положительное, если s=1 - число отрицательное. Цифры определяют номера разрядов памяти.
Машинное представление данных типа COMP. . 0 Тип COMP предназначен для работы с большими целыми числами (см. таблицу 2.1). Поэтому числа данного типа представляются в памяти в соответствии с правилами представления целых чисел со знаком - в дополнительном коде. Но для удобства пользователей при вводе и выводе значений чисел в этом формате допускается использование формы записи чисел характерных для вещественных чисел (в виде мантиссы и порядка).
Формат машинного представления данных типа comp
Рисунок 2.4. Формат машинного представления данных типа COMP
где s - знаковый разряд числа (если s=0,то число положительное, если s=1 - число отрицательное )
Например: машинное представление чисел в формате COMP: +512 0..0 00000010 0..0 0..0 0..0 0..0 0..0 0..0 -512 0..0 11111110 1..1 1..1 1..1 1..1 1..1 1..1
где @ Имя -адрес вектора или, что тоже самое, адрес первого элемента вектора,
Sizeof(тип)-размер слота (количество байтов памяти для записи одного элемента вектора), (k-n)*Sizeof(тип) - относительный адрес элемента с номером k, или, что тоже самое, смещение элемента с номером k.
Например: var m1:array[-2..2] of real;
представление данного вектора в памяти будет как на рис. 3.2.
Представление вектора m1 в памяти
Рисунок 3.2. Представление вектора m1 в памяти
В языках, где память распределяется до выполнения программы на этапе компиляции (C, PASCAL, FORTRAN), при описании типа вектора граничные значения индексов должны определены. В языках, где память может распределяться динамически (ALGOL, PL/1), значения индексов могут быть заданы во время выполнения программы.
Количество байтов непрерывной области памяти, занятых одновременно вектором, определяется по формуле:
ByteSise = ( k - n + 1 ) * Sizeof (тип)
Обращение к i-тому элементу вектора выполняется по адресу вектора плюс смещение к данному элементу. Смещение i-ого элемента вектора определяется по формуле:
ByteNumer = ( i- n ) * Sizeof (тип), а адрес его: @ ByteNumber = @ имя + ByteNumber.
где @ имя - адрес первого элемента вектора.
Например: var МAS: array [ 5..10 ] of word.
Базовый тип элемента вектора - Word требует 2 байта, поэтому на каждый элемент вектора выделяется по два байта. Тогда таблица 3.1 смещений элементов вектора относительно @Mas выглядит так:
Смещение (байт)
+ 0
+ 2
+ 4
+ 6
+ 8
+ 10
Идентификатор поля
MAS[5]
MAS[6]
MAS[7]
MAS[8]
MAS[9]
MAS[10]
Физическая структура двумерного массива из (k1-n1+1) строк и (k2-n2+1) столбцов
Рисунок 3.3. Физическая структура двумерного массива из (k1-n1+1) строк и (k2-n2+1) столбцов
Многомерные массивы хранятся в непрерывной области памяти. Размер слота определяется базовым типом элемента массива. Количество элементов массива и размер слота определяют размер памяти для хранения массива. Принцип распределения элементов массива в памяти определен языком программирования. Так в FORTRAN элементы распределяются по столбцам - так, что быстрее меняется левые индексы, в PASCAL - по строкам - изменение индексов выполняется в направлении справа налево.
Количество байтов памяти, занятых двумерным массивом, определяется по формуле :
ByteSize = (k1-n1+1)*(k2-n2+1)*SizeOf(Тип)
Адресом массива является адрес первого байта начального компонента массива. Смещение к элементу массива Mas[i1,i2] определяется по формуле:
ByteNumber = [(i1-n1)*(k2-n2+1)+(i2-n2)]*SizeOf(Тип) его адрес : @ByteNumber = @mas + ByteNumber. Например: var Mas : Array [3..5] [7..8] of Word;
Базовый тип элемента Word требует два байта памяти, тогда таблица 3.2 смещений элементов массива относительно @Mas будет следующей:
Смещение (байт)
Идентификатор поля
Смещение (байт)
Идентификатор поля
+ 0
Mas[3,7]
+ 2
Mas[3,8]
+ 4
Mas[4,7]
+6
Mas[4,8]
+ 8
Mas[5,7]
+ 10
Mas[5,8]
Представление массивов с помощью векторов айлиффа
Рисунок 3.4. Представление массивов с помощью векторов Айлиффа
Для массива любой мерности формируется набор дескрипторов: основного и несколько уровней вспомогательных дескрипторов, называемых векторами Айлиффа. Каждый вектор Айлиффа определЯнного уровня содержит указатель на нулевые компоненты векторов Айлиффа следующего, более низкого уровня, а векторы Айлиффа самого нижнего уровня содержат указатели групп элементов отображаемого масси- ва. Основной дескриптор массива хранит указатель вектора Айлиффа первого уровня. При такой организации к произвольному элементу В(j1,j2,...,jn) многомерного массива можно обратиться пройдя по цепочке от основного дескриптора через соответствующие компоненты векторов Айлиффа.
На рис. 3.4 приведена физическая структура трЯхмерного массива В[4..5,-1..1,0..1], представленная по методу Айлиффа. Из этого рисунка видно, что метод Айлиффа, увеличивая скорость доступа к элементам массива, приводит в то же время к увеличению суммарного объЯма памяти, требуемого для представления массива. В этом заключается основной недостаток представления массивов с по- мощью векторов Айлиффа.
Машинное связное представление дерева при смешанном обходе с прошивкой
Рисунок 6.29. Машинное связное представление дерева при смешанном обходе с прошивкой
Трассировка смешанного обхода с прошивкой приведена в табл.6.4.
@ указателя
Узел
Обработка узла
Выходная строка
P:=PT
H
LPH
A
LPA
B
LPB
C
-LPC
C
C
C
-RPC
B
B
CB
-RPB
A
A
CBA
RPA
D
LPD
E
LPE
F
-LPF
F
F
CBAF
-RPF
E
E
CBAFE
-RPE
D
D
CBAFED
RPD
G
-LPG
G
G
CBAFEDG
-RPG
H
Конец алгоритма
представление выражения в виде бинарного дерева.
Рисунок 6.32 Представление выражения в виде бинарного дерева.
перемножать, вычитать, дифференцировать, интегрировать, сравнивать на эквивалентность и т.д. Т.е. получаются символьные выражения, которые можно закодировать в виде таблиц:
(-) - операция унарного минуса; () - операция возведения в степень; (+) - операция сложения; (*) - операция умножения; (/) - операция деления. (Е) - указательная переменная, адресующая корень дерева, каждая вершина которого состоит из левого указателя (LPТR), правого указателя (RPTR) и информационного поля TYPE.
LPTR
DATA
RPTR
Для неконцевой вершины поле TYPE задает арифметическую операцию, связанную с этой вершиной. Значения поля TYPE вершин +,-,*, /, (-) и равны 1, 2, 3, 4, 5, 6 соответственно.
Для концевых вершин поле символа в TYPE имеет значение 0, что означает константу или переменную. В этом случае правый указатель вершины задает адрес таблицы символов, который соответствует данной константе или переменной. В дереве указывается тип оператора, а не он сам, что позволяет упростить обработку таких деревьев.
Алгоритм складывается из построения упорядоченного двоичного дерева и последующего его обхода. Если нет необходимости в построении всего линейного упорядоченного списка значений, то нет необходимости и в обходе дерева, в этом случае применяется поиск в упорядоченном двоичном дереве. Алгоритмы работы с упорядоченными двоичными деревьями подробно рассмотрены в главе 6. Отметим, что порядок алгоритма - O(N*log2(N)), но в конкретных случаях все зависит от упорядоченности исходной последовательности, который влияет на степень сбалансированности дерева и в конечном счете - на эффективность поиска.
Связное представление орграфов.
СВЯЗНОЕ ПРЕДСТАВЛЕНИЕ ОРГРАФОВ.
Орграф представляется связным нелинейным списком, если он часто изменяется или если полустепени захода и исхода его узлов велики. Рассмотрим два варианты представления орграфов связными нелинейными списковыми структурами.
В первом варианте два типа элементов - атомарный и узел связи (см. раздел 5.5). На рис.6.5 показана схема такого представления для графа рис.6.2. Скобочная запись связей этого графа:
( < A,B >, < B,C >, < C,D >, < B,D >, < D,C > )
Иными словами, диапазон возможных значений
Таблица 2.1
Иными словами, диапазон возможных значений целых типов зависит от их внутреннего представления, которое может занимать 1, 2 или 4 байта. В таблице 2.1 приводится перечень целых типов, размер памяти для их внутреннего представления в битах, диапазон возможных значений.
с плавающей точкой является мантисса.
Таблица 2.2
Следующим компонентом представляемого в машине числа с плавающей точкой является мантисса. Для увеличения количества значащих цифр в представлении числа и исключения переполнения при умножении мантиссу обычно подвергают нормализации. Нормализация означает, что мантисса (назовем ее F), кроме случая, когда F=0, должна находиться в интервале
R^(-1)
Для двоичной системы счисления R=2. Тогда в связи с тем, что 2^(-1)
Приведенный метод нормализации является классическим методом, при котором результат нормализации представляется в виде правильной дроби, т.е. с единицей после точки и нулем в целой части числа. Но нормализацию мантиссы можно выполнить по разному.
В IBM PC нормализованная мантисса содержит свой старший бит слева от точки. Иными словами нормализованная мантисса в IBM PC принадлежит интервалу 1
Первый, старший, бит в представлении чисел в формате с плавающей точкой является знаковым, и по принятому соглашению нуль обозначает положительное число, а единица - отрицательное.
Число бит для хранения мантиссы и порядка зависит от типа вещественного числа. Суммарное количество байтов, диапазоны допустимых значений чисел вещественных типов, а также количество значащих цифр после запятой в представлении чисел приведены в таблице 2.3.
Тип
Диапазон значений
Значащие цифры
Размер в байтах
real
2.9*10^(-39)..1.7*10^38
11-12
6
single
1.4*10^(-45)..3.4*10^38
7-8
4
double
4.9*10^(-324)..1.8*10^308
15-16
8
extended
3.1*10^(-4944)..1.2*10^4932
19-20
10
в таблице следует понимать как:
Таблица 2.4
Примечание: запись chr(ord(0)) в таблице следует понимать как: символ с кодом 0.
А) Интервальный тип от символьного: определение кода символа и, наоборот, символа по его коду.
Пусть задана переменная типа tz:'d'..'h'. Данной переменной присвоено значение 'e'. Байт памяти отведенный под эту переменную будет хранить ASCII-код буквы 'e' т.е. 01100101 (в 10-ом представлении 101).
Б) Интервальный тип от перечислимого: определение порядкового номера идентификатора по его значению и, наоборот, по номеру идентификатора - его значение.
На логическом уровне все операции, разрешенные для данных базового типа, возможны и для данных соответствующих интервальных типов.