АкушерствоАнатомияАнестезиологияВакцинопрофилактикаВалеологияВетеринарияГигиенаЗаболеванияИммунологияКардиологияНеврологияНефрологияОнкологияОториноларингологияОфтальмологияПаразитологияПедиатрияПервая помощьПсихиатрияПульмонологияРеанимацияРевматологияСтоматологияТерапияТоксикологияТравматологияУрологияФармакологияФармацевтикаФизиотерапияФтизиатрияХирургияЭндокринологияЭпидемиология

Хранение прямоугольных массивов

Прочитайте:
  1. V1: ЗДРАВООХРАНЕНИЕ В РФ
  2. Биосинтез, хранение и секреция гормона
  3. Посттрансфузионные реакции и осложнения, связанные с консервированием и хранением крови, эритроцитарной массы.
  4. Сохранение в тайне информации о факте обращения за медицинской помощью, о состоянии здоровья, диагнозе и иных сведений, полученных при его обследовании и лечении
  5. Сохранение зубов здоровыми
  6. Сохранение синусового ритма
  7. ХРАНЕНИЕ ВАШЕГО МОЛОКА
  8. Хранение инсулина и подготовка к уколу
  9. Хранение карпул с анестезирующими веществами
  10. Хранение непрямоугольных массивов

 

Для примера используем язык Pascal, допускающий массивы с отрицательными, нулевыми и положительными индексами, т.е. более общего вида чем большинство других языков.

Прямоугольный n-мерный массив X определяется на языке Pascal следующим образом

X: array [I1 .. K1,..., In .. Kn] of тип-элемента, (3.1)

где Im, Km - начальная и конечная границы (граничная пара) m-го индекса (m = 1, 2, …, n).

Массив обычно хранят в виде вектора (его называют отображающим век тором). Пронумеруем элементы этого вектора от 0 до N-1, где N - количество элементов массива:

n

N = P (Km - Im + 1). (3.2)

m=1

Здесь P обозначает произведение (аналогично сумме S), Km-Im+1 равно количеству возможных значений m-го индекса.

Объем занимаемой массивом памяти V равен

V = N * d, где d - длина элемента (количество ячеек). (3.3)

Обычно элементы массива размещаются в памяти по возрастанию индексов, начиная с элемента X[I1,...,In], имеющего минимальные индексы. Тогда, считая от 0, порядковый номер L элемента X[J1,...,Jn] в памяти равен:

n

L = S Dm * (Jm - Im), (3.4)

m=1

где Dm – перемещение по памяти при изменении индекса Jm на 1, выраженное количеством элементов,

Обычно элементы размещают “ строками” (когда при просмотре элементов в порядке увеличения адресов быстрее изменяетcя правый индекс). В этом случае

Dn = 1; Dm-1 = Dm * (Km - Im + 1), (m = 2,..., n). (3.5)

При размещении “ столбцами ” (когда быстрее изменяетcя левый индекс)

D1 = 1; Dm = Dm-1 * (Km-1 - Im-1 + 1), (m = 2,..., n). (3.6)

Согласно формуле (1.1) адрес элемента X[J1,...,Jn] с номером L: равен

адрес(X[J1,...,Jn]) = адрес (X[I1,...,In]) + d*L.

Из формулы (3.4) получим:n

адрес(X[J1,...,Jn]) = B + C + d * S Dm*Jm, (3.7)

m=1

где B = адрес (X[I1,...,In]) - база отображающего вектора,

n

C = - d * S Dm*Im (3.8)

m=1

Числа Dm и C зависят только от строения массива - граничных пар его индексов и длины элемента. Граничные пары используются также для контроля правильности индексов при выполнении программы.

Таким образом, для вычисления адреса элемента по его индексам нужна база B отображающего вектора и дескриптор массива - определяющий вектор из 3*n+2 целых чисел:

n; C; n чисел d*Dm; n граничных пар I1, K1,..., In, Kn.

Для массивов с одинаковыми описаниями транслятор создает общий дескриптор.

Для доступа через дескриптор к элементам массива перед каждой операцией с элементом транслятор вставляет довольно громоздкий фрагмент программы, вычисляющий адрес этого элемента по формуле (3.7) и содержащий n сложений и n умножений, а для проверки правильности индексов требуется еще 2*n сравнений.

Таким образом, любая операция с элементом массива, особенно многомерного, требует много памяти и времени. Поэтому следует минимизировать число таких операций, особенно внутри циклов.

Пример 3.17. Определение дескриптора массива. Требуется составить функцию зависимости адреса элемента от его индексов для доступа через дескриптор к элементам целочисленного массива с данным Pascal-описанием

Y: array [1.. 3, 0.. 2, 2.. 3] of integer;

I1 K1 I2 K2 I3 K3

Здесь n = 3, d = объем(integer) = 2 байта.

Если быстрее изменяется правый индекс, то по формулам (3.5) и (3.8) найдем

D3 = 1, D2 = D3*(K3-I3+1) = 1*2 = 2, D1 = D2*(K2-I2+1) = 2*3 = 6,

C = - d*(D1*I1 + D2*I2 + D3*I3) = -2*(6*1 +2*0 + 1*2) = -16.

Подставив найденные величины в формулу (3.7), получим требуемое выражение

адрес(Y[i, j, k]) = адрес(Y[1,0,2]) - 16 + 12*i + 4*j + 2*k.

Для случая, когда быстрее изменяется левый индекс, аналогичным образом по формулам (3.6), (3.8) и (3.7) получим

D1 = 1, D2 = D1*(K1-I1+1) = 1*3 = 3, D3 = D2*(K2-I2+1) = 3*3 = 9,

C = - d*(D1*I1 + D2*I2 + D3*I3) = -2*(1*1 +3*0 + 9*2) = -38.

и окончательный результат

адрес(Y[i, j, k]) = адрес(Y[1,0,2]) - 38 + 2*i + 6*j + 18*k

Вместо использования формулы (3.7) и дескриптора можно (как делается, например, в языке C) рассматривать многомерный массив как одномерный массив массивов, а индексные скобки [ ] как операцию доступа к элементу:

A[J] = *(A + J), (3.9)

где имя массива A обозначает базовый адрес массива; индекс J автоматически умножается на длину элемента массива (размер объекта, адресуемого указателем A); *(адрес) обозначает операцию обращения по адресу – значение элемента с заданным адресом. При этом индексы изменяются от 0, а операции [ ] выполняются слева направо. Например, трижды применяя формулу (3.9), для трехмерного массива Z получим:

Z[i][j][k] = *(*(*(Z + i) + j) + k) (3.10)

Для n-мерного массива в этом случае, как и при доступе через дескриптор по формуле (3.7), потребуется n сложений, но вместо n умножений используется такое же количество обращений по адресу, выполняемых на порядок быстрее, чем умножения.

Этот метод позволяет экономить время, но требует больше памяти (для хранения структуры указателей).


Дата добавления: 2015-09-27 | Просмотры: 442 | Нарушение авторских прав







При использовании материала ссылка на сайт medlec.org обязательна! (0.004 сек.)