100 likes | 325 Views
Рекурсия. Recur (от латински re = обратно + currere = изпълнява се ; Т.е. Да се случи отново, на повтарящи се интервали Техника за дефиниция на математически функции и на структури данни.
E N D
Рекурсия Recur (от латински re = обратно + currere = изпълнява се ; Т.е. Да се случи отново, на повтарящи се интервали • Техника за дефиниция на математически функции и на структури данни. • Математически функции, които могат да се дефинират рекурсивно: факториел, ред на Фибоначи, най-голям общ делител, трансформация на Фурие. • Рекурсивни решения са удобни в игрите (шах и др.) – решавайки проблема със серия рекурсивни извиквания, се намира решение.
Рекурсия Простата дефиниция е: • Програма, която вика себе си. • Условие за край, когато престава извикването. Рекурсивен алгоритъм – решава проблем чрез решаване на по-малки екземпляри на същия проблем. • Най- известната рекурсивна функция е факториел. N! = N(N-1)! за N >= 1 с 0!=1. int factoriel(int n) { if(n==0) return 1; return n*factoriel(n-1); }
Функцията връща коректна стойност, когато се извиква с неотрицателна стойност на n, която е достатъчно малка. • Програмата е еквивалентна на цикъла: for(i=1,t=1;i<=n;i++) t*=i; • Защо се използва рекурсията? • За изразяване на сложни алгоритми в компактна форма без да се намалява ефикасността. • Отпада необходимостта от локални променливи. • Разходи на рекурсивната реализация. • Обръщенията към функции, ползващи стека. • Рекурсивните функции трябва да удовлетворяват две свойства: • Те трябва да решават основния случай. • Всяко рекурсивно извикване трябва да включва по-малка стойност на аргументите.
Съмнителна рекурсивна програма int puzzle(int n) { if(n==1) return 1; if(n%2==0) return puzzle(n/2); else return puzzle(3*n+1); } • Не всяко рекурсивно извикване използва аргумент по-малък от дадения (не може да се докаже, че програмата завършва). • Не се знае дали изчислението завършва за всяко n. • За n=3, стойностите за извикване на puzzle са:10, 5,16, 8, 4,2,1. • За големи стойности на n има вероятност цикълът да бъде безкраен.
Всеки цикъл for може да се замени с еквивалентна рекурсивна програма. • При рекурсивната програма се влагат викания на функция до достигане на точка, където не се прави извикване, а се осъществява т.нар. връщане назад. • Вложени обръщения към функции – реализират се чрез стек. • Дълбочината на рекурсия е степента на влагане на извикванията по време на изпълнение. • Средата за програмиране трябва да подържа стек с размер, пропорционален на дълбочината на рекурсия. • Големите задачи водят до отказ от рекурсия.
Рекурсивна програма за реализация на алгоритъма на Евклид за намиране на най-голям общ делител на две цели числа. int gcd(int m, int n) { if(n==0) return m; return gcd (n , m%n); } • Базирана е на факта, че НГД на 2 цели числа (m>n) е същият като НГД на n и остатъка при деление на m с n. • Число tдели mи n тогава когато дели и nи m mod n, защото m е равно на m mod n плюс кратно на n. • Дълбочината на рекурсията зависи от аритметичните свойства на аргументите (известно е, че тя е логаритмична)
Пример за запис на екрана на едно цяло число във вид на последователност от символи • Функцията без използване на рекурсия • В масив се поставят цифрите на числото (като символи) в посока от младши към старши разреди. • На екрана се извеждат елементите на масива в обратен ред. void printd(int n) { char s[10]; int i; if(n<0) { putchar(‘-’); n=-n; } i=0; do { s[i++]=n%10 + ‘0’; }while(n/=10); while(--i >= 0) putchar(s[i]); }
Функцията с използване на рекурсия • При движението напред, изпълнението се отлага, като в стека се записват стойностите на n и i, докато i е отлично от нула. • При връщането назад се завършват отложените изпълнения. n i n i n i void printd(int n) { char s[10]; int i; if(n<0) { putchar(‘-’); n=-n; } //движение напред if( (i=n/10)!= 0 )printd(i); //връщане назад putchar(n%10 + ‘0’); } 123 12 12 1 1 0