Искусство программирования на Си (984073), страница 33
Текст из файла (страница 33)
ся на определенной позиции. Это легко сделать, ис- ке через дорогу. Это может привести к путанице, пре- Если пользователь-программист ласт нам адрес элеЕсли для сохранения это~о обьскта недостаточно дотвратить которую способна только работа над кодом мсн~а, находящегося внутри списка, то в результате мы ьпс Бьврдаса(БЬЫБт *геев, памяти, завершаем работу безопасным способом, освопрограммы. пол>чим расщепленный список. У этою списка будет 1пг Иеытав, бождая память, которую выделили для структуры чп)д *ИеыОЬ есе При втором добавлении начинаем построение спис- два начала, один из которых — только что добавленный чп)д ИеыОЬ)есе, ВЬЬ(аТ, так что лля нового элемента память совсем не алге Е Иечв1ге) ка.
Кажлый элемент списка указывает на следующий элемент. Какой бы заманчиво новаторской ни казалась выделяется. Такие обслуживающие действия обязательэлемент, а указатель последнего элемента имеет значе- эта идея расщепленного списка, она полна опасностей 1пе веап1г = Бь Бвссевя; ны, однако они имеет тенленцию значительно увеличиние )ЧЬ'ЬЬ. и л>чше о ней не вспоминать.
вать размеры кола но срапнению с простой рсализациПри работе с лвусвязными списками эта проблема чо(д *рм пе Бщцщ(БЬЫВт **ьсвв, еи Наградой за это будет возлюжность использовать исчезает (более подробно об этом речь пойдет далее), лпе таО, щот кол со значительной долей уверенности, что ои >т(веял>ге > 0) чоьд «ОЬ)есс, так лак по своей природе они позволяют перемещаться выдержит работу в самых разных приложениях. ( алке Е Блае) по списку в обратном направлении. геа11ос(1гев->ОЬ'есс, Иеывлге Данная функция вставляет элемент в список после ( Лобавлять элементы в начало списка выгодно, так гт(ИОЬЬ З= р) БЬЫБт *Иеы1еев; того элемента, алрес которого ей передается. Хотелось как зто выполняется быстро.
Однако иногда в прилолпе Вевп1Г = ЯЬ БОССЕБЯ; бы так:ке иметь возможность вставлять новый элел1ент женин может потребоваться поместить новые элеменпсред тем элементом, адрес которого передастся в фун- вешвоче(1ееш->ОЬ)есе, ИеыОЬ)есе, аааегг(1геш 3= ивьь); ты в конец списка. киню. Эту задачу выполняет следующая функция.
Од- ' .иеывлве); Оразтыс абстрант нас структуры данны» Глава 11 Организация данны» Часть и (Нельзя занрститьсмуделатьэто,нсусложняявогром- аьывт *вьоаьесатьхе(вьыат *тсев> функциях йяог( и ЬвеагсЬ, частью списка параметров зьывт 'тьха1сев; нои степени код, и такое решение затрулнило бы < которых являются указатели на функции. Функции ОЬЫЗТ *Яехгиоде = ВОЬЬ; пользование библиотекой, от чего пострадали бы БЕ>ра(й требуется указатель на функцию, принимаю(от(твьагеев = Ывг; пользователи-программисты, соблюлаюшис правила.) 11(<сев <= ИОЬЬ) ш> ю три параметра: тсг, указатель на объект некоторо- О == вевп1с аь тьхв1сев )= яцьь< Однако, если предоставить простой механизм, обсспс- < го типа и указатель на структуру, солержашую аргумсн- ТЬ(вггев = Тьзвгеев- Яехг) чиваюший ему доступ к данным более объектно-орисн- Яехьиоде = 1Сев->Яехг; ты (соли аргументы не требуются, этот последний ( тированным способом, то мозкно обоснованно ожидать, указатель может иметь значение )х(ИзЕЕ).
Тсг позволяет 11<ггев->ОЬ)есг .= ЯОЬЬ) У ' Тьхяггев->ОЬ)ест., что он будет поступать подобаюшим образом. ( создать внутри функции какой-нибуль оператор выбоАгэа)1 чаьв ВЬОагпаеа(аЬЫат *леев, (гее(1Сев->ОЬ)есС); ра на тот случай, если потребуется иметь дело с разны) 1пС 'Тав, ) ми вилами обьсктов. Функция БЕ%а(й просто проходит еьхе С *вахе) ггее(1Сев) < последовательно по всем элементам списка, вызывая для геспгп Кеап1с; каждого из них эту функцию и передавая в нес тсг, чоха *р = ЯОЬЬ; объект и аргументы.
В функции В(Луа(й прслполагаст- Вот и вес Теперь > нас есть все нсобхолимое, что11<1Сев <= ИОЬЬ) ся, что в случае успешного выполнения вызванная фун- бы облегчить работу с олносвязными списками. Итак, ( кция возврашаст О. Если какой-нибудь вызов этой Фун- как пользоваться этой библиотекой? давайте посмот- 11(таэ <и ЯОЬЬ) чо<д ВЬОе1еСеиехг(БЬЬ(ЭТ '1Сев) кции завершится аварийно (она возвратит нснулсвое рилз, как эзо делается,на примере программы тестово'Таэ = 1Сев->Тав; 11<ггев .= ИОЬЬ ЬЬ заев->Иехг .= ИОЬЬ) значение), фуззкция БЕИа(й прекратит проход по элс го драйвера.
( ментам списка. Она возвратит результат самого после<1[в<хе <= ивьь) 1сев->иехс = вьве1есетьза(1сев->иехс); диего вызова (который, если при прохолс глс-нибуль не Тестовый драйвер Организация данные Узраетые абгтрактные структуры данные Масть и Гпава 11 ЯМЙ )ае ва(а(гоьд) Применение структуры Е(ЕЕП )»4ЕО в нашем коде Руст->Рген->»ц»ех(->»дель (Но только при условии, что < носит довольно искусственный характер; информация, все элементы, входяшие в это довольно странное выра- ВООВ Воок(1 которую она содержит, поступив в структуре ВООК, жение, действительно существуют.
Если любое из этих ( ('Вхрегг С Ргодгаввьпд , 'аап дег Ыпдеа », Все. что требуется сделать, — воспользоваться опсрато- подвыражений принимает значение (н»НЕЕ, код рабо- ("С Ргодгаавгад РВОа", Яапвгь'), ром ь(геоГ Однако с помошью этои структуры иллюст- тать нс будет.) ( Сь+ Ргодгавв1пд Ьапдваде , яггопаггар ), рируется механизм применения параметра Агйя. Ранее было показано, как можно использовать мас('В1дог)СЬвв ьв С , яеддеыьсс ), сины переменного размера для хранения ~екстового Двусвязные списки файла в оперативной памяти, и тогда было высказано прсдположе ис, н, что можно было бы использовать этот Итак, использование односвязных списков сопрюкено вид структуры данных при написании программы тск- ("С Ргодгаьшгад Ьапдпаде", "КегпгдЬаа Ь В(годсе"», с рядок~ проблем, большая часть которых вызвана тем, стового редактора.
Однако этот подход чреват различ( Ььпах ОЬ1еавЛед , Впаагп аад Рагкег"), что невозможно возврашаться к началу списка. Все эти ными проблемами. Таким способом можно легко читать ('С Оп1еавЬед, "ВеаСЬС(е16 ь В1гЬу'», трудности мо кно решить путем добавления указателей файл, но при попьпке отредактировать сто сразу же с : в ае(егепсе Иаапа1 , "Вагвьвап ь Ягее1е возврата. При добавлении этих связей в односвязный возникнут трудности. Если, например, пользователь ( Ооя Ргодгаввегв ве(егеасе", Оессвапп ь зоЬавоа"), < с: Воы с Рг гав , о 'с 1 ь О 'с 1 ), список он становится двусвязным. нажимает на клавишу Ве(цгп, то он ожидает, что в ре- Двусвязный список отличается от олносвязного тем, дактируслюм файле будет начата новая строка.
Это оз- ( ОВ1Х Ов1еавЬед", Вагс авд Вогиагв") что элемент этого списка содержит не только указатель начает, что в массив должна быть вставлена новая стро)' на следующий элемент, но и указатель на предыдуший ка — и нс в конце (это было бы пустяковой задачей), а элемент. Это увеличивает наклалные расходы, связан- где-то в середине. Поскольку мы имеем массив указа- ЯЬЫЯР нЬ(ВС = ИОЬЬ; Организации данных Пинт не адан рентные етрЗи туры данных 1 Масть и Глава 11 Меы1сев = ва11ос(вгхеп( *Меы1сев); ( также перед данным элементом и после него Если спи- прилстся позаботиться о чстырсх указателях, таких как сок короткий, искоторыс из эпзх мест мог)т гоападать, указатели Реет и й(ех( нового элемента, указатель )ь)сх( ио, как мы увидим, это нс имеет значения.
предшествующего элемента и указатель Ргет последуюМеы1сев->Ргеч = Меы1сев->аеас = МОЬЬ; ыв11е(Ьгвс->Мехе 1= МОЬЬ) ( шсго элемента. Поскольку большой список можзео повея(сев->Вьге = В(хез Ььвг = ОЬОегвехь(Ь(вс) Вставка элемента в начало списка лучить только начиная с маленького списка, некоторые Меы1сев->ОЬ)есс = ва11пс(агае); ) из этих элсмситов могут отсутствовать, поэтому исобЧтобы вставить элемент в начало списка, необходимо ходимо быть осторожным со значениями )н(()ЕЕ этих ( ге(ига Ьзвсз вевсру(веы1сев->ОЬ)есг, ОЬ)есс, В(хе); ) жить, что пользователь-программист указывает имсино указателей.
иачазо списка, ио лучше вес-таки быль уверенным, чем е1ве Во многих функциях требуется вставлять некотории списка, можно будет вставить новый элемент перел иим прслполагать.) Для этого можно использовать функцию ( элемент в список, где этот элемент уже сушсствуст или после исто. Допустимо как одно, так и лругое, и С)ьОе(Е(гаг(). (гее(меы1сев)1 Например, элемент мог быль только что создан с помо- трудно выбрать одно из двух, ис зная особенностей и шью ф) икции С)ЕСгеа(еп, и гспсрь иужио вставить сто Ьпс ОЬВгерепд(ОЬЬхат **зьеп, специфики приложения. Поэтому леы реализовали оба иа соотвстствуюшсс место. Весь код указателей можно (пс Та Ч варианта. (Они очень похожи, и здесь показан только ) ипИ *ОЬ)ест, бедло бы поместить в каждую фуикцию, глс ои требу- один из них.) вгае Г ягхе) геспгп Меы1сев; ется.
Но имеет смысл выделить сто в отдсльиую функпс оьлддлгеег(оььгвт ннзсет, ) цию. При необходимости пользователь-программист 1вс Меап1Г гпс Тач, П з еа с ь-п ог ммист если хочет ожет выз- может вызывать сеиспосрслствсиио, но в большииствс чпгд ОЬ)есе ~~г!с Органа>анан данны> Прттые абгтрактныа струккщры данных Часть )! Глава 11 списка в лрутой. Такую операцию несложно выполнить, вьывт )1(Ыаь != ВВЬЬ! Уничтожение всего списка но при этол! на пользоватсля-программиста возлагается у+!Сева; Процесс уничтожсния всего списка очень прост, и, что ответственность закончить лолжным образом эту работу. хв()сева )= ювьь ьь 1сеюв )= ввьь! евкье[(Рг = ВЬСеьвсеч(всеч)! )= НСЬЬ) интересно, для этого нс нужсн первый элемент списка.
ПЬЫВт *ПЬВхехесь(ПЬЫВт *1Сеп» ( Подойдет любой элемент. Поскольку в списке имеется ( * 11[гьевв- Вель == гьевВ) ++гьева! ) двоиная связь, люжно псрсмсшаться от того места, кохь(11 != ВСЬЬ! ВЬ|хьгесь(ткешь)! чвхье[(нехь = ВЬСеьнехь(юехг)! != ВВЬЬ! торос указано, впсрсд и назад до тех пор, пока нс на- 11(ььеш->Ргеч )= ВСЬЬ) ПЫлеегхдгьег(гьева, 1ьева)! ( толкнемся на указатель со значением )т)(ЛА..
С помо( ++1ьева! шью Функции (у).бе(с(та[() можно было бы 11ев->Ргеч->Вехь = 11ею->Нех!М ! переместиться в начало списка, но более эффективно ! ( ) удалить сначаза часть списка, расположенную до порвав[!Сев->Вехь )= НВЬЬ) ВЬВхггась гьева ! ВЫпаегьдгьег[гьева, 11 В); гегесв 1Сева; данного нам элемента, а затем — послс него, особенно 1ьеш->Вехь->Ргеч = 11ев->Ргеч) ) ! соли псрсланный указатель находится на некотором рас! е1ае стоянии от начала списка ( Вырезание и вставка гесехя СВ = 11еюв->Ргеч; чогд ЦЬОееьсоу[ПЬЬ1ат **Ьаеь) гаева->Вахт; Возможность разбивать списки на части и затем объс- ( 12 = 1ьевв->Ргеч! динять их снова новыми и интересными способами Удаление элемента списка сз = 1сеюв->вакс! была бы очень полезной во многих видах приложсний.
ВЬВхьгась[11евд)! ЮЬЫЯР *Вехь) Делать это совсем нетрудно, соли только у вас есть ос- Лростие асгтрантние етруитури данных Оргинигоаии данина ЯП— ° 1 Часть О /* Здесь вырезана проверка амебах */ Глава 11 очень обширного маршрута, а затем будем постепенно ) Тр = [арен[недо[1), г ); > произвольно урезать список до тех пор, пока в не>! не ) с->Ьапдсепае '= Р1; десь вырезана проверка овв ох останется только одно место Для экономии месза я с->Ьопдсепде /= 180.0! сократил код (включая проверку кое-каких ошибок и е1ве эа[е = Ь1ве! большую часть файлов включения' ), но нв 5)геб-свите геепгп 1; ( издательства "ДиаСофт" можно найти полный исход- > раен( Р1еаве врес11у а с)С1ез 111е.'з! мй11е!' > 1 ех11.(ЕХ1Т РА1ЬОЕЕ); ( ( р у .'!; мйс егз 1> ныи код вместе с файлом сйу[ослелч, ко!орый содержит /* Вмчвслвть расстоянве менду двумя точкамв на Тоеа10звеапсе О, шиРотУ и лолготу тРехсот кРУпных городов.