Лекция 5_Рекурсивные алгоритмы.ppt
- Количество слайдов: 84
Рекурсивные алгоритмы.
► Рекурсивным называется способ построения объекта (понятия, системы), в котором определение объекта включает аналогичный объект в виде некоторой его части
Примеры рекурсии ►Рекурсивная структура данных ►Рекурсивная функция void F() {…. F()…. }
Особенности программирования рекурсивных функций. void main() { F(); } void F() { { {. . if()F(); } } } рекурсия не может быть безусловной, в этом случае она становится бесконечной
► Копируются - формальные, фактические параметры, локальные переменные и точка возврата ► Алгоритм (операторы, выражения) рекурсивной функции не меняется, поэтому он присутствует в памяти компьютера в единственном экземпляре
►Линейная void F() {……F()……}
Определение факториала // Циклический алгоритм n! int fact(int n) { for (int s=1; n!=0; n--) s *=n; return s; }
n=4 fact(4) // Рекурсивный алгоритм int fact(int n) { fact=4*fact(3) =4*6=24 if (n==1) return 1; fact(3) =3*2=6 fact=3*fact(2) return n * fact(n-1); } fact(2) fact=2*fact(1) =2*1=2 fact(1)=1
Вычисления квадрата натурального числа 2=n 2+2*n+1, (n+1) 2=1 1 int kv(int n) { if (n==1) return 1; else return kv(n-1)+2*(n-1)+1; }
Смешанная ► ( непрямая) рекурсия (две или более) void B() {……A()……} void A() {……B()…. . }
is. Even(4) is. Even(0) is. Odd(3) is. Even(2) is. Odd(1)
Ветвящаяся void F() {……F()…} void F() {……for(. . ; F(); . . )…}
Бинарная ► разновидность ветвящейся
Вычисление указанного числа Фибоначчи a(0)=0 a(1)=1, a(i)=a(i-1)+a(i-2), где i>1,
Вложенная ► гнездовая , nested ► особенность - не может быть выражена через обычный цикл.
Функция Акермана
void F(int a, int b) {int c, b; ……F()……} фрейм стека b c адрес a b 4 4 возврата 00400 fh 6 34
Стек вызова
некоторые аспекты рекурсии ► Математическая индукция § Правила ►разрабатывается как обобщенный шаг процесса ►обобщенные начальные условия шага - формальные параметры функции ►начальные условия следующего шага - фактические параметры рекурсивного вызова ►проверять условия завершения рекурсии ►локальными переменными функции должны быть объявлены все переменные, которые имеют отношение к протеканию текущего шага процесса
Рекурсия и поисковые задачи Результат рекурсивной функции: ►результат void ►результат логическое выражение (ture, false) ►результат значение -оценка
Варианты возврата последовательности ►РФ выводит выбранные элемент ►записать в область глобальных данных ►результат функциидинамические структуры
Поиск выхода в лабиринте int LB[10]={ {1, 1, 0, 1, 1, 1, 1}, {1, 1, 0, 0, 0, 1, 1}, {1, 1, 1, 0, 0, 0, 1, 1}, {0, 0, 1, 1, 1, 0, 0, 0, 1, 1}, {1, 0, 0, 0, 1, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 1, 1}, {1, 1, 1, 1, 1, 1}};
void step(int x, int y) { step(x+1, y); . . . step(x, y+1); . . . step(x-1, y); . . . step(x, y-1); . . . }
Результат РФ int step(int x, int y) {. . . if (step(x+1, y)) return 1; if (step(x, y+1)) return 1; if (step(x-1, y)) return 1; if (step(x, y-1)) return 1; return 0; }
Возврат найденного пути int step(int x, int y) {. . . if (step(x+1, y)) { LB[x][y]=2; return 1; } if (step(x, y+1)) { LB[x][y]=2; return 1; } if (step(x-1, y)) { LB[x][y]=2; return 1; } if (step(x, y-1)) { LB[x][y]=2; return 1; } return 0; }
Отсечение недопустимы, выход найден int step(int x, int y) { if (LB[x][y]==1) return 0; if (x==0 || x==9 || y==0 || y==9) return 1; . . .
int step(int x, int y) { if (LB[x][y]==0 ) return 0; if (x==0 || x==9 || y==0 || y==9) return 1; LB[x][y]=2; if (step(x+1, y)) return 1; if (step(x, y+1)) return 1; if (step(x-1, y)) return 1; if (step(x, y-1)) return 1; LB[x][y]=0; return 0; }
Линейный кроссворд ►Цель – присоединение слова ►Результат РФ – лог. Выражение ►Условие завершение – нет слов – успешное завершение или нельзя построить - неудача
char *w[]={"РАСИСТ", "МАТРАС", "МАСТЕР", "СИСТЕМА", "СТЕРЖЕНЬ", NULL}; int step(char *w) { int n; for (n=0; w[n]!=NULL; n++) { char *pw; if (*w[n]==0) continue; pw=w[n]; w[n]=""; if (step(pw)) {. . . return 1; } } w[n]=pw; } return 0; }
Ханойские башни. i n-1 w n-1 j 3 1 2 1
min 2^n-1 T(n, i, j, w) = T(n-1, i, w, j), T(1, i, j, w), T(n-1, w, j, i)
Обход шахматной доски
► Возврат результата
Пометка доски, условия окончания
Вызов
1. Генераторы перестановок ► Дано n-разрядное натуральное число. Определить все перестановки разрядов этого числа ► Если S={1} - то одна перестановка
a) метод вертикальной прогонки
б) Метод последовательного замещения
► в) перестановка с одной транспозицией в соседних разрядах ► г) перестановка в лексикографическом порядке ► д) перестановка в антилексикографическом порядке
2. Доказательство утверждений ►с помощью систем искусственного интеллекта; ► построением контрпримеров (опровержение утверждений); ► полным перебором и проверкой правильности всех возможных случаев, возникающих при рассмотрении утверждения; ► синтетическим методом,
3. Сортировки ► простым выбором ► обменом ► слиянием ► пирамидальная ► быстрая
4. Алгоритмы с матрицами ► нахождение обратной матрицы ► разложение матриц ( метод Гаусса) ► функции решения линейных алгебраических уравнений
Нахождение вещественного корня ► ► Пусть функция f(x) вещественной переменной x непрерывна на отрезке [a, b] и f(a)×f(b)<0. Составить рекурсивную программу нахождения на [a, b] какого-либо вещественного корня f(x). [a, b] (b-a<2×e) x 0=(b+a)/2.
Дихотомии, бисекции, деления отрезка попол
5. Другие задачи ► a) перебор с возвратом § обход конем шахматной доски § латинские квадраты § задача о назначениях § ферзи на шахматной доске § задача коммивояжера § задача о рюкзаке
► б) финансовые функции § платежи § дисконтирование § инвестиции § динамика вклада
► в) решение рекуррентных соотношений ► г) булевы функции ► д) фракталы § кривая Гилберта § кривая Серпинского § кривая Кох § функция Веерштрасса § и тд.
► е) операции над множествами § пересечение § разность § мощность § принадлежность § равенство
► ж) перевод чисел из одной с/ с в другую
Написать рекурсивную функцию, переводящую целое число из десятичной системы счисления в восьмеричную void convert (int z) { if (z>1) convert(z/8); cout<<(z % 8); }
► з) конвейер ► и)задача о Хайнонских башнях ► к) числа Фибоначчи ► л) возведение в степень ► м) биномиальные коэффициенты
Рекурсивно описать функцию C(m, n) (число размещения n неразличимых предметов по m ящикам, не более чем по одному в ящик) где 0<=m<=n , т для биноминального коэффициента Сn по следующей формуле : int C (int n, int m) { if (m==n || m==0 ) return 1; else {return (C(n-1, m)+C(n-1, m-1)); }
► н) простые числа ► о) функция Аккермана ► п) периодическое продолжение ► р) моделирование испытаний ► с) делители числа
Количество делителей ► Составить рекурсивную функцию подсчета количества всех положительных делителей натурального числа n. ► для натурального числа n количества всех его положительных делителей, меньших или равных заданному натуральному числу x.
int div(int n, int x) { if (x==1) return 1; else { if (n mod x==0) return 1+div(n, x-1) ; else div(n, x-1); } } O(n)
Количество разбиений числа ► Составить функцию подсчета количества x(m) разбиений натурального числа m (вводится с клавиатуры), то есть его представлений в виде суммы натуральных чисел.
► m=6. ► 5+1; ► 4+2, 4+1+1; ► 3+3, 3+2+1, 3+1+1+1; ► 2+2+2, 2+2+1+1, 2+1+1; ► 1+1+1+1;
► P( m , n ) разбиений натурального числа m со слагаемыми, не превосходящими n. ► x(m)=P(m, m) - дать пояснения
► свойства ► P(m, 1)=1 m=1+1+…+1 ► P(1, n)=1 ► P(m, n)=P(m, m) при n>m ► P(m, m)=P(m, m-1)+1 ► P(m, n)=P(m, n-1)+P(m-n, n) (n<m).
int deco (int m, int n) { if (m==1) return 1; if (n>m) return deco(m, m) ; else if (m==n) return 1+deco(m, m-1); else return(deco(m, n-1)+deco(m-n, n)); }
Написать рекурсивную функцию для поиска максимального элемента в одномерном массиве int max (int *a, int i) { if (i==1) return a[1]; else if a[i]>max(a, i-1) return a[i]; else return max(a, i-1); }
Эквивалентность нерекурсивных и рекурсивные функции main() /* вызывающая функция */ Пусть параметры F{. . . f(). . . } f() Р 1, Р 2, . . . , Рs, внутренние переменные /* рекурсивная функция */ V 1, V 2, . . . , Vt и в функциях main и f имеется k обращений к функции f. {. . . f(). . . }
Дополнительные объекты ► переменные AR 1, AR 2, . . . , ARs ► переменная rz ► стек ► указатель dl ► промежуточный указатель u ► k новых меток L 1, . . . , Lk ► метка jf ► промежуточная переменная l типа int
Получение нерекурсивной функции 1. Убрать объявление функции f в функцию main; 2. Добавить в функции main объявления переменных AR 1, AR 2, . . . , ARs, RZ, объявления стека ST и указателей dl и u; 3. Модифицировать тело функции f во фрагмент программы. 4. Каждый i-тый вызов функции f (как в вызывающей функции, так и в теле функции f) заменить 5. Вставить модифицированное тело функции f.
Модифицикация тела функции f ► а) удалить заголовок функции f; ► б) объявления параметров и внутренних переменных и заменить ► в) все обращения к формальным аргументам заменить обращением, к соответствующим элементам стека; ► г) вместо каждого оператора return(y) в функции f записать switch case
Пример функция Аккермана + X+1, если N=0 | X, если N=1, Y=0, | 0, если N=2, Y=0, A(N, X, Y)= | 1, если N=3, Y=0, | 2, если N=>4, Y=0, + A(N-1, A(N, X, Y-1), X), если N#0, Y#0; где N, X, Y - целые неотрицательные числа.
int smacc( int n, int x ) // вспомогательная функция { switch (n) { case 0: return(x+1); case 1: return (x); case 2: return (0); case 3: return (1); default: return (2); } }
рекурсивная функция int ackr( int n, int x, int y) { int z; int smacc( int, int); if(n==0 || y==0) z=smacc(n, x); else { z=ackr(n, x, y-1); z=ackr(n-1, z, x); } return z; }
{ typedef struct st { int i, j, k, z, lr; struct st *pst; } ST; ST *u, *dl=NULL; int l, x, y, n; int smacc(int, int); int an, ax, ay, rz, t; scanf("%i %i %i", &n, &x, &y);
an=n; ax=x; ay=y; l=1; // замена вызова t=ackr(n, x, y) goto ackr; l 1: t=rz; printf("n %d ", t); goto jackr;
// замена функции ackr: u=( ST *) malloc( sizeof (ST) ); u->i=an; u->j=ax; u->k=ay; u->lr=l; u->pst=dl; dl=u; if (an==0||ay==0) dl->z=smacc(an, ax);
// замена вызова z=ackr(n, x, y-1); else { an=dl->i; ax=dl->j; ay=dl->k-1; l=2; goto ackr; l 2: dl->z=rz;
// замена вызова z=ackr(n-1, z, x); an=dl->i-1; ax=rz; ay=dl->j; l=3; goto ackr; l 3: dl->z=rz; }
// замена оператора return z rz=dl->z; an=dl->i; ax=dl->j; ay=dl->k; l=dl->lr; u=dl; dl=u->pst; free(u); switch(l) { case 1: goto l 1; case 2: goto l 2; case 3: goto l 3; } jackr: }
int smacc( int n, int x ) { switch (n) { case 0: return(x+1); case 1: return (x); case 2: return (0); case 3: return (1); default: return (2); } }
►. Ввести I целое натуральное число (не массив составляющих знаков числа) II слово Используя стек цифры (символы) заданного натурального числа (слова) записать в обратном порядке. 1234567890 ║ 0987654321
Лекция 5_Рекурсивные алгоритмы.ppt