קצת על המבנה של הקורס:
- נתחיל בלהגדיר שפה מתמטית ולפרמל את הרעיון של נוסחאות נסיגה, זמני ריצה וסיבוכיות אסימפטוטית.
- נעבור ללהכיר מבני נתונים שונים
- לקראת סוף הקורס נדבר על דברים שיכינו אותנו לקורס אלגוריתמים 1
ההגדרות הבסיסיות
יהיו f(n),g(n):N→R+.
נאמר כי f(n)=O(g(n)) אם קיימים c,n0∈R+ כך שלכל n≥n0 מתקיים: f(n)≤c⋅g(n).
יהיו f(n),g(n):N→R+.
נאמר כי f(n)=Ω(g(n)) אם קיימים c,n0∈R+ כך שלכל n≥n0 מתקיים f(n)≥c⋅g(n).
יהיו f(n),g(n):N→R+.
נאמר כי f(n)=Θ(g(n)) אם f(n)=Ω(g(n))∧f(n)=O(g(n)).
יהי p(n)∈Nk[n] שמקדמיו חיוביים. כלומר:
p(n)=a0+a1n+⋯+aknk=i=0∑kainiai≥0,ak>0
נרצה להראות כי p(n)=O(nk). עבור כך נרצה למצוא קבועים c,n0>0 כך שלכל n≥n0 מתקיים p(n)≤c⋅nk.
נשים לב כי לכל 0≤i≤k ולכל n≥1 מתקיים ni≤nk ולכן נקבל כי:
p(n)=i=0∑kaini≤i=0∑kaink=(i=0∑kai)nk
ולכן, עבור n0=1,c=i=0∑kai מתקיים כי p(n)≤c⋅nk ולכן p(n)=O(nk).
כעת, נרצה להראות כי p(n)=Ω(nk). נשים לב כי לכל n≥1 מתקיים כי:
i=0∑kaini=a0+a1n+⋯+aknk≥aknk
ולכן, עבור n0=1,c=ak נקבל כי p(n)≥c⋅nk ובכך p(n)=Ω(nk).
לפי הגדרה מתקיים כי p(n)=Θ(nk).
הראו כי לכל קבוע k≥2 מתקיים:
i=0∑nki=1+k+⋯+kn=O(kn)
נשתמש בסכום סדרה הנדסית:
i=0∑nki=k−1kn+1−1≤k−1kn+1
מכיוון ש-k≥2 מתקיים כי k−1≥21k ולכן:
i=0∑nki≤21kkn+1=2kn
ולכן, לפי הגדרה ∑i=0nki=O(kn).
הוכיחו כי log(n!)=Θ(nlogn).
הוכחה:
נראה כי log(n!)=O(nlogn) תחילה. לפי הגדרה נקבל:
log(n!)=log(1⋅2⋯n)=log1+log2+⋯+logn↓ היא פונקציה מונוטוניתlogn≤nlogn
לכן, עבור c=1,n0=1 נקבל כי logn!=O(nlogn).
כעת, נראה כי log(n!)=Ω(nlogn).
log(n!)=log1+log2+⋯+log2n+⋯+logn≥log2n+⋯+logn≥2nlog2n=2n(logn−log2)=2nlogn−2n
הערה (טריק שיחזור בכמה מקומות)
אם אנחנו פוגשים פונקציה שהיא אינטואיטיבית גדולה מפונקציה אחרת, אנחנו יכולים לפצל אותה ולבטל איכשהו את הפונקציה הקטנה יותר.
log(n!)≥2nlogn−2n=4nlogn+4n(logn−2)≥4nlogn
נשים לב כי השלב האחרון מתקיים רק עבור n≥4 שכן logn−2≥0 עבור n≥4.
הלוג ה"רגיל" במדעי המחשב הוא log2 ולכן כל ה-log-ים פה היו log2 בסתר.
לכן מתקיים כי log(n!)=Ω(nlogn) עם c=41,n0=4 בהגדרה.
לכן, לפי הגדרה log(n!)=Θ(nlogn).
∎
משפטים על החסמים
יהיו f1,f2,g1,g2:N→R כך ש: f1(n)=O(g1(n)) ו-f2(n)=O(g2(n)). אזי:
- מתקיים f1(n)+f2(n)=O(g1(n)+g2(n)).
- מתקיים f1(n)+f2(n)=O(max{g1(n),g2(n)})
- מתקיים f1(n)⋅f2(n)=O(g1(n)⋅g2(n)).
הוכחה:
קיימים קבועים c1,n01>0 כך שלכל n≥n01 מתקיים f1(n)≤c1g1(n) וקיימים קבועים c2,n02>0 כך שלכל f2(n)≤c2g2(n).
לכן:
f1(n)+f2(n)≤c1g1(n)+c2g2(n)≤(c1+c2)g1(n)+(c1+c2)g2(n)=(c1+c2)(g1(n)+g2(n))
ולכן, עבור c=c1+c2,n0=max{n01,n02} מתקיים לפי הגדרה כי f1(n)+f2(n)=O(g1(n)+g2(n)).
באותו האופן נקבל גם כי:
f1(n)+f2(n)≤(c1+c2)(g1(n)+g2(n))≤(c1+c2)⋅2max{g1(n),g2(n)}
ולכן, עבור c=2(c1+c2),n0=max{n01,n02} מתקיים לפי הגדרה כי f1(n)+f2(n)=O(max{g1(n),g2(n)}).
לבסוף, נקבל גם כי:
f1(n)⋅f2(n)≤c1⋅g1(n)⋅c2⋅g2(n)=(c1⋅c2)(g1(n)⋅g2(n))
ולכן, עבור c=c1c2,n0=max{n01,n02} מתקיים לפי הגדרה כי f1(n)⋅f2(n)=O(g1(n)⋅g2(n)).
∎
האם מתקיים כי f1(n)f2(n)=O(g1(n)g2(n))?
התשובה היא לא
בשאלות מסוג אלו תמיד כדאי לנסות להפריך קודם.
נסתכל למשל על הפונקציות f1(n)=g1(n)=n ו-f2(n)=2,g2(n)=1.
הטענה n2=O(n) אינה נכונה ונראה זאת באמצעות הנחה בשלילה.
נניח בשלילה כי קיימים c,n0>0 עבורם לכל n≥n0 מתקיים n2≤c⋅n נחלק ב-n שכן n=0 ונקבל כי:
n≤c
מה שאינו נכון אם נקח n=max{n0,c+1} ולכן הגענו לסתירה ומתקיים כי n2=O(n).
חישוב זמן ריצה של תוכנית
scanf("%d", &n);
int k = 2;
while (k < n)
{
k += 1;
}
הפקודות מחוץ ללולאה הינן O(1) ועלות איטרציה יחידה היא O(1).
מספר האינטרציות הוא n−2 ולכן סך זמן הריצה של התוכנית הוא O(n).
בסוף האיטרציהk234⋮i+2⋮nמספר האיטרציה012⋮i⋮n−2
scanf("%d", &n);
int k = 2;
while (k < n)
{
k = k * 2;
}
כעת, מכיוון שאנחנו משנים את k בתוך הלולאה יהיה לנו זמן ריצה שונה מהדוגמה הקודמת. האיטרציה האחרונה תקרה כאשר:
2i⋅2≥n⟹i+1≥log2n⟹i≥log2n−1
לכן, סך זמן הריצה של התוכנית הוא O(logn).
scanf("%d", &n);
int k = 2;
while (k < n)
{
k = k * k * k;
}
בתוכנית זו אנחנו משנים את k באופן דרסטי ובעצם עושים k=k3 ולכן האיטרציה אחרונה תתרחש כאשר 23i≥n ולכן:
3i≥logn⟹i≥log3(log2n)
ולכן סך זמן הריצה הוא O(loglogn).
סימונים אחרונים לתרגול
נאמר כי f(n)=o(g(n)) אם לכל c>0 קיים n0>0 כך שלכל n≥n0 מתקיים f(n)≤c⋅g(n).
נאמר ש-f(n)=o(g(n)) אם ורק אם limn→∞g(n)f(n)=0.
נאמר ש-f(n)=ω(g(n)) אם לכל c>0 קיים n0>0 כך שלכל n≥n0 מתקיים f(n)≥c⋅g(n).
n→∞limf(n)g(n)=0⟺f(n)=ω(g(n))
לכל קבוע ε>0 מתקיים כי logn=o(nε).
הוכחה:
נוכיח את הטענה לפי ההגדרה השקולה של o. כלומר, נראה כי limn→∞nεlogn=0.
לפי כלל לופיטל נקבל כי:
n→∞limnεlogn=n→∞limε⋅nε−1ln21n1=n→∞limεln21nε1=0
∎
נתונות פונקציות f,g:N→R+.
נגדיר f(n)=S(g(n)) אם מתקיים f(n)=O(∑i=1ng(i)).
הוכח/הפרך:
א. n2=S(n).
ב. n=S(logn)
ג. f(n)=S(g(n)) וגם g(n)=S(h(n)) אז f(n)=S(h(n)).
פתרון א':
הטענה נכונה.
אם אנחנו לוקחים את הסכום זה סכום של סדרה חשבונית וכבר ראינו שסכום של פונקציות זה O(הפונקציה המקסימלית)
הוכחה:
נרצה להראות כי n2=O(∑i=1ni), כלומר, נרצה להראות כי קיימים קבועים c,n0>0 כך שלכל n≥n0 מתקיים:
n2≤ci=1∑ni=c2n(n+1)=21c(n2+n)
אם נבחר c=2 נקבל n2≤n2+n וברור כי זה מתקיים לכל n∈N+.
∎
פתרון ב':
הטענה גם כן נכונה.
הוכחה:
נרצה להראות כי n=O(∑i=1nlogi). כלומר, שקיימים קבועים c,n0>0 כך שלכל n≥n0 מתקיים:
n≤ci=1∑nlogi=clog(n!)
נזכר כי ראינו ממקודם כי log(n!)=Θ(nlogn) ולכן, מתקיים log(n!)=Ω(nlogn). כלומר, קיימים קבועים c′,n0′>0 כך שלכל n≥n0′ מתקיים:
log(n!)≥c′⋅nlogn⟹c′1log(n!)≥nlogn
נשים לב כי לכל n≥2 מתקיים nlogn≥n ולכן לכל n≥n0=max{2,n0′} מתקיים n≤c⋅log(n!) כאשר c=c′1.
∎
פתרון ג':
הטענה אינה נכונה.
נראה דוגמה נגדית באמצעות הפונקציות f(n)=n2,g(n)=n,h(n)=logn.
בסעיפים א' ו-ב' ראינו כי n2=S(n) וכי n=S(logn) אולם הטענה n2=S(logn) אינה נכונה.
נניח בשלילה כי n22=S(logn), כלומר, קיימים קבועים c,n0>0 כך ש-n2≤c∑i=1nlogi=clog(n!).
ראינו בתחילת התרגול כי log(n!)=Θ(nlogn) ולכן בפרט log(n!)=O(nlogn). כלומר, קיימים קבועים c′,n0′>0 כך שלכל n≥n0′ מתקיים log(n!)≤c′⋅nlogn.
לכן, לכל n≥max{n0,n0′} מתקיים:
n2≤c⋅c′⋅nlogn⟹n≤c⋅c′⋅logn
בסתירה לכך ש-logn=o(n).