21
2013 Copyright © 2013 DAVID Holding Company Курс по програмиране на C# Занятие №5 Рекурсия

Училищен курс по програмиране на C# (2013/2014), занятие №5

Embed Size (px)

DESCRIPTION

Училищен курс по програмиране на C# (2013/2014) Занятие №5: Рекурсия

Citation preview

Page 1: Училищен курс по програмиране на C# (2013/2014), занятие №5

2013Copyright © 2013 DAVID Holding Company

Курс по програмиране на C#

Занятие №5Рекурсия

Page 2: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Съдържание 1/2

• Рекурсия– Какво е рекурсия?– Как работи рекурсията?

• Видове рекурсия– Единична и множествена рекурсия– Пряка и косвена рекурсия– Опашна рекурсия

• Използване на рекурсия– Приложение– Основни принципи– Предимства и недостатъци– Оптимизация

Page 3: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Съдържание 2/2

• Примери за рекурсия– Факториел– Числа на Фибоначи– Обръщане на масив– Двоично търсене в сортиран масив– Търсене на път в лабиринт

Page 4: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Рекурсия

• Какво е „рекурсия“?– За определение на „рекурсия“ вж. „Какво е рекурсия“?– Рекурсия в най-общ смисъл е представяне на един обект или

процес чрез самия него– Рекурсия в математиката е изразяване на една функция чрез

самата нея– Рекурсия в компютърното програмиране е решение, при което

едно функция използва сама себе си

Page 5: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Рекурсия

• Как работи извикването на функция?– При извикване на функция, в стека се запазва информация за

локалните променливи и мястото на извикването и параметрите– При връщане от извикване на функция, изпълнението

продължава от мястото на извикването, като локалните променливи и параметрите се възстановяват

• Как работи рекурсията?– Описаната схема на извикване на функции работи при

произволен брой вложени извиквания на различни функции– В частност тези извиквания могат да бъдат рекурсивни– Внимание: При прекалено много вложени извиквания, стекът

може да се препълни това да доведе до грешка и прекратяване изпълнението на програмата

Page 6: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Рекурсия

1. Директор към секретарката:– „Заминаваме на командировка в чужбина за седмица.“

2. Секретарката към мъжа си:– „Заминавам с шефа на командировка в чужбина за седмица.“

3. Мъжът към любовницата си:– „Жена ми заминава в командировка. Тази седмица сме заедно.“

4. Любовницата (учителка) към ученика си:– „Болна съм, тази седмица. Няма да имаме уроци.“

5. Ученикът към дядо си:– „Дядо, тази седмица идвам нагости, няма да имам уроци.“

6. Дядото (директорът) към секретарката си:– „Внукът идва нагости тази седмица. Командировката се отлага.“

7. Go to 1.

Page 7: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Видове рекурсия

• Единична и множествена рекурсия– Единична рекурсия е тази, при която има само едно

рекурсивно извикване– Множествената рекурсия е тази, при която има повече от

едно рекурсивно извикване

• Пряка и косвена рекурсия– Пряка рекурсия е тази, при която функцията извиква себе си

директно– Косвена (непряка) рекурсия е тази, при която функцията

извиква себе си чрез извикване на друга функция– Косвената рекурсия се нарича още споделена рекурсия, тъй

като всички функции участващи в нея се извикват рекурсивно, макар и косвено

Page 8: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Видове рекурсия

• Опашна рекурсия– Опашно извикване е извикване на функция като последно

действие в друга функция– Извикваната функция може да връща резултат, който да се

върне на извикващата функция– Ако в резултат на опашното извикване в дадена функция

същата функция бъде извикана отново, то говорим за опашна рекурсия

– С други думи, опашна рекурсия е тази, при която рекурсивното извикване се осъществява в „опашката“ на функцията

– Опашната рекурсия винаги може да бъде сведена до итерация (оптимизация на опашна рекурсия)

Page 9: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Използване на рекурсия

• Приложение– Решаване на математически задачи, решенията на които са

зададени с рекурсивна връзка– Разбиване на решението на по-малки сходни решения и

обединяване на техните резултати („разделяй и владей“) – динамично програмиране/оптимиране.

– Рекурсия + таблици за търсене = мемоизация

• Основни принципи– Всяко рекурсивно извикване трябва да опростява решението– Рекурсията трябва да съдържа условие за край (т.нар. дъно на

рекурсията)

Page 10: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Използване на рекурсия

• Предимства– Опростява решението на множество задачите чрез разбиването

им на малки прости подзадачи

• Недостатъци– Значително по-бавна работа, поради засилено използване на

стека– Прекомерно използване на стек

• Оптимизация– Свеждане на рекурсията до итерация, когато това е възможно

• Използване на собствени стекови структури за симулиране на рекурсия

– Използване на мемоизация, когато рекурсивните извиквания дават еднозначен резултат при едни и същи аргументи

Page 11: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – факториел

• Какво е факториел?– Класическа дефиниция

n! = 1. 2 . 3 . … . (n-1) . n , n ∈ ℕ0! = 1 (граничен случай)

– Рекурсивна дефиницияn! = n . (n-1)! , n ∈ ℕ0! = 1 (дъно на рекурсията)

• Факториелът е бързо растяща функция• За големи стойности, използвайте

BigInteger вместо int

Page 12: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – факториел

// факториел - итеративноint GetFactorialIter(int n){ int result = 1; // n! = 1.2.3. … .n for (int i = 1; i <= n; i++) result *= i; return result;}

• Итеративно намиране на факториел– Итеративна дефиниция:

n! = 1. 2 . 3 . … . (n-1) . n , n ∈ ℕ0! = 1 (граничен случай)

Page 13: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – факториел

// факториел – рекурсивноint GetFactorialRec(int n){ // 0! = 1 if (n <= 0) return 1; // n! = n . (n-1)! return n * GetFactorialRec(n-1);}

• Рекурсивно намиране на факториел– Рекурсивна дефиниция:

n! = n . (n-1)! , n ∈ ℕ0! = 1 (дъно на рекурсията)

Page 14: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – числа на Фибоначи

// числа на Фибоначи – рекурсивноint GetFibonacciNumbersRec(int n){ // F0 = 1, F1 = 1 if (n <= 1) return 1; // Fn = Fn-1 + Fn-2

return GetFibonacciNumbersRec(n - 1) + GetFibonacciNumbersRec(n - 2);}

• Кои са числата на Фибоначи?– Рекурсивна дефиниция:

Fn = Fn-1 + Fn-2

F0 = 1, F1 = 1

Page 15: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – обръщане на масив

// обръщане на масив – рекурсивноvoid ReverseArrayRec(int[] a, int start, int end){ // краищата на масива са се разминали if (end <= start) return; // разменяме крайните елементи int t = a[end]; a[end] = a[start]; a[start] = t; // обръщаме подмасива ReverseArrayRec(a, start + 1, end – 1);}

• Рекурсивно обръщане на масив– Ако краищата на масива са се

разминали, се връщаме обратно

– Разменяме крайните елементи на масива

– Обръщаме подмасива от елемент 1 до елемент n-2

Page 16: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – дв. търсене в сорт. масив

• Двоично търсене в сортиран масив– Ако краищата на масива са се

разминали, се връщаме неуспешно– Взимаме средния елемент и

стойността му наричаме „ключ“– Ако ключът:

• е по-малък от елемента, който търсим,търсим в дясно стоящия подмасив

• е по-голям от елемента, който търсим,търсим в ляво стоящия подмасив

• съвпада с елемента, който търсим,връщаме индекса му

Page 17: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Примери за рекурсия – търсене на път в лабиринт

• Търсене на път в лабиринт– Рекурсивното търсене на път в лабиринт се основава на

принципа „проба-грешка“– На всяка стъпка:

1. Проверяваме дали сме стигнали. Ако да, се връщаме успешно.2. Маркираме настоящата позиция като настъпана3. Стъпваме във всяка една посока, докато не се

изчерпат и/или не сме намерили пътя

Page 18: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Задачи за упражнение

• Създайте програма със следните функции:– CreateMatrix, която създава масив от елементи от

тип ConsoleColor попълнен произволно с бяло(White) и черно (Black).

– ShowMatrix, която визуализира създадения масив поподходящ начин

– FillMatrix, която започва да запълва бял регион с червено използвайки рекурсивния flood fill алгоритъм, започвайки от произволна бяла позиция.

– Нека във всяко рекурсивно извикване на FillMatrix се извиква и ShowMatrix, така че визуализираният масив да се опреснява.

Page 19: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Задачи за упражнение

• Направете рекурсивна функция, която да намира и изпечатва наименованията на всички файлове и техните големини намиращи се в папка с подадено име и на подадена дълбочина в нейните подпапки.– За да вземете списък с наименованията на папките в дадена

папка, използвайтеstring[] folderNames = Directory.GetDirectories(path);

– За да вземете списък с наименованията на файловете в дадена папка, използвайте:string[] fileNames = Directory.GetFiles(path);

– За да вземете големината на файл, използвайте код като следния:long length = new FileInfo(fileName).Length;

Page 20: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Въпроси?

Page 21: Училищен курс по програмиране на C# (2013/2014), занятие №5

Copyright © 2013 DAVID Holding Company

Благодаря!

• Валери Дачев– [email protected]– @vdachev– https://facebook.com/vdachev

• ДАВИД академия– [email protected]– http://acad.david.bg/– @david_academy– https://facebook.com/DavidAcademy