Лекции по информатике (984119), страница 3
Текст из файла (страница 3)
Однако частое определение длины (0(Ж)) может серьезно отразиться на быстродействии программ работы с таким списком. епс1; епс1„ сЭункдия 13е1еСе() удаляет элемент, на который указывает итератор, возвращая в качестве результата итератор, ссылающийся на следующий за удаленным элемент. Если итератор указывает на тслрлслглнатор, то удаления не происходит, и функция принимает значение терминатора списка ВаяС().
250 ГппсС1оп 1пяегС(ъсаг 1: Ь1яС: ъсаг ! 1СегаСог: С: Т): 1гегаСог; айаг гея: 1Сегагог: Ьеи1п пеис(гея.пос!е): 1Г(гея.пос1е лл!1) СЬеп 1пяегС: =-- Ьая1,(1) !' Возврат терминатора! 3 е1яе Ьеи1п гея.пос1е .с1аСа ь — с: гея,пос1е" тех! г л.пос1е; гея.псн1е".ргел: !.пос1е".расу: гея,пос1е".ргеу".пехС:= гея.пос1е; л .пос1е .ргеу гея.пос1е; 1. я1ие: - 1. я!хе - 1; 1пяегС; гея; !с Возьрапл итератора на добав.аслннелл! элемент л! 1СегаСог 1пяег! (Ь1яСл 1, 1Сегагог ~ сопяС Т С) 1Сегагог гея -- ( пла11ос(я1хеоГ(яСгпсС 1!ею)) 1; 1С' (! гея . пос1е) геСпгп Ьаяг(Ц; гея.
ллос1е — >с1а!.а = гея. пойе — >пехС - л — >пос1е; гея.пос1е — >ргеу -- л — >пос1е — >ргеу; гея . нос1с —. 1эгсу — ллех! " гея.глос!е; л — >пос1е — >ргеу гея.пос1е: 1 — >я!хе — , '+; геСпгп гея. Функция Рев1тоу() уничтожает список, перебирая его элементы и удаляя их.
Зал<етим, что можно было бы вызывать фупкциго Ре!<.1с(), передавая ей в качестве аргумента указатель на текущий первый элемент списка, Гата!() до тех пор, .пока список нс станет пуст, после чего удалить терминатор. Но тогда код функции стал бы короче всего па одну-две строки. а накладные расходы на вызов функций увеличили бы время работы Ревгтоу(). ГппсС1ог! 1)е1еге(ъаг1: 1!вг,, ъаг ! 1гегасог) : 11егатог; л<аг гев: 1ге!.аго! ! Ьеиш гев:: — 1~вас(1); К(Е<1<га1(1, гев)) сЬеп 1!е1< се: — гев е1ве Ьеиш гсв,псн1е: !.пос1е,пехг: гев.пос1е .ргег ь= !.пос1е .ргег; ! .
ргег".пехг — гев.пос1е; 1. в!хе:=- 1. в!хе — 1: Йврове ( ! . пос1е); ! . пос1е: — п!1: Бе!еле ! гев: епс1; еп<1; ргосес1пге Ревггоу(л<аг 1: 1.!вГ): л<аг 1, р1: !~!гоп!; Ьеиш 1, !!еа<1 .пехг; лл<Ы1е(! <> 1.!<на<1) с1о Ье! ш р! ! 1.!<еа<1: ! ".пехс; Йвров<', (р!); епс1; Й арове(1 . )геа<1); 1, 1н ас1: и!1; 1гстагог !Ое!еге(1.!вт* 1, 11егагог* !) ( 1гегагог гев — 1;авс(1); Г(Е<1<га1(1, Йгев)) геФпгп гев; гев. пос1е — ! — >по<1е — >пехг; гсв.
пос1е — >рг<вл — ! — >пос1е — >ргеь-! ! —.-ргегс — >псх! -- <ев.по<!е; 1 > '.. †. "!хе — — ' 1гее ( ! — >пос1е): ! — - пос1е — О: ге$пгп гев; л оЫ Певггоу(Ь!вгэ 1) ( вСгисФ 1гсш* ! — ! — >!<еа<1 — >г<ехг! лл<Ь11е(! ! 1 — >!<еас1) в$гпс$ 1гегг!~ р! — 1 — >1<еа<1; . ! — >цех<; 1гсе(р!); 1гсе (1 — > 1<еас1); 1 — >11еас1 О; !.
яис:= 0; еп<1; ! — >э!ие 0; Как и в с»уча<. о >ере><и, возможна р<.ку1>синг>ая версия программы уни <тол<ения, но никакого практического эффекта она не дает. 5.6.3.3 Реализация на массиве сопвС 1пС Р001. 31Хà — 100: сопвС РООЬ 31ХГ -- 100; Суре 1.!эС вЂ” гесог<1 1>еа<1: Р11ет; яяе: 1пСеяег; 1ор; Р1Сеп>; ба<а: аггау!О..Р001. 51ХЦ оС'1Сеш; еп<1; Суре<1е1 вСгпсС ( вСгпсС 1Сепи !>еа<1; 11>С а!ие; вСгпсС !Сени Сор; эСгпсС 1Се>т> <!а<а!Р001. 51ХЕ ! 1~; 1йэС; Теперь рассмотрим функционирование списка.
Сначала спи< ок пуст и весь массив <1аСа 252 Приведенная выше реализация списка, на динамических структурах обладает существенными преимуществами, например, потенциальной бесконечностью списка: его длина статически не определена и ограничена лишь размером доступной памяти всей вычислительной системы. Однако при очень частых операциях модификации списка запросы к распределителю памяти могут опять-таки нелучшим образом отразиться на быстрочействии программь>.
В этом случае, а также если известно, что длина списка ни при каких условиях пе превысит за„><анной величины (обозначим ее уже известным идентификатором РОО! ЫЯЕ), приоеган>т к более эффективной реализации списка на массиве. При переходе от динамического выделения памяти к статическому есть возможность повторного использования болыпей части уже написанного кода. В частности, предложенные итера,торы полностьн> совместимы с динамической версией списка, поскольку нет никакой необходимости менять тип элемента списка (можно было бы отказаться от указателей и перейти к индексам, но поскольку и целочисленные индексы, и ссылки занимая>т в памяти машинные слова одинакового размера, никакого выигрыша в памяти это не даст, но потребует весьма существенной модификации кода).
Однако, программировать все-таки придется. Попробуем сохранить итераторы и отказаться от использования стандартного распределителя памяти, вызываемого посредством пе»« и <!!ерове. Описание типа список в данной реализации будет несколько шире. К уже описанным полям Ьеа<! и яяе добавим Сор и <1аСа. В поле 1ор мы будем хранить ссь<лву на, первый свободный элемент массива да1а.
В самом массиве ИаСа кроме места для хранения РООЛ Я>'УЕ элементов предусмотрим еще одну дополнительную компоненту для хранения терминатора. Введение полей Сор и <1а1а в структуру. списка вызвано необходимостью явного представления ранее находившегося за кулисами резидентного массива для реализации списка; 1о1> играет роль ссылочного выходного параметра процедуры порождения нового элемента списка пеи, указывая ссылочным (не индексныкл!) образом на первый свободный элемент массива. уоЫ Сгеа1е(1лэ1э 1) ш1 1; Гог(! - О:, ! < Р001.
Б1ХГ: ! ! ! ) 1 — ><лага[!].пех!, -- Й(! — >с!ага[! !- 1]) ргосес1пге Сгеа$е(ъаг 1: 1лас); уаг 1: ш$едег; Ьепш 1ог 1: - О $о Р001. Б1Хà — 1 с1о !.<1ала[! ]. пех1: — 0(!.с!а$а[! -! Ц); !.с1а1а[Р001 Б1ХŠ— 1].пех1: -- и!1; ! . !геас1: О(!.<!а1а[Р001.
Б1ХЕ]); 1.аеас!".ргеу г-- О(!.!геас1); 1. !<еас1".пехг: — О(!.!<еа<1); ! .1ор: — О(!.<1а1а [О]); 1. в!ке: — О; епс1; 1 — ><1а1а[Р001 Б1ХŠ— 1]шех1 -- О; 1 — >Ьеас1 -- вс(! — >с1ага[Р001. Б1ХЕ]); 1 — >Ьеас1 — >ргеу — 1 — >!<еас1 — >вехе — ! — >!<на<1; ! — >гор — в< (! — > <1ага [О]) ! 1 — >а!ке =- О; Заметим, что в < форматированном таким образок< массиве свободные элементы образуют односвязный список. Тип 1 <в1 содержит ссылку на его начало, поэтому из списка легко брать элементы.
Вместо вызова функции певуч необходимо лигпь взять значение переменной 1ор и передвинуть 1ор на следукнций элемент списка, .удаляя тем самым этот элемент из списка свободных. Правда.,не всегда можно передвинуть Йор,поскольку в нем может содержаться ш1, разыменование которого приведет к исключительной ситуации. Функция 1пвег1() проверяет все условия и не допускает такой ситуации, возвращая 1 аИ() в случае переполнения буфера.
Сравнение этой функции с ее вариантом для динамического списка, показывает, что благодаря избранному подходу пришлось лишь переписать одну строку и добавить одну строку Весь остальной код остался неизменным: 1ппс$1оп 1пвег$(ъаг 1: 1лМ; уаг ! 11ега!ог: <: Т): 1!ега<ог; уаг гев: 11ега1ог; Ьепш 1гегагог 1пвег1,(1лэ1~ 1, 11ега!от* г, сопят Т 1) ,~'л Првдосгпавленл<е свободного считается свободным, а элемегп <1а!п[Р001. с11Х1д] отводится под терминатор.
Свободные элементы списка с индексами от О до Р001, 31ХŠ— 1 связываются друг с,чругом, причем волго пех! г-того элемента присваивается ссылка на <' ! 1-ый элемент массива. Последний свободный элел<ент массива не связан ни с каким другим, и в его поле пех1 х!эанится значение ш1.
Ксп<понента 1о1< любо~~, в да~~о~ случае пус~~~~, с~~с~а указывас'т на первый из свободных элементов, а терминатор пустого списка так же, как и его динамический аналог, по-прежнему удостоверяет пустоту списка и устанавливает обе свои ссылки на себя. Функция Сгеа1с() создает необходимую адресную разметку суррогат вышеописанной чинамической структуры, пользуясь адресной функцией Вог1апс1, СМ3 Рааса! Ф (синоним АсЫг).
Другим спосооом унификации кода с динамической версией было бы первоначальное получение ссылки на массив посредством пеи< с последующим преобразованием ее в целое число с помощью вариантной записи и дальнейшими манипуляциями с индексными переменными, базирующимися на полученном таким образом адресе. Этот способ менее приемлем для компилируемых языков без динамических структур данных, таких,как Фортран и Бейсик. епс1; епс1; Функция 1Эе1е1е(), как и прежде, удаляет элемент из списка, но возвращает память не операционной системе, а сттиску свободных элементов, помещая этот элемент в начало списка.