Тақырып 7

Алгоритмдер және программалау (функция, рекурсия, жолдармен жұмыс, файлдармен жұмыс, сұрыптау, граф)

Спецификация бойынша не тексеріледі:

Функциялар: def, параметрлер, returnКөріну аймағы: жергілікті және глобалды айнымалыларРекурсия: базалық жағдай және шақырулар стегіЖолдар: индекстер, кесінділер, аралауЖол әдістері, палиндромдар, символдарды санау, сөздіктер мен жиындарФайлдармен жұмысСұрыптау және іздеуГрафтар: берілуі, аралау, ең қысқа жол, ағаштар

Бір минутта мәні

Бұл тақырып — Python тілінде «тереңдетілген» программалау: программаны функцияларға қалай бөлу, функцияның өзін-өзі қалай шақыратыны (рекурсия), жолдар мен файлдарды қалай өңдеу, деректерді қалай сұрыптау және тез іздеу, объектілер арасындағы байланысты граф арқылы қалай сипаттау. ҰБТ-да мұндағы тапсырмалардың басым бөлігі: «программа не шығарады», «функция неше рет шақырылады», «сұрыптау неше салыстыру/алмастыру жасайды», «екілік іздеу неше қадам жасайды» және «салмақтар кестесі бойынша ең қысқа жолды табыңыз». Басты дағды — кодты қолмен мұқият трассалау: айнымалылардың мәндерін қадам сайын жазып отыру және индекстерді шатастырмау. Бірнеше негізгі санды есте сақтаңыз: nn элементке көпіршікті сұрыптау n(n−1)2\frac{n(n-1)}{2} салыстыру жасайды, екілік іздеу ⌈log⁡2(n+1)⌉\lceil\log_2(n+1)\rceil қадамнан аспайды, граф төбелерінің дәрежелерінің қосындысы қабырғалар санының екі еселенгеніне тең. Қалғаны — зейін мен қадамдап трассалау.

Қарапайым тілмен

Программа — ас үй сияқты: функциялар — дайын рецепттер, рекурсия — матрешка, жол — әріптерден тізілген моншақ, файл — дәптер, сұрыптау — кітаптарды биіктігі бойынша қою, ал граф — қалалар арасындағы жолдар картасы.

Функция = рецепт

Рецептті бір рет сипаттаймыз (def), кейін оны әртүрлі өнімдерді — параметрлерді — қойып, қанша рет болса да қолданамыз. return — функция кері қайтаратын дайын тағам.

Рекурсия = матрешка

Үлкен матрешканы ашсаң, ішінен дәл сондай, бірақ кішірек матрешка шығады. Ең кішісі ашылмайды — бұл базалық жағдай. Онсыз рекурсия ешқашан аяқталмайды.

Жол = моншақ

Әр моншақ — өз нөмірі бар символ, нөмірлеу 0-ден басталады. s[2:5] кесіндісі — 2, 3, 4 нөмірлі моншақтарды алу (бесінші кірмейді!).

Граф = жолдар картасы

Қалалар — төбелер, жолдар — қабырғалар, жолдың ұзындығы — салмақ. «Қалай ең тез жетуге болады» деген есеп — ең қысқа жолды іздеу, және тура жол әрқашан ең қысқасы бола бермейді.

Басты формулалар

Cкөпіршік=n(n−1)2C_{\text{көпіршік}} = \dfrac{n(n-1)}{2}
nn элементке арналған классикалық көпіршікті сұрыптаудағы (және таңдау арқылы сұрыптаудағы) салыстырулар саны; n=5n=5 үшін 1010.
kmax⁡=⌈log⁡2(n+1)⌉k_{\max} = \lceil \log_2(n+1) \rceil
nn элементтен тұратын сұрыпталған массивте екілік іздеудің ең көп қадам саны (ортаңғымен салыстыру); n=1000n=1000 үшін 1010, n=15n=15 үшін 44.
∑deg⁡(v)=2∣E∣\sum \deg(v) = 2|E|
бағытталмаған графта барлық төбелер дәрежелерінің қосындысы қабырғалар санының екі еселенгеніне тең (әр қабырға екі ұшында да «саналады»).
∣E∣толық=n(n−1)2|E|_{\text{толық}} = \dfrac{n(n-1)}{2}
nn төбелі толық бағытталмаған графтағы қабырғалар саны (әр төбе әр төбемен қосылған).
∣E∣ағаш=n−1|E|_{\text{ағаш}} = n - 1
nn төбелі ағашта (циклсіз байланысқан граф) дәл n−1n-1 қабырға бар.
шақырулар(fib(n))=2⋅Fn−1\text{шақырулар}(fib(n)) = 2\cdot F_n - 1
базасы n <= 2 болатын «қарапайым» рекурсивті fib(n) неше рет шақырылатыны; мысалы, n=6n=6 үшін: 2⋅8−1=152\cdot8-1=15.

Ұғымдар мен терминдер

Функция
бағдарламаның керек орындарында аты бойынша шақырылатын кодтың атаулы блогы; Python-да def сөзімен жарияланады және return арқылы мән қайтара алады.
Параметр (аргумент)
шақыру кезінде негізгі программадан ішкі программаға берілетін мән; def f(a, b=2) тақырыбында — формальды параметрлер, f(5) шақыруында — нақты параметрлер.
Процедура
бірнеше іс-әрекетті орындайтын көмекші алгоритм; Python-да бұл return жоқ функция (ол None қайтарады).
Жергілікті және глобалды айнымалы
жергілікті (локальді) айнымалы функция ішінде жасалады және тек сонда көрінеді; глобалды айнымалы — негізгі программада. Глобалды айнымалыны функция ішінде өзгерту үшін global операторы қажет.
Рекурсия
функцияның дәл сондай, бірақ кішірек есепті шешу үшін өзін-өзі (тікелей немесе басқа функция арқылы) шақыру тәсілі.
Базалық жағдай
рекурсиядан шығу шарты, бұл кезде функция өзін қайта шақырмай-ақ жауап қайтарады (мысалы, факториал үшін n <= 1).
Жол (str)
символдардың реттелген өзгермейтін тізбегі; символдар 0-ден бастап нөмірленеді, индекс және кесінді арқылы алынады.
Файл
нақты атаумен компьютердің сыртқы жадында сақталған ақпараттар жиынтығы; Python-да open(аты, режим) функциясымен ашылады.
Сұрыптау
деректер жиынының элементтерін қандай да бір белгі (кілт) бойынша өсу немесе кему ретімен орналастыру.
Граф
төбелер (түйіндер) мен олардың арасындағы қабырғалар (байланыстар) жиынтығы; бағытталған және бағытталмаған, салмақты және салмақсыз болады. Ағаш — циклсіз байланысқан граф.

Тақырыпты талдау

Функциялар: def, параметрлер, return 10 сынып

Функция — атау берілген программа бөлігі. Бір рет жариялаймыз, қанша рет болса да шақырамыз. Үлгі: def аты(параметрлер):, одан кейін 4 бос орын шегініспен денесі жазылады. return сөзі функцияны аяқтап, нәтижені функция шақырылған жерге қайтарады.

def area(a, b=2):
    return a * b

print(area(3))        # b әдепкі мәннен алынады: 6
print(area(3, 5))     # 15
print(area(b=4, a=10))  # атаулы аргументтер: 40

Әдепкі мәні бар параметрді (b=2) бермеуге болады. Әдепкі мәнді параметрлер қарапайым параметрлерден кейін жазылады: def f(a, b=2) — дұрыс, def f(a=1, b) — қате. Шақыру кезінде аргументтерді атымен көрсетуге болады, сонда реті маңызды емес.

Функция бірден бірнеше мән қайтара алады: return a + b, a * b — кортеж шығады, оны «ашып» алу ыңғайлы: s, p = f(2, 3). return-нен кейінгі функция коды орындалмайды.

Егер return жоқ болса (немесе бос болса), функция None қайтарады. Бұл — процедура: ол бір әрекет жасайды (мысалы, басып шығарады), бірақ мән қайтармайды. ҰБТ-ның классикалық тұзағы: r = show(7) 14 шығарады, ал print(r) None шығарады.

Білу пайдалы кірістірілген функциялар: len, abs, max, min, sum, sorted, int, str, round, ord (символ коды), chr (код бойынша символ), range.

Көріну аймағы: жергілікті және глобалды айнымалылар 10 сынып

Функция ішінде жасалған айнымалы — жергілікті: ол тек шақыру кезінде өмір сүреді және сырттан көрінбейді. Негізгі программаның айнымалысы — глобалды: функция оны оқи алады, бірақ функция ішіндегі меншіктеу сол аттас жаңа жергілікті айнымалы жасайды.

x = 10

def f():
    x = 5          # жергілікті x, глобалдысына тимейді
    print(x)

def g():
    global x       # енді глобалды x-пен жұмыс істейміз
    x = x + 1

f()        # 5
print(x)   # 10
g()
print(x)   # 11

Есептерге арналған ереже: функцияда global x-сіз x = ... меншіктеуі болса — бұл басқа, жергілікті x. Егер global x болса — функция «ортақ» айнымалыны өзгертеді.

Функция параметрлері де — жергілікті айнымалылар. Сандар мен жолдарды параметр арқылы сырттан өзгерту мүмкін емес. Ал функцияға берілген тізімді әдістермен (a.append(...), a[0] = ...) өзгертуге болады — өзгерістер сыртта да көрінеді, сондықтан сұрыптауларда жиі a = a[:] көшірмесі жасалады.

Рекурсия: базалық жағдай және шақырулар стегі 10–11 сынып

Рекурсивті функция кішірек есеп үшін өзін-өзі шақырады. Міндетті екі элемент бар: базалық жағдай (бірден жауап береміз) және рекурсивті қадам (есепті кішірегіне келтіреміз). Базалық жағдай болмаса, рекурсия шексіз болып, RecursionError қатесі шығады (Python-да тереңдік шегі әдепкі бойынша шамамен 1000).

def fact(n):            # n! = 1·2·…·n
    if n <= 1:          # базалық жағдай
        return 1
    return n * fact(n - 1)

def power(a, n):        # a-ның n дәрежесі
    if n == 0:
        return 1
    return a * power(a, n - 1)

def digsum(n):          # цифрлар қосындысы
    if n < 10:
        return n
    return n % 10 + digsum(n // 10)

def fib(n):             # 1, 1, 2, 3, 5, 8, 13, ...
    if n <= 2:
        return 1
    return fib(n - 1) + fib(n - 2)

Қалай жұмыс істейді: әр шақыру шақырулар стегіне (тәрелкелер бумасы сияқты) салынады және кішірек шақыру қайтқанша күтеді. fact(4) fact(3)-ті күтеді, ол fact(2)-ні, ол — fact(1)-ді. fact(1) бірден 1 қайтарады, сосын стек кері «тарқатылады»: 2⋅1=22\cdot1=2, 3⋅2=63\cdot2=6, 4⋅6=244\cdot6=24.

Егер функция ішінде екі рекурсивті шақыру болса (fib-тегідей), шақырулар ағаш сияқты тармақталады және олардың саны өте тез өседі: fib(6) функцияны 15 рет, fib(7) — 25 рет шақырады. Шақыруларды C(n)=C(n−1)+C(n−2)+1C(n)=C(n-1)+C(n-2)+1, C(1)=C(2)=1C(1)=C(2)=1 формуласымен санау ыңғайлы.

Шығару реті. Егер print рекурсивті шақырудан БҰРЫН тұрса, сандар «түсу кезінде» (тура ретпен) басылады; КЕЙІН тұрса — «көтерілу кезінде» (кері ретпен). Мысал: def g(n): print(n); if n > 1: g(n // 2); print(n) функциясы g(10) кезінде 10 5 2 1 1 2 5 10 шығарады.

Кез келген рекурсияны циклмен (итерациямен) алмастыруға болады және керісінше. Цикл әдетте жылдамырақ және стекті жұмсамайды; рекурсия «өзіне ұқсас» есептерде — ағаштар мен графтарды аралауда (DFS), жылдам сұрыптауда, рекурренттік формула бойынша есептеуде қысқа жазылады.

Жолдар: индекстер, кесінділер, аралау 10 сынып

Жол — символдар тізбегі. Нөмірлеу солдан 0-ден, оңнан −1-ден басталады. s = "informatika" (11 символ) үшін: s[0] = i, s[4] = r, s[-1] = a, len(s) = 11. Жол шегінен тыс индекс (мысалы s[11]) IndexError қатесін береді.

s[start:stop:step] кесіндісі start нөмірінен stop-қа дейінгі символдарды, stop-ты ҚОСПАЙ, step қадамымен алады. start жазылмаса — басынан, stop жазылмаса — соңына дейін. s[2:5] = for, s[:4] = info, s[7:] = tika, s[-3:] = ika, s[::2] = ifraia, s[1::3] = nrta, s[::-1] = akitamrofni (жол кері ретпен). Жол шегінен тыс кесінді қате бермейді — бар бөлігін ғана қайтарады.

Жолдар өзгермейді: s[0] = "I" — қате. Жолды «өзгерту» үшін жаңасын құрады: s = "I" + s[1:]. Амалдар: + біріктіреді, * қайталайды ("ab" * 3 = ababab), in ішінде бар-жоғын тексереді ("for" in s → True), жолдар символ кодтары бойынша символдап салыстырылады ("apple" < "banana", бірақ "Z" < "a", себебі бас әріптердің коды кішірек).

Жолды аралау: for ch in s: — символдар бойынша; for i in range(len(s)): — индекстер бойынша (орны маңызды болғанда керек, мысалы s[i] мен s[i+1]-ді салыстыру). Символ кодтары: ord("A") = 65, ord("a") = 97, chr(66) = B.

Жол әдістері, палиндромдар, символдарды санау, сөздіктер мен жиындар 10 сынып

Әдістер жолды өзгертпейді, жаңа жол қайтарады: s.upper() / s.lower() — әріп регистрі; s.strip() — шеттеріндегі бос орындарды алып тастау; s.replace(a, b) — барлық a-ны b-ға ауыстыру (s.replace(a, b, 1) — тек біріншісін); s.find(x) — бірінші кездесу индексі, жоқ болса −1; s.count(x) — қиылыспайтын кездесулер саны; s.split(sep) — тізімге бөлу; sep.join(тізім) — жолдар тізімін біріктіру; s.isdigit() / s.isalpha() — жол тек цифрлардан / әріптерден тұра ма.

t = "Astana, Almaty, Shymkent"
parts = t.split(", ")     # ['Astana', 'Almaty', 'Shymkent']
print("-".join(parts))     # Astana-Almaty-Shymkent
print(t.find("Almaty"))    # 8
print(t.lower().count("a")) # 5
print("aaaa".count("aa"))  # 2 (3 емес!)

Палиндром — солдан оңға және оңнан солға бірдей оқылатын жол: level, kazak, 12321. Бір жолмен тексеру: s == s[::-1]. Егер регистр маңызды болмаса, алдымен s = s.lower(); бос орындарды елемеу керек болса — s.replace(" ", "").

Символдарды санау. Цифрлар: if ch.isdigit(): total += int(ch). Әріптердің жиілігін сөздікте сақтау ыңғайлы: freq[ch] = freq.get(ch, 0) + 1; "banana" үшін {'b': 1, 'a': 3, 'n': 2} шығады. Сөздік (dict) «кілт: мән» жұптарын сақтайды, кілт бойынша қатынау d["a"], len(d) — кілттер саны.

Жиын (set) тек қайталанбайтын элементтерді ретсіз сақтайды: set("banana") = {'a', 'b', 'n'}, len(set(s)) — әртүрлі символдар саны. Амалдар: | біріктіру, & қиылысу, - айырма.

Файлдармен жұмыс 7, 10 сынып

Файл open(аты, режим) функциясымен ашылады. Режимдер: "r" — оқу (әдепкі; файл жоқ болса — қате), "w" — жазу (файл жасалады, ал бұрын болса — толығымен ТАЗАЛАНАДЫ), "a" — соңына қосып жазу (ескі мазмұны сақталады). with open(...) as f: құрылымы блоктан кейін файлды өзі жабады — f.close()-ты қолмен шақырғаннан гөрі осылай жазған дұрыс.

Оқу: f.read() — бүкіл файл бір жол болып; f.readline() — соңындағы \n символымен бірге келесі бір жол; f.readlines() — барлық (қалған) жолдар тізімі; for line in f: — жолдарды бір-бірлеп аралау. Жазу: f.write(мәтін) тек жол жазады және жаңа жолға көшуді ӨЗІ ҚОСПАЙДЫ — \n-ді анық жазу керек; сандарды жазар алдында жолға айналдырады: f.write(str(x) + "\n").

with open("data.txt", "w") as f:
    f.write("5\n12\n7\n20\n3\n")

with open("data.txt") as f:
    nums = [int(line) for line in f]   # int \n-ді өзі алып тастайды

print(sum(nums), max(nums))   # 47 20

Типтік есеп: «файлда әр жолға бір саннан жазылған, қосындысын / жұп сандар санын / ең үлкенін табыңыз». Үлгі: жолдарды оқу, әрқайсысын санға айналдыру (int(line) немесе int(line.strip())), әрі қарай санауышы бар кәдімгі цикл. Егер сандар бір жолда бос орын арқылы жазылса: nums = list(map(int, f.read().split())).

Файл магнитофон сияқты тізбектей оқылады: readline()-нан кейін «көрсеткіш» келесі жолда тұрады, ал readlines() тек қалған жолдарды қайтарады. Басынан қайта оқу үшін файлды қайта ашу керек.

Сұрыптау және іздеу 9–10 сынып

Көпіршікті сұрыптау: массивті аралап, көршілерді салыстырамыз және сол жақтағысы үлкен болса, орындарын ауыстырамыз. Бірінші өтуден кейін ең үлкен элемент соңына «қалқып шығады»; kk-өтуден кейін соңғы kk элемент өз орнында тұрады. nn элемент үшін: n−1n-1 өту, салыстырулар саны (n−1)+(n−2)+⋯+1=n(n−1)2(n-1)+(n-2)+\dots+1=\frac{n(n-1)}{2}. Алмастырулар саны «инверсиялар» санына — дұрыс емес ретте тұрған жұптар санына тең.

Таңдау арқылы сұрыптау: ii-қадамда ii-элементтен соңына дейінгі элементтердің ең кішісін тауып, оны ii-элементпен алмастырамыз. Салыстырулар саны да n(n−1)2\frac{n(n-1)}{2}, бірақ алмастырулар n−1n-1-ден аспайды. Кірістіру арқылы сұрыптау: кезекті элементті алып, сол жағында үлкені тұрғанша оны солға жылжытамыз — қолдағы карталарды осылай реттейді; дерлік сұрыпталған деректерде өте тез жұмыс істейді.

for i in range(n - 1):              # көпіршік
    for j in range(n - 1 - i):
        if a[j] > a[j + 1]:
            a[j], a[j + 1] = a[j + 1], a[j]

Кірістірілген құралдар: sorted(a) ЖАҢА сұрыпталған тізім қайтарады, a.sort() тізімнің өзін сұрыптайды және None қайтарады. Параметрлер: reverse=True — кему бойынша; key=функция — белгі бойынша сұрыптау: sorted(words, key=len) — ұзындығы бойынша, a.sort(key=abs) — модулі бойынша. Python-дағы сұрыптау орнықты: кілті бойынша тең элементтер бастапқы ретін сақтайды.

Сызықтық іздеу — элементтерді ретімен қараймыз; ең нашар жағдайда nn салыстыру, кез келген массивте жұмыс істейді. Екілік (бинарлық) іздеу — тек СҰРЫПТАЛҒАН массив үшін: ортаңғы mid = (lo + hi) // 2 элементпен салыстырып, ізделетін сан бола алмайтын жартысын тастаймыз; қадамдар саны ⌈log⁡2(n+1)⌉\lceil\log_2(n+1)\rceil-ден аспайды (1000 элемент үшін — 10, миллион үшін — 20).

Графтар: берілуі, аралау, ең қысқа жол, ағаштар 10 сынып

Граф — төбелер мен қабырғалар. Бағытталмаған граф: A–B қабырғасы бойынша екі жаққа да жүруге болады (жолдар). Бағытталған граф: A→B доғасы тек бір жаққа апарады (бір бағытты көшелер, жазылулар). Салмақты граф: әр қабырғаның саны — салмағы бар (қашықтық, уақыт, құн). Жол — қабырғалармен қосылған төбелер тізбегі; жолдың ұзындығы — қабырғалар саны немесе салмақтар қосындысы; цикл — бастапқы төбеге қайта оралатын жол.

Төбенің дәрежесі — одан шығатын қабырғалар саны (тұзақ 2 береді). Барлық төбелер дәрежелерінің қосындысы 2∣E∣2|E|-ге тең, сондықтан тақ дәрежелі төбелер саны әрқашан жұп. Бағытталған графта кіру және шығу жарты дәрежелері ажыратылады.

Сыбайластық матрицасы — n×nn\times n кесте: A–B қабырғасы болса, [A][B] ұяшығында 1 (немесе салмақ), болмаса 0 немесе сызықша тұрады. Бағытталмаған графтың матрицасы бас диагональға қатысты симметриялы; төбенің дәрежесі = оның жолының қосындысы. Сыбайластық тізімі — әр төбе үшін көршілерін тізіп шығамыз; Python-да сөздікпен ыңғайлы: g = {"A": ["B", "C"], "B": ["A", "D"], ...}.

Ені бойынша аралау (BFS) — «толқынмен»: алдымен бастапқы төбенің барлық көршілері, сосын олардың көршілері т.с.с. Кезекті пайдаланады; қабырғалар саны ең аз жолды табады. Тереңдігі бойынша аралау (DFS) — бір тармақпен мүмкіндігінше алысқа барамыз, тірелсек — артқа қайтамыз; рекурсиямен жазу ыңғайлы.

Салмақты графтағы ең қысқа жол (Дейкстра алгоритмі, кесте бойынша қолмен шешіледі): 1) бастапқы төбеге 0, қалғандарына ∞ белгісін қоямыз; 2) белгісі ең кіші, әлі бекітілмеген төбені таңдап, оны «бекітеміз»; 3) оның әр көршісінің белгісін жақсартып көреміз: жаңа белгі = ағымдағы төбенің белгісі + қабырға салмағы, ескісінен кіші болса — ауыстырамыз; 4) соңғы төбеге дейін қайталаймыз. Басты ереже: тура қабырға міндетті түрде ең қысқасы емес — басқа төбелер арқылы айналма жол арзанырақ болуы мүмкін.

Ағаш — циклсіз байланысқан граф; nn төбелі ағашта дәл n−1n-1 қабырға бар және кез келген екі төбе арасында дәл бір жол бар. Тамырлы ағаш: тамыр, ата-аналар, ұрпақтар, жапырақтар (ұрпағы жоқ төбелер). Ағаш түрінде бумалар құрылымын, шежірені, рекурсивті шақырулар ағашын бейнелейді. Циклсіз бағытталған графтағы жолдар саны былай есептеледі: төбеге апаратын жолдар саны = оған доға кіретін барлық төбелерге апаратын жолдар сандарының қосындысы.

Шешімі бар есеп мысалдары

Есеп 1Программа не шығарады?
def f(a, b=3):
    return a * b - 1

x = f(2)
y = f(2, 5)
print(x, y, f(b=1, a=y))
  1. f(2): b параметрі берілмеген, әдепкі мән 3 алынады: 2⋅3−1=52\cdot3-1=5, яғни x = 5.
  2. f(2, 5): 2⋅5−1=92\cdot5-1=9, яғни y = 9.
  3. f(b=1, a=y): атаулы аргументтер, a = 9, b = 1: 9⋅1−1=89\cdot1-1=8.
  4. print үш мәнді бос орын арқылы шығарады.
Жауабы 5 9 8
Есеп 2Функция берілген. digsum(4872) неге тең және digsum функциясы неше рет шақырылады (бірінші шақыруды қоса)?
def digsum(n):
    if n < 10:
        return n
    return n % 10 + digsum(n // 10)
  1. Түсу: digsum(4872) = 2 + digsum(487); digsum(487) = 7 + digsum(48); digsum(48) = 8 + digsum(4).
  2. digsum(4): 4<104<10 — базалық жағдай, жаңа шақырусыз 4 қайтарады.
  3. Көтерілу: 8+4=128+4=12, 7+12=197+12=19, 2+19=212+19=21.
  4. Шақырулар: 4872, 487, 48, 4 аргументтерімен — барлығы 4 (әр цифрға біреуден).
Жауабы 21; функция 4 рет шақырылады
Есеп 3s = "informatika". s[2:5], s[1::3], s[-3:] және s[::-1] мәндерін табыңыз.
  1. Индекстерді жазып шығамыз: i0 n1 f2 o3 r4 m5 a6 t7 i8 k9 a10 (барлығы 11 символ).
  2. s[2:5] — 2, 3, 4 индекстері (5 кірмейді): for.
  3. s[1::3] — 1 индексінен 3 қадаммен: 1, 4, 7, 10 → n, r, t, a: nrta.
  4. s[-3:] — соңғы үш символ: ika; s[::-1] — кері ретпен жазылған жол: akitamrofni.
Жауабы for, nrta, ika, akitamrofni
Есеп 4[5, 1, 4, 2, 8] массиві көпіршікті әдіспен өсу ретімен сұрыпталады. Бірінші өтуден кейін массив қандай болады? Барлығы неше салыстыру және неше алмастыру жасалады?
  1. 1-өту: (5,1) — алмастыру → [1,5,4,2,8]; (5,4) — алмастыру → [1,4,5,2,8]; (5,2) — алмастыру → [1,4,2,5,8]; (5,8) — алмастырусыз. Өтуден кейін: [1,4,2,5,8], 4 салыстыру, 3 алмастыру.
  2. 2-өту: (1,4) жоқ; (4,2) алмастыру → [1,2,4,5,8]; (4,5) жоқ — 3 салыстыру, 1 алмастыру.
  3. 3 және 4-өтулер: 2 + 1 салыстыру, алмастыру жоқ.
  4. Салыстырулар: 4+3+2+1=10=5⋅424+3+2+1=10=\frac{5\cdot4}{2}. Алмастырулар: 3+1=43+1=4 — бұл инверсиялар саны (5>1, 5>4, 5>2, 4>2).
Жауабы [1, 4, 2, 5, 8]; 10 салыстыру, 4 алмастыру
Есеп 5[3, 7, 12, 18, 25, 31, 40, 46, 52, 60, 71] массивінен (индекстер 0–10, mid = (lo + hi) // 2) 46 санын екілік іздеумен іздейміз. Ортаңғымен неше салыстыру қажет болады?
  1. 1-қадам: lo=0, hi=10, mid=5, a[5]=31 < 46 → lo=6.
  2. 2-қадам: lo=6, hi=10, mid=8, a[8]=52 > 46 → hi=7.
  3. 3-қадам: lo=6, hi=7, mid=6, a[6]=40 < 46 → lo=7.
  4. 4-қадам: lo=7, hi=7, mid=7, a[7]=46 — табылды. Бағалау арқылы тексеру: ⌈log⁡212⌉=4\lceil\log_2 12\rceil=4 — 4 қадамнан артық болуы мүмкін емес еді.
Жауабы 4 салыстыру, сан 7-индекстен табылды
Есеп 6A–F пункттері арасындағы жолдар ұзындығының кестесі берілген (сызықша — жол жоқ). A-дан F-ке дейінгі ең қысқа жолдың ұзындығын және жолдың өзін табыңыз.
    A   B   C   D   E   F
A   -   4   2   -   -   -
B   4   -   1   5   -   -
C   2   1   -   8  10   -
D   -   5   8   -   2   6
E   -   -  10   2   -   3
F   -   -   -   6   3   -
  1. Бастау: A=0, қалғандары ∞. A-ны бекітеміз. Көршілері: B=4, C=2.
  2. Ең кіші белгі C-да (2), C-ны бекітеміз. C арқылы: B=min(4, 2+1)=3, D=2+8=10, E=2+10=12.
  3. B-ны (3) бекітеміз. B арқылы: D=min(10, 3+5)=8.
  4. D-ны (8) бекітеміз. D арқылы: E=min(12, 8+2)=10, F=8+6=14.
  5. E-ні (10) бекітеміз. E арқылы: F=min(14, 10+3)=13. F=13-ті бекітеміз.
  6. Жолды соңынан қалпына келтіреміз: F←E←D←B←C←A. Тексеру: 2+1+5+2+3=132+1+5+2+3=13. Байқаңыз: тура A–B жолы (4) A–C–B жолынан (3) ұзын.
Жауабы 13, жол A→C→B→D→E→F

Күрделі есептер: қадам-қадаммен

Есеп 1Рекурсивті процедура берілген. f(3) шақыруы не шығарады? f(5) неше сан шығарады және олардың қосындысы неге тең?
def f(n):
    if n > 0:
        f(n - 1)
        print(n, end=" ")
        f(n - 1)

Идея: Шығаруды кішірек n үшін шығару арқылы жазыңыз: f(n) шығаруы = f(n−1) шығаруы, сосын n, сосын қайтадан f(n−1) шығаруы. Осыдан саны мен қосындысы үшін рекурренттік формулалар шығады.

  1. Кіші мәндер
    f(0) ештеңе шығармайды. f(1): f(0), 1-ді басу, f(0) → 1.
    f(2): f(1) шығаруы, сосын 2, сосын f(1) шығаруы → 1 2 1.
  2. f(3) шығаруы
    f(3) = f(2) шығаруы + 3 + f(2) шығаруы = 1 2 1 3 1 2 1.
  3. Сандар саны
    K(n)=2K(n−1)+1K(n)=2K(n-1)+1, K(0)=0K(0)=0: K(1)=1K(1)=1, K(2)=3K(2)=3, K(3)=7K(3)=7, K(4)=15K(4)=15, K(5)=31K(5)=31, яғни K(n)=2n−1K(n)=2^n-1.
  4. Сандар қосындысы
    S(n)=2S(n−1)+nS(n)=2S(n-1)+n, S(0)=0S(0)=0: S(1)=1S(1)=1, S(2)=4S(2)=4, S(3)=11S(3)=11, S(4)=26S(4)=26, S(5)=57S(5)=57.
    f(3) үшін тексеру: 1+2+1+3+1+2+1=111+2+1+3+1+2+1=11 — сәйкес келеді.
Жауабы f(3) 1 2 1 3 1 2 1 шығарады; f(5) қосындысы 57 болатын 31 сан шығарады
Есеп 2fib(7)-ні есептегенде fib функциясы неше рет шақырылады (бірінші шақыруды қоса)? fib(7) неге тең?
def fib(n):
    if n <= 2:
        return 1
    return fib(n - 1) + fib(n - 2)

Идея: Шақырулар саны C(n) = 1 (шақырудың өзі) + C(n−1) + C(n−2); база үшін C(1)=C(2)=1. Бүкіл ағашты салмаңыз — төменнен жоғары қарай кестемен санаңыз.

  1. Функция мәндері
    fib: n = 1…7 үшін 1, 1, 2, 3, 5, 8, 13, яғни fib(7) = 13.
  2. Шақырулар кестесі
    C(1)=C(2)=1C(1)=C(2)=1; C(3)=1+1+1=3C(3)=1+1+1=3; C(4)=1+3+1=5C(4)=1+3+1=5; C(5)=1+5+3=9C(5)=1+5+3=9; C(6)=1+9+5=15C(6)=1+9+5=15; C(7)=1+15+9=25C(7)=1+15+9=25.
  3. Формуламен тексеру
    C(n)=2⋅fib(n)−1C(n)=2\cdot fib(n)-1: 2⋅13−1=252\cdot13-1=25 — сәйкес келеді. Қарапайым рекурсияның неге баяу екені көрінеді: бір ғана fib(3) бірнеше рет қайта есептеледі (мұны нәтижелерді есте сақтау немесе цикл арқылы түзетеді).
Жауабы 25 шақыру; fib(7) = 13
Есеп 3Бағытталған графта мына доғалар бар: A→B, A→C, B→C, B→D, C→D, C→E, D→E, D→F, E→F. A-дан F-ке дейін неше түрлі жол бар? Олардың нешеуі D арқылы өтеді?

Идея: Циклсіз графта төбеге апаратын жолдар саны оған доға кіретін барлық төбелерге апаратын жолдар сандарының қосындысына тең. A-дан бастап ретімен санаймыз.

  1. Әр төбеге дейінгі жолдарды санаймыз
    A = 1. B: тек A-дан кіреді → 1. C: A мен B-дан → 1+1 = 2. D: B мен C-дан → 1+2 = 3. E: C мен D-дан → 2+3 = 5. F: D мен E-ден → 3+5 = 8.
  2. D арқылы өтетін жолдар
    A→D жолдары: 3. D→F жолдары: тура D→F және D→E→F — 2.
    D арқылы 3⋅2=63\cdot2=6 жол өтеді (көбейту ережесі).
  3. Тексеру
    D арқылы өтпейтін жолдар A→…→C→E→F түрінде болуы керек: A→C→E→F және A→B→C→E→F — дәл 2, және 6+2=86+2=8 — сәйкес келеді.
Жауабы 8 жол, оның 6-уы D арқылы

ҰБТ-дағы жиі қателіктер

  • Кесінді оң шекараны қамтымайды: s[2:5] — бұл 3 символ (2, 3, 4 индекстері), ал нөмірлеу 0-ден басталады. Әрқашан әріптердің астына индекстерді жазып шығыңыз.
  • Функция ішіндегі print пен return — әртүрлі нәрселер. return-сіз функция None қайтарады; a.sort() та None қайтарады, сондықтан print(a.sort()) None шығарады, ал b = a.sort() b-ны бүлдіреді.
  • Базалық жағдайсыз рекурсия (немесе ешқашан орындалмайтын базалық жағдаймен, мысалы тақ n-нен n - 2 қадамымен жүргенде n == 0) тоқтамайды және RecursionError қатесімен аяқталады.
  • "w" режимі файлдың ескі мазмұнын өшіреді, қосып жазу "a" режимінде жасалады. readline() жолды \n-мен бірге қайтарады, ал write() жаңа жолды өзі қоспайды.
  • Екілік іздеу тек сұрыпталған массивте жұмыс істейді. Ал ең қысқа жол есебінде тура қабырға міндетті түрде ең қысқасы емес — айналма жолдарды тексеріңіз.

Есте сақта

Функция: def + return (return жоқ → None); рекурсия = базалық жағдай + қадам; s[a:b] кесіндісі b-сыз; w өшіреді, a қосып жазады; көпіршік — n(n−1)/2 салыстыру; екілік іздеу — тек сұрыпталғанда, ⌈log₂(n+1)⌉ қадам; дәрежелер қосындысы = 2·қабырғалар; Дейкстра — ең кіші белгіні бекіт.

Өзіңді тексер

1. Программа не шығарады: s = "informatika"; print(s[2:5])?
  1. for
  2. nfo
  3. form
  4. orm
Жауабын көрсету

for 2, 3, 4 индекстері (5 оң шекарасы кірмейді): f, o, r.

2. Функция былай берілген: def f(n): return 0 if n == 0 else n % 10 + f(n // 10). print(f(2024)) не шығарады?
  1. 2024
  2. 4
  3. 8
  4. 6
Жауабын көрсету

8 Функция цифрлар қосындысын есептейді: 4+2+0+2=84+2+0+2=8.

3. Классикалық көпіршікті сұрыптау 5 элементтен тұратын массивке неше салыстыру жасайды?
  1. 5
  2. 10
  3. 20
  4. 25
Жауабын көрсету

10 n(n−1)2=5⋅42=10\frac{n(n-1)}{2}=\frac{5\cdot4}{2}=10 (4, 3, 2 және 1 салыстырудан тұратын өтулер).

4. Бағытталмаған графта 6 төбе және 8 қабырға бар. Барлық төбелер дәрежелерінің қосындысы неге тең?
  1. 6
  2. 8
  3. 14
  4. 16
Жауабын көрсету

16 Әр қабырға екі төбенің дәрежесіне 1-ден қосады: 2⋅8=162\cdot8=16.

5. Бар файлды open("data.txt", "a") командасымен ашып, оған жазғанда не болады?
  1. Файл тазаланады, сосын мәтін жазылады
  2. Файл бұрыннан бар болғандықтан қате шығады
  3. Мәтін файлдың соңына қосып жазылады
  4. Файл тек оқу үшін ашылады
Жауабын көрсету

Мәтін файлдың соңына қосып жазылады "a" (append) режимі ескі мазмұнды сақтап, соңына жазады; файлды "w" режимі тазалайды.

6. 1000 элементтен тұратын сұрыпталған массивте екілік іздеуге ортаңғымен ең көп дегенде неше салыстыру қажет?
  1. 500
  2. 10
  3. 100
  4. 1000
Жауабын көрсету

10 Әр қадам аралықты екіге бөледі: ⌈log⁡21001⌉=10\lceil\log_2 1001\rceil=10, себебі 210=1024>10002^{10}=1024>1000.

Байланысты тақырыптар

Деңгейіңді біл: ҰБТ-ға тегін диагностика