Лекция · 3.4

Рекурсия

Екі айна бір-біріне қарама-қарсы қойылғанда не болатынын көрдің бе? Айнада — тағы да айна, ішінде — тағы да айна, шексіздікке дейін. Немесе орыс матрёшкасын ойлап көр — әр қуыршақтың ішінде тағы кішірек, дәл сол секілді, тағы бір қуыршақ бар. Дәл осындай «өзін-өзі қайталау» идеясы программалауда да бар — оны рекурсия деп атайды.

Рекурсия деген не

Рекурсия — тек программалауда ғана емес, өнерде де кездеседі: гүлді қырыққабаттың фракталды құрылымында, архитектурадағы қайталанатын бағандарда, тіпті қазақ поэзиясындағы қайырмаларда. Информатикада бұл идея нақты, пайдалы механизмге айналады.

Анықтама
Рекурсия — процедура немесе функцияның ӨЗІН-ӨЗІ шақыруы арқылы есептеу процесін ұйымдастыру тәсілі.
⚠️
Маңызды ереже: рекурсивті функция ЕШҚАШАН тоқтамай өзін-өзі шақыра берсе, программа «ілінеді» немесе құлайды. Сол себепті әр рекурсияда МІНДЕТТІ ТҮРДЕ рекурсияны ТОҚТАТАТЫН шарт (базалық жағдай) болуы керек.
Факториал есебі — классикалық мысал

Рекурсияны түсінудің ЕҢ ЖАҚСЫ жолы — факториал есебі. Санның факториалы (n!) дегеніміз — 1-ден n-ге дейінгі барлық санның көбейтіндісі. Бірақ мұнда қызық байқау бар: n! = n × (n−1)! — яғни, n-нің факториалын есептеу үшін (n−1)-дің факториалын білу жеткілікті!

Есеп (орта): n! есептейтін рекурсивті функция

Берілді: n натурал саны (n! = 1×2×...×n, 0!=1).

Неге рекурсия қолданамыз? n! = n·(n−1)! қатынасы функцияны ӨЗІ АРҚЫЛЫ анықтауға мүмкіндік береді — базалық жағдай ретінде n=0 кезінде 1 қайтарамыз.

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

Қалай орындалады? factorial(2) шақырылса:

factorial(2) → 2 * factorial(1)
             → 2 * (1 * factorial(0))
             → 2 * (1 * 1) = 2

Жауабы: факториал n! = 1, егер n=0; n! = n·(n−1)!, егер n>0.

Стек және рекурсия тереңдігі

Функция өзін-өзі шақырғанда, компьютер «мен қайда тоқтадым, қайда ораламын» дегенді есте сақтауы керек. Мұны компьютер арнайы жад аймағында сақтайды.

Анықтама
Стек (ағылшынша *stack* — байлам) — уақытша деректерді немесе қайтарылатын адрестерді сақтауға арналған арнайы жад аумағы.
🍽️
Аналогия: стек — асхана табақтарын үстіне-үстіне қоятын үйіндіге ұқсас. Соңғы қойылған табақ БІРІНШІ алынады (last in, first out). Рекурсивті шақырулар да дәл осылай — соңғы шақырылған функция БІРІНШІ аяқталады.

Кіріктірілген шақырулардың жалпы саны — рекурсия тереңдігі деп аталады (мыс. factorial(n) үшін дәл n+1 шақыру болады). Егер рекурсия шексіз болса, стек тез толып, программа құлайды.

АртықшылығыКемшілігі
Код қарапайым, анық, ықшам боладыЖедел жады үнемді пайдаланылмайды
Күрделі есепті «табиғи» түрде сипаттайдыПрограмманы айтарлықтай баяулатуы мүмкін
Басқа рекурсивті есептер
Есеп (қиын): Фибоначчи тізбегі

Берілді: Фибоначчи тізбегі — әр келесі мүше алдыңғы екеуінің қосындысына тең: 1, 1, 2, 3, 5, 8, 13, ...

Табу керек: тізбекті N мүшеге дейін рекурсия арқылы шығару.

def Fib(p, q):
    global i, n
    t = p + q
    i += 1
    print(t, end=' ')
    if i < n:
        Fib(q, t)

n = int(input('N='))
x = 1
y = 1
i = 0
print(1, 1, end=' ')
Fib(x, y)

Жауабы: N=8 үшін — 1 1 2 3 5 8 13 21 34

Есеп (орта): цифрлар қосындысын рекурсиямен есептеу

Берілді: k саны.

Неге бұл рекурсия? Санның соңғы цифры (n % 10) мен қалған цифрлар (n // 10) арасында қатынас бар — функция «қалған бөлігін» өзі арқылы шешеді.

def sumDig(n):
    sum = n % 10
    if n >= 10:
        sum += sumDig(n // 10)
    return sum

k = int(input('k='))
print(sumDig(k))

Базалық жағдай: n < 10 болғанда — тек соңғы цифр қайтарылады, рекурсия тоқтайды.

Жауабы: k=56255252125533 үшін — 51.

🎯 ҰБТ байланысы
Рекурсивті функцияның қалай «ашылатынын» қадам-қадаммен қадағалау — ЕНТ-те жиі кездесетін код-талдау түрі.
1
Базалық жағдайсыз рекурсия ШЕКСІЗ болады — программа құлайды.
2
Рекурсия тереңдігі — толық шақырулар саны, оны стек арқылы бақылау керек.
3
Рекурсивті шақыруларды «ашу» кезінде ЕҢ ІШКІ шақырудан бастап артқа қарай есептеу.
Сабақ қорытындысы
  • Рекурсия — функцияның өзін-өзі шақыруы арқылы есептеу; міндетті түрде тоқтату шарты (базалық жағдай) болуы керек.
  • Факториал (n! = n·(n−1)!) — рекурсияның классикалық мысалы.
  • Стек — рекурсивті шақырулардың қайтарылатын адрестерін сақтайтын жад; рекурсия тереңдігі — толық шақырулар саны.
  • Рекурсия код жазуды ықшамдайды, бірақ жады мен жылдамдық жағынан циклге қарағанда «қымбатырақ».