28642

Использование указателей для представления динамически структур данных

Лекция

Информатика, кибернетика и программирование

Оригинальные функции для ASCIIZ-строк включают функции сравнения строк (с учётом или без учёта регистра символа), инициализации строки, стирания строки, определения вхождения символа в строку (первого или последнего вхождения), специальные функции копирования и некоторые другие. Работа с этими функциями требует некоторых знаний механизма указателей.

Русский

2013-08-20

59 KB

1 чел.

Лекции 24-25: Использование указателей для представления динамически
структур данных.

1. Тип Pchar и "строки, заканчивающиеся нулем".

2. Линейные списки и очереди.

3. Кольцевые списки.

4. Использование указателей для обработки деревьев.

 

1. Тип Pchar и "строки, заканчивающиеся нулём".

Описанные ранее строки (называемые строками ASCII), как указывалось, могут иметь максимальную длину только 255 символов. В то же время API-функции Windows, а также язык С используют другой тип строк - "строки, заканчивающиеся нулём" (называемые ASCIIZ-строками). Это - строки, которые ꗬÁIЙለ¿ကЀሢ橢橢뎲뎲Й鈰
ጕ
Ɠ￿ 锞锞锞5镓Ô阧Ô電ꄠǴꌔf電हૌ晩嘕|嚑晩晩電изован в версии  Borland Pascal 7.0 специальным модулем Strings, в котором содержатся функции обработки таких строк и преобразований между строками ASCII и строками ASCIIZ.

Тип PChar является указателем на область памяти, где размещена строка, заканчивающаяся символом #0. Сама строка представляет собой массив вида:

array [0..K] of Char; где: K - количество символов строки.

В отличие от строки string в "строке, заканчивающейся нулем" первый символ имеет индекс 0, а последний - K-1. Символ-терминатор #0 размещен в позиции K и недоступен для прикладной программы.

Замечание

Все стандартные процедуры и функции, рассмотренные для типа string, также применимы и для строк типа PChar. Для определения длины такой строки s можно использовать функцию Length(s), но не ord(s[0]).

Функции над ASCIIZ-строками (все они имеют префикс Str) можно разделить на три группы: аналоги функций для ASCII-строк, оригинальные функции (не имеющие аналога среди функций ASCII-строк) и функции преобразования.

Функции - аналоги: StrCopy, StrPos, StrLen, StrCat.

Оригинальные функции для ASCIIZ-строк включают функции сравнения строк (с учётом или без учёта регистра символа), инициализации строки, стирания строки, определения вхождения символа в строку (первого или последнего вхождения), специальные функции копирования и некоторые другие. Работа с этими функциями требует некоторых знаний  механизма указателей.

Функции преобразования: преобразование из ASCIIZ к ASCII (StrPas), из ASCII к ASCIIZ (StrPCopy).

Чтение и запись ASCIIZ-строк поддерживается обычными стандартными процедурами: read, readln, write, writeln.

2. Линейные списки и очереди.

Одной из самых распространенных динамических структур данных, легко организуемых с помощью указателей, являются линейные списки. 

Линейный список - линейная последовательность произвольного числа компонент (элементов списка), каждый из которых непосредственно связан со следующим или/и предшествующим элементом. Список однонаправленный, если в нём имеется только связь с предшествующим или только со следующим элементом. Список двунаправленный, если в нем имеется связь, как с предшествующим, так и со следующим элементом.

Построение списков с помощью указателей позволяет размещать элементы списка в динамической памяти независимо друг от друга (т.е. необязательно сплошным массивом адресов), что придает спискам бóльшую гибкость по сравнению с обычными массивами. Над такими списками легко выполнять операции включения элемента в любое место списка или удаления произвольного элемента из списка (без перемещения остальных элементов в памяти), однако, доступ к любому элементу  только последовательный (через голову списка). Переменная-указатель выполняет в списке роль связи между соседними элементами.

Линейные списки часто используются для представления и обслуживания очередей. Характерным для очередей является её естественный порядок: каждый новый элемент помещается в "хвост" очереди. Различают две дисциплины обслуживания очередей:

FIFO  (first input first output) - первым пришёл, первым обслуживается.

LIFO  (last input first output) - последним пришёл, первым обслуживается.

Дисциплина FIFO соответствует классической очереди, однако, в ряде случаев используются очереди с дисциплиной LIFO (такие очереди распространены в приложениях информатики, например при анализе иерархически вложенных языковых конструкций, а также в некоторых технических системах - обоймы патронов в автоматическом оружии).

Очередь с дисциплиной обслуживания LIFO называется стеком, а с классической дисциплиной FIFO - магазином.

Пример программы создания очереди - FIFO был приведен выше (список телефонов). Аналогичная программа для стека телефонов (имеющая смысл для определения, кто звонил последним) приведена ниже.

       program stack_tel;{создание стека телефонов}

       uses CRT;

       type ref=^inf; {тип - Указатель на запись }

                inf= record name,adr,tel:string;

                                    pred:ref 

                       end;

       var head,p:ref; {указатель на начало стека и текущий}

             s:string;

            procedure write_stack(start:ref);

       {вывод всех элементов стека}

        begin repeat with start^ do

                begin writeln(name); writeln(adr); writeln(tel);

                end; start:=start^.pred

                  until start=nil

       end{write_stack};

        BEGIN TextBackground(cyan);TextColor(white);ClrScr;

                    window(10,5,40,20);TextBackground(green); ClrScr;head:=nil;

             repeat  new(p); with p^ do {заполнение полей записи}

                  begin write('Ф.И.О.:'); readln(name); write('Адрес:'); readln(adr);

                            write('Телефон:');readln(tel);pred:=head;

                  end;  head:=p;readln(s)

             until (s=' '); writeln('Стек телефонов создан');

             write_list(head);  writeln('Конец вывода стека');

        END{list_tel}.

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

3. Кольцевые списки.

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

       program RING_METRO; {Кольцевая линия Московского метро}

       type link=^nest;nest=record forw,back:link;inf:string end;

       var r,r1,start:link;f:text;c,c1,c2:string;dir:Boolean;L:byte;

       procedure insert(el1,el2:link);{вставка el2 после el1}

           begin el2^.forw:=el1^.forw;el2^.back:=el1;el1^.forw^.back:=el2;el1^.forw:=el2;

           end{insert};

       procedure dir_path(var d:Boolean;s1,s2:string);{направление}

       var g:link;j1,j2:byte;er1,er2:Boolean;

           begin j1:=0;j2:=0;g:=start;er1:=false;er2:=false;

            repeat g:=g^.forw;  if g^.inf=s1   then

              repeat g:=g^.forw;j1:=j1+1;er1:=(g^.inf=s1);d:=(2*j1<L);

              until (g^.inf=s2) or (g^.inf=s1)  else  if g^.inf=s2   then

              repeat g:=g^.forw;j2:=j2+1;er2:=(g^.inf=s2);d:=(2*j2>L);

              until (g^.inf=s1) or (g^.inf=s2);

            until (g=start) or (g^.inf=s1) or (g^.inf=s2);if er1 or er2 then

   begin write('Ошибка в названии ');

           if er1  then write('конечной') else write('начальной');writeln(' станции');halt

   end; if j1+j2=0 then begin writeln('Ошибка в названиях станций');halt end

           end {dir_path};

       procedure write_path(d:Boolean;s1,s2:string);{кратчайший путь}

       var p:link;

           begin p:=start; while not(p^.inf=s1) do p:=p^.forw;

             repeat writeln(p^.inf);if d then  p:=p^.forw else p:=p^.back;

             until (p^.inf=s2) ; writeln(p^.inf);

           end {write_path};

       BEGIN writeln('КОЛЬЦЕВАЯ  ЛИНИЯ  МОСКОВСКОГО МЕТРО');

             new(start);r:=start;r^.forw:=r;r^.back:=r;assign(f,'names_st');{$I-}reset(f);{$I+};

            if IOResult<>0 then begin writeln('Не найден файл names_st');halt end;

             L:=1;readln(f,r^.inf);while not eof(f) do{создание кольца }

             begin readln(f,c);new(r1);insert(r,r1);r1^.inf:=c;r:=r1;L:=L+1 end;

             writeln('Задайте начальную и конечную станции:');    readln(c1);readln(c2);            dir_path(dir,c1,c2); writeln('Кратчайший путь:');write_path(dir,c1,c2);

       END{ring_metro}.

4. Использование указателей для обработки деревьев.

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

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

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

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

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

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

 type link =^node; node = record c:char;count:word;left,right:link end;

 Программа имеет следующий вид:

       program frequency_letters; {Частота вхождения  латинских букв в строку}

       type link=^node; {тип - Указатель на запись}

               node=record c:char;count:word;left,right:link end;

      var root:link; {Корень дерева поиска} symb:char;j:word;

             L:set of  char; {множество символов}

             s:string; { вводимая строка }

       procedure insert_tree(var r:link;ch:char);{Вставка ch в дерево}

            begin if r=nil then

                  begin new(r);with r^ do begin c:=ch;count:=1;left:=nil;right:=nil end end

                                  else with r^ do

                if ch<c then insert_tree(left,ch)   else

                if ch>c then insert_tree(right,ch) else count:=count+1;

            end{insert_tree};

      procedure print_tree(r:link); {Печать количества вхождений букв }

            begin if r<>nil then with r^ do

                  begin print_tree(left);writeln(c,':',count); print_tree(right) end

            end{print_tree};

       procedure search_tree(r:link;ch:char); {Поиск ch и печать}

            begin if r=nil then writeln(ch,':0') else with r^ do

               begin if ch<c then search_tree(left,ch)   else

                         if ch>c then search_tree(right,ch) else writeln(ch,':',count)

               end

            end{search_tree};

  BEGIN L:=['A'..'Z']; root:=nil;writeln(' Введите текст:');while not eof do

         begin readln(s);for j:=1 to length(s) do

     begin if upcase(s[j]) in L then insert_tree(root,s[j]) end;

         end; writeln('СПРАВКА ПО ЧАСТОТАМ ЛАТИНСКИХ БУКВ:');

                 while not eof do begin readln(symb);search_tree(root,symb) end;

                   write('Печатать по всем буквам?(Y/N)');readln(symb);

                   if symb<>'N' then print_tree(root);

  END{frequency_letters}.


 

А также другие работы, которые могут Вас заинтересовать

38941. Применение лидаров для исследования загрязнения вод 226.5 KB
  Пробы любой воды за исключением воды наивысшей чистоты флуоресцируют. Так называемая синяя флуоресценция воды является источником значительных трудностей при флуоресцентных исследованиях но такая флуоресценция полезна для изучения качества воды с использованием лазерного дистанционного зондирования ЛДЗ. Очищенные сточные воды предприятий целлюлознобумажной промышленности можно контролировать с помощью флуоресцентного метода т. эти воды содержат сульфонат лигнина высокой концентрации.
38942. Лидар для исследования состава атмосферы 59.5 KB
  Лидар для исследования состава атмосферы Литвинов Действие лидаров Л этого типа чаще всего основано на неупругом обратном комбинационном рассеянии ОКР зондирующего лазерного излучения ЛИ молекулами газовых компонент ГК имеющих вынужденные колебательновращательные энергетические переходы при взаимодействии с зондирующим ЛИ. При этом с помощью Л по смещению спектральных линий принимаемого излучения ОКР устанавливается наличие в исследуемом участке атмосферы атм определенных ГК а по интенсивности этих линий концентрация...
38943. Лидар для измерения концентрации озона в атмосфере 34 KB
  Действие лидаров для исследования атмосферы основано на том что лазерное излучение распространяясь в реальной атмосфере оставляет в ней свет вызванный взаимодействием квантов излучения с неоднородностями в атмосфере. Это взаимодействие проявляются в упругими неупругом рассеянии лазерного излучения в атмосфере при котором обрся эхосигналы лаз. рассеяния они несут информацию о сввах и параметрах атмосферы что следует из формулы для пиковой мощности принимаемого эхосигнала: Pи пиковая мощность зандирующего импульса лаз. Зрачка...
38944. Применение лидаров для обнаружения и идентификации нефтяного поверхностного загрязнения вод 564 KB
  Если ЗЛИ имеет соответсвующую длину волны УФ то возникает флюоресценция свечение нефтяного пятна: стрелки 22 а также комбинационное рассеяние КР ЛИ стрелки 33 и на молекулах воды стрелки 44. Жизнеспособность фитопланктона свидетельствует о чистоте воды. Эффект флюоресценции воды можно использовать для индикации сильных органических загрязнений и т. О наличии на поверхности воды нефтяной пленки можно судить и по интенсивности отраженного ЛИ 11.
38945. Определение, назначение, действие, применение и классификация лидаров 244 KB
  Действие лидара основано на таких свойствах лазерного излучения как высокая мощность квазимонохроматичность направленность и малая длительность импульсов и таких физических процессах как упругое молекулярное и упругое аэрозольное рассеяние упругое резонансное и неупругое комбинированное рассеяние флюоресценция и поглощение лазерного излучения при его взаимодействии с атомами молекулами и другими частицами веществ в окружающей среде. При распределении зондированного лазерного излучения ЛИ от передающего устройства лидара в исследуемой...
38946. Типы и характеристики излучения лазеров для лидаров 26.5 KB
  Если в лидаре используется лазер с перестраиваемой частотой или длиной волны зондирующего излучения υи = с λи то лидар можно применять для лазерного химического анализа состава атмосферы Земли на основе эффекта комбинационного рассеяния молекулами химических соединений компонент атмосферы. Лидар с перестраиваемой λи зондирующего лазерного излучения может быть использован для химического анализа атмосферы Земли путем измерения интенсивности после прохождения исследуемой трассы. Поэтому исследуя зависимость интенсивности прошедшего в атмосфере...
38948. Физические процессы взаимодействия лазерного излучения с веществом 558 KB
  Физические процессы взаимодействия лазерного излучения с веществом. Действия лидаров для исследования атмосферы основано: лазерное излучение распространяясь в реальной атмосфере оставляет в ней след вызванный взаимодействием фотонов лазерного излучения с атомами и молекулами газов частицами аэрозолей и неоднородностями атмосферы обусловленными турбулентными вихревыми движениями воздуха. Это взаимодействие прежде всего проявляется в упругом и неупругом рассеянии лазерного излучения в атмосфере при которых в частности образуется...
38949. Методические погрешности анализа спектра с использованием процедуры ДПФ. Растекание спектра (эффект Гиббса - leakige). Слияние отсчетов спектра 20.21 KB
  Методические погрешности анализа спектра с использованием процедуры ДПФ. Растекание спектра эффект Гиббса lekige. Слияние отсчетов спектра.Эффект появления ложных спектральных составляющих При расчете параметров процедуры ДПФ выбирают некоторую граничную частоту fg из логарифмического уравнения и находят интервал дискретизации t как: t = 1 2 fg 1.