Энциклопедия Turbo Pascal. Главы 1-4
Страница 36. Применение массива указателей для организации разреженных массивов


Применение массива указателей для организации разреженных массивов

     Предположим, что электронная матрица имеет размеры 26х100 /с
А1 по Z100/ и состоит всего из 2 600 элементов. Теоретически мож-
но использовать следующий массив записей:
       str9 = string[9];
       str128 = string[128];

       CellPointer = CellPointer;

       cell = record
         CellName:str9;
         formula:str128;
       end;
     var
       pa:array[1..2600] of cell;

     Однако, 2 600 ячеек,  помноженные на 128 (размер одного поля
для формулы),  потребует 332 800 байт памяти под довольно неболь-
шую электронную таблицу. Такой подход, очевидно, нельзя использо-
вать на практике. В качестве альтернативы можно использовать мас-
сив  указателей  записей.  В  этом случае потребуется значительно
меньше памяти, чем при создании всего массива. Кроме того, произ-
водительность будет значительно выше,  чем при использовании свя-
занного списка или дерева.  Для этого метода  данные  описываются
следующим образом:

     type
       str9 = string[9];
       str128 = string[128];

       cell = record
         CellName:str9;
         formula:str128;
       end;
     var
       sheettarray[1..10000] of CellPointer;

     Этот массив меньшего размера можно использовать для содержа-
ния указателей на информацию, введенную пользователем в электрон-
ную матрицу. При вводе каждого элемента указатель на информацион-
ную  ячейку  помещается  в соответствующее место массива.  Рис.16
иллюстрирует структуру памяти,  когда разреженный массив строится
на основе массива указателей.

                          a
     ----T----T---T----T-----------T----T---¬
     ¦   ¦1nil¦   ¦1nil¦           ¦1nil¦   ¦
     L-+-+----+-+-+----+-----------+----+-+--
       ¦        ¦                         ¦   ---------------¬
       ¦        ¦                         L---¦2info for A[n]¦
       ¦        ¦                             L---------------
       ¦        ¦
       ¦        ¦   ----------------¬
       ¦        L-- ¦2 info for A[a]¦
       ¦            L----------------
       ¦   ----------------¬
       L---¦2 info for A[l]¦
           L----------------

    Рис.16. Использование массива указателей для организации раз-
реженного массива:

1 - нулевое значение указателя; 2 - информационные поля соответс-
твующего элемента.
     Перед первым использованием  массива  указателей  необходимо
каждый  элемент  установить в нулевое значение,  что означает от-
сутствие элемента в этой позиции.  Используйте следующую функцию:
    procedure InitSheet;
    var
      t:integer;

    begin
      for t :=       1 to 10000 do sheet[t] :=  nil;
    end; { конец блока инициализации }

     Перед написанием процедуры вставки следует запрограммировать
функцию поиска индекса.  Эта функция находит соответствующий  ин-
декс массива указателей по заданному названию ячейки.  При поиске
индекса предполагается,  что все названия  начинаются  с  большой
буквы, за которой идет некоторое число, например, В34, С19 и т.д.
Эта функция приводится ниже на следующей странице.

     Эта функция позволяет при реализации процедуры вставки
    { эта функция  определяет  индекс  указанной  ячейки   }
    function FindIndex(i: CellPointer): integer;
    var
      loc,temp,code:integer;
      t:str9;

    begin
      loc :=  ord(i^.CellName[1]);
      t :=  copy(i^.CellName,2,9);

      val(t,temp,code);
      loc :=  loc+(temp*20);
      find :=  loc;
    end; { конец функции поиска индекса }


соответствующую позицию массива указателей для каждой ячейки. Как
видно, поиск нужного индекса выполняется просто и быстро, так как
нет необходимости выполнять последовательный просмотр. Этот метод
иногда называют прямым хешированием,  поскольку индекс ячейки па-
мяти определяется непосредственно по  заданному  элементу.  Когда
пользователь  вводит  формулу для ячейки,  то эта ячейка /которая
задается своим обозначением/  задает  индекс  массива  указателей
"sheet". Индекс определяется по обозначению ячейки путем его пре-
образования в число с помощью функции FindIndex. Вставка осущест-
вляется с помощью следующей процедуры:

    procedure Store(New: CellPointer);
    var
      loc:integer;

    begin
      loc :=  FindIndex(New);
      if loc>10000 then WriteLn('Location out of bounds')
      else sheet[loc] :=  New;
    end; { конец процедуры вставки }

     Поскольку каждая  ячейка  имеет уникальное обозначение,  она
будет иметь также уникальный индекс. Поскольку используется стан-
дартная кодировка символов, указатель каждого элемента будет пра-
вильно помещен в массив. Если вы сравните эту процедуру с вариан-
том для связанного списка,  то вы обнаружите, что она значительно
короче и проще.
     Функция удаления  также  выглядит  короче.  При  вызове этой
функции задается индекс ячейки и возвращается указатель элемента.
Кроме того, освобождаемая память возвращается системе:
    { удаление ячейки из массива }
    procedure Delete(r_cell: CellPointer);
    var
      loc:integer;
    begin
      loc :=  FindIndex(r_cell);
      if loc>10000 then WriteLn('Cell out of bounds')
      else
      begin
       Dispose(r_cell);
       sheet[loc]:=nil;
      end;

    end; { конец процедуры удаления }

     Если вы сравните эту процедуру с версией,  использующей свя-
занный список или дерево, то обнаружите, что она значительно про-
ще и выполняется быстрее.
     Следует помнить, что сам массив указателей требует некоторо-
го дополнительного расхода памяти под каждую ячейку.  В некоторых
случаях это является серьезным ограничением.

 
« Предыдущая статья