Искусство программирования на Си (984073), страница 29
Текст из файла (страница 29)
Почем>7 с// спириты двоичного поиска Втот алгоР/етм прн/ен 11 ак к и об азоь/ можно зап ог амхгирова так, каким образом, но не стоитбсспокоиться -- зти структуры все- Предположим, вы вызываете ПЬ(9). Первое, чзо делает мас~ сортированный массив и находит в массиве залан- с. э а айте п едположим что мы аботаем с цегда рибитиеит как стек.) функция, — вычис:щез йЬ(7), которос, в свою очередь, шю вс ~нчинт (если она там есть) Алгоритм Работает л ми числами зад ем массив целых величин азмс Рек>рспя вС использует ирены>/дествонеявиогирас- требует вычисления йЬ(б) и ВЬ(5).
Ко/да заканчивает- слсдуклпнм обРазом. ВыполннетсЯ сравнение среднего массива и искомое значение Что н жно возв ашатьэ 6 пределсния ресурсов в стеке для управления вызовами ся вычисление 6Ь(7), функция вычисляет й/Ь(8). Что значения в массиве с ключом поиска. Если это искомое п е почитаю возв ашать казательна искомый элемент предпочитаю возвращать указатель на искомый элемент вложенных функпнй. Вы не должны специально заира- знач/п вычислить 6/Ь(8)? Сначала вновь вычисляется зн/ н с пР цесс заканчиваетсн Если люч больше а с ва ибон л в й казатель е„и вел!1/инаненай шнвать память для сохранения прол/сжуточных роз>ль- Гй/(6), затем вновь вычисляется ВЬ(7), для чего, конеч- срсдпсго значсннЯ, поиск продолжаетса в части масси- дена (аким образом функция лолжна выглядеть притатов вычислений, а также называть псрсмснныс — вы но, нсобходилю вновь вычислить также ЛЬ(б) Таким ва "н,ш" срелним значением; в противном сл>час след>- ме но так как код п иведенный в листинге 16 > просто пишетс определения н пол>часто желасмын ре- образом, громадное количество лополн/польного времсз>льтат.
ни троится на вычисление рез>льтазов, которые уже Листинге 10.3. Функция поиска. Вернемся к примеру рас1опа1(п). Обршнге внпмш/ие, вычислены. Детально мы проанализируем это позднсс. Ч/О ПОЛ>Чаетея СЛИШКОМ МНО/О ВСЛИЧНН, КОтОрЫЕ Непб- НО НадО ОСОЗНаВатЬ, еПО даННЫй аЛГОритч дейезаитЕЛЬ- лолнмо где-то гохран/пь, — мнох,шслей, которые ис- но непрнелшем с точки зрения эффективности.
(Если 03 ввагеп()пс а(1, Ьпе ав(ае, хпе хеу> 1 пользуются в цепочке возвратов в конно каждон опера- все, что вы хотитс, — это описи/ль последовательность ае Ьпе пуд = авхае / 27 пнн. Каждый оператор фибоначчн, зо, конечно, этот код прекрасно подойлет 06 /* Проверяем раэумвоеть эвачвавв аргумевтов */ кеесеп п*спеепгьпз (п-1>: лля этого.) 07 ГЕ (а == ИПЬЬ ) ) авххе == 01 Вгргпчрмреачмл язык Г Пй 1 ' Часть ! й*хтргхм Я~ Глава 10 ным поиском в массиве. Втя улобства читателей, нс име- осушествляется проверка передаваемого массива, и вы- Как не следует использовать рекурсию Мне шо кажется неверным.
Почему? Потомт что юших доступа к ттеб-санту нзльпельства "ДИВСофт", полнястся сравнение )геу со средним элементом, кото- новци ю,1зов геаг) шрв(о — это нс рсшешк части проэтот массив приведен злссрк рыл! является число !О. В паннам случае кто меньше сдержанность часто яв1яется наил)чшеи стратс1неп. Озле»ы (1олее высокого уровня; это резценпс совсем г)Р]- Гпг а!]=( О, 2, а, 5, 7, 9, Зо, 12) 10, поэтому мы проходилг первук1 1р ер у Р 11 ОВ РК ' и КЧХОЛИЗ1 Сушествуют сигуапип.
в которых рекурсия, хотя и ка- О1] проблемы. точно такои л,е, как и первая Так что в в тело слслук»пего оператора К в с1рокс 14. В этом слу- жется изначально хорошим Решением. но таковым " этом случае приходится говорить об итсрапии, а нс о Заметим, что массив уэке отсортирован. Э!от метод час вылов функпии выполняется из строки !6. Мы на- действитсльности нс является Вычисление поспелова- Рекурсии, даже пример с последгнательностью Фибопоиска аеллимеаил1, если массив нс отсортирован' Он чинасм с начала лзассива и том же самом месте, но при тельности Фибоначчи является прекрасным примерок' наччи нс вы!пялит так пттанно, как это1 кол. Функпию может повести себя салзым непредсказуемым образом и новом вызове ВеагсЦ) в нем сзп!ествуют зчемснты с но этого.
хотя зта залача лсистви1ельно имеет Рек) Рсивные геа1) 1прв((), вероятно, следует написать таким образом. нс привести к успех). Про1рамма нс принесет никаких мерами тотько "!пред" ши1. черты, заключающиеся в том. что кажлын шен полуме амп только "!пред" гп особых разрушении, но алгоритм поиска может оказа1ь- Теперь т пас есть лы.сив из лног зз е! н чается в результате решения меньшего вариан!а этой жс геаб ]прас(чагд) ( СЯ не очень эффективным юзлотьдо того, что програм- ная с О Величина ав,гс,явна 1 „,, тем В,л ч , поэтому величина пив задачи, но каждая такая зр шча решается повторно нс- вкь]е (геаа ]гпе()) ма можс1 сообшить об огсУ1ствии искол1ой всличинь1 В равна О.
ото значит что осушсствтястся поиск в нзле сколько раз рпс ]гпе гп Ьпттаг(]1 массиве, лаже если он:1 в массиве есть Вом" элементе лзассива. есть только олин Гшемснт. Срав- 1 менте л1 сс1 »1, (- Рассмотрим програимт ЛЬ!.с. Фуньпия 6Ц) имссг и~вал~ в-лп1ину 1сет (по про~не»~ Ршную ц встроенный счетчик, поз1ому можно опрелслить, какое Обратите внимание, что здесь нс создастся гигантсшт хор вилик голосок "Мы не наилсм его'") Хоршлс' элс»ситом В меньше 9 поэзо»у п1рлас»ся повтсри 11с»ситом ' меньше, почто»у п1юрк»ся повторрпь количсстВО Вычислсни11 производится.
Перед лыполнскии сзск вызовов лля ллинного вхолно1о граила. Трулэто верно, мы нс наилсм ыо Полавлпс посгипр11ч нт тот же поиск но с вс иием этой программы слслайге нскоторыс оценки. Как но зочно определить, почему это имеет значение, осорис 1О ! В л.шно» с 1]чае в рслльтатс проверки ива в данно» случае в рслльтатс проверки массива вывы л) масте, сколько Вызовов ЙЦ) понадобится гшя выбенно если известно.
что входной фаил невелик По Начнем пыпошю»1ю чеагсЦ) с 1акими а»у»ен1а»п О даскя опшбка Ьолылс нет элементом лля поиска. по- числсния ВЬ(10)? морс приобре1ения собственного опыта у вас разовьст'1ас"нвс"1 '1рнвслсннь1х1 Вынзе вс:В1'нипнз ачзге Риизс»1 этогзх возвр,1шается нхчсвои уклзатс,п, Как вилнтс (сели вы зап)стили тестовую програм ся определенное чутьс на это. Просто будьте вниматсль- //г/мгнонееннлн/ н ~нл Г Щ$ !!— Часть ! l'гл//кил — — — Е)п Глава 10 Еще один пример: Евклидов алгоритм рекураш при выювс есдо.
Это поможет вам увидеть, ременные, возврашастся к началу Неясно? Тогда давай- лиг»множснис х на факториал (х-1). Однако в этом квк в деис~вительности работает рек) рсивныи ал/оритм тс рассмотрим нсрекурсивнос вычисление факториала. случае»множснис происходиг тут жс, без погр»жсния Дстбавим ешс пару примеров к нашей коллекции и проПример вывола представлен в листинге !ОУЕ Эта функция похожа на прслылушую, только она в попочку гпожснных вызовов Гасеопа1().
а/затиззср)т»/ их. Сначала рассмотрим Гвклилов алгоритм никогда нс вызывает сача себя. она пере»од!п в свое Мно/ие компиляторы создают лля этих двух варилля поиска наибольшего обшсто делителя лву» шссл. Листинг 10.5. Глубина рекурсии. начжзо. 51 испольювал ео(о вместо явного цикла. чтобы антов програмл1ы практически одинаковыи кол, котоМалснькая математическая подробность: наиболынин Ево впвьегвт 25 15 привлечь внимание к тому факт», что компилятор не рый выполняет олни и тс жс функции общин делизаель двух чисел — эзо наибольшее целое чисвссгла воспринимает такой цикл так жс, лак он восприло, на которос делятся оба эти числа без остатка При- гева[пйег 10, сп11(пд дсе(15, 10) Е)це раа о последовательности Фибоначчи нимает операторы (ог и ий!)е.
Определенно булуший мер реализации предстагшен в листинге !04 гепа)пеег 5, св11зпд дев(10, 5) читатель вашегокодабулетрассмагрнватьэтоотличным Теперь уберем рекурсию из примера с послсдоватсльЛистинг 10.4. Евклидов алгоритм. геепгпзпд 5 образом. (В действительности обычно ис/зользеется ностыо с)зибзоначч/ь Наша первая версия немного неук— — — гесшп1пд 5 шзкл, но ссичас рассматривается пример, а нс экспл»а- люжа, но в нси нсз рекурсии. Не стеснянтесь попроболпс дсе(1пс х, спс у) ( тируюшийся кол.) Вать сс сами и оцснить сс' эффсктиВность Всрсия, зу (х < у) [ Можстс опрслелить, насколько зтог вывод соотвст- Можно замет/пь. что неожиданно исчезает рсальныи представленная в листинге П).7, начсюго быстрее рскургеспгп дса(у, х); с/в)с! вашим ожиданиям.
Попробуйте выполнить эт» вопрос о гл»бине рекурсии мы накапчивасм величины с испо(„ ) е1ве ТЕ ((х Ъ у) 1= О) ( программу для нескольких комбинации исхолных чи- пока не произойдет некос собьпие Конечно, можно геешв се(, х $ д (у у)г сел; вы залштитс, что глубина рек»рсии редко бывает определить итерацию, но, !зоскольк) при каждой пте- Листинг 10.7. Первое исправление программы для е1пе [ геспгп у: очень большой. рации нс вылеляется новая область памяти, /л»бина ее вычисления последовательности Фибоначчи.
ви и н нс настолько важна 01 1пе ) Хвостовая рекурсия То жс самое можно сделать и в других функциях. 02 ель[сне х) [ Пиесам ям ниии я гик С ~Щ ! Часть 1 Регчгия аая(а$ая — — Щд Глава 10 память(строка 19]. н ютем вотврашасм Значение, кото- Таблица 10.1. Трассировка функции для вычис- Непрямая рекурсия тать в сючстанин с рекурсцси. Например, рассмогрим станрое было в массиве. пения последовательности фибоначчи.
партн>ю бпбтиотс шею функцию э1г(ой() Эга фтнкция Это пригодная к рсальночу использованию версия, Пес«олькт в С ~егко вытывать одп> ф>нюгцю нт лйе- ичсст част, статпческцх )шины„ и[()/ а/// и/2/ / Где.чы нигидимгя но не очень приятно выполнять закат всей этой пачя- ГОИ, ВОЗМОжНа НСПРЯМаа РСК>РСИЯ. Ф>НКЦИЯ МОжет НС строк>, когорая б>дст продолжать поиск.
если вы исти, когда каждое число реально испольлустся нс более 1 1 м/д 2 исходные установки прямо вызывать себя, она может вгазвать лр>пк7 ф>нк редалитс нулевой укататель. рассмотрим прслставлснлв>л раз Поэтому принимаем окончательную версию 1 1 2 2 вычисление а[21 цию, та, в свою очерель, след>юшую и тш — так меж ную в листинге )09 функцию, которая вьплялит вполвчесго того иобы вылсля7ь начать лля всех чисел, ПРЦйтн К ВЫЗОВУ ПСХОЛНОй фУНКПИЦ ° нс ц аш)ополобно ц кото ~я 1 атбцпаст вхш)ш ~с строкц 1 2 2 2 перемещение величин в выдслим сс только ш1я трсх чиссл — лля тсх ла>х чи- массиве, "вращение" Это нс РаспРостРаненный полхол, но вполне вогмож- на л .. сел, которые ск1алываекь и для результата сложения.
1 2 2 3 '-ч ный Вообще, это люжст проитойги только в более 1(овая версия приведена в листинге 10.8 сложцык сит>алиях. Например, реализация сннгакси- Листинг 10.9. Простая программа для разбиения 1 2 вычисление а[21 чсскспо анщтнтатора чох ст привести к некоторой нс- на лексемы Листинг 10.8. Окончательная версия функции для 2 3 3 3 перемещение величин в прячои рекурсии. вычисления последовательности Фибоначчи. Обы цю непрямая рекурсия ш7епцслыю нс рассгшт 1 К( Ь г, Ь *4 1гв 01 гвг ривастся Однако н>жно помнить, что непрямая рскур- сьаг *сер; 02 11Ь(гпе х) ( 2 3 5 4 вычисление а[21 сия вес равно остается релурсиси, потому что в рскур- 03 гвс г, а(31; 3 5 5 4 перемещение величин в снвных колах могут с>ц)се~певать ловушки, прис>шис 1в = яггеех(я, ее11а); Р 04 ч811е (твр) 05 гг (х < 3) массиве только рекурсивным кодам, и в них можно угодить, да кс рггв11("говел тя>л" Гвр) 06 гегягп 1; 3 5 5 5 если рек>'ра~я в кодс нспосрсдсг асино нс очсвцлнп твр = ягггох(яШ,Ь, де)гв1; 07 3 5 8 5 вычисление а[21 (Обрагцте внимание на пример э(г(ойи в слсл> юшсч ) ре Зре Перееяяеяреяяналзеея Г' ! Глава 10 Часть ! ши очная попытка до авпения дополнительной возпгожности.
ности которого подобны возможностям функции рованы все имсна, начинающиеся св(г и спослсдуюши- эсг(о(еО, но всгверО не использ>ст статичсский буфер. к ми прописными буквами, для использования в рсщш- 01 чп)б сожалению, эта функция нс входит в стандарт С, но она зациял, и действительно многис снстсмы прслоставля- 02 Сох(сваг *н, сьаг "бн11в) ( 03 сваг 'сн ; с аг 'снр! вхощп в библиозски с для различных бссплатных ют функцию в(гаер(). (известно, что она включена в 04 С[ч!Х-подобных систем, поэтолеу вы вссгда можстс по- нскоторыс дистрибутивы [лпцх и во всс снстсмы на 05 Свр = аггхпх(н, бн1св); лУчн~в копию либо использовать РаботающУю подоб- платфоРмс 44ВВР, такие как ВВРееОВ илп )ес(ВВР.) 06 нк)1е (Свр) ( ным образом функцию, прсдставлсннукз на Учсб-санто Вообщс, это показывает способ созлания функции, 07 /* Длина нсхпдаой подстрока, содеркадей тпявко сннвппн вз второго аргунента */ издательства "ДиаСофт".