Transcript O(n)
ניתוח זמן ריצה
(על קצה המזלג)
קרן כליף
ביחידה זו נלמד:
מהו ניתוח זמן ריצה
מוטיבציה
הגדרה
ניתוחי זמן ריצה בסיסיים
2
© Keren Kalif
קבוע
לינארי
ריבועי
לוגריתמי
משפחות של פונקציות
לינאריות:
כאשר aו b -קבועים
ריבועיות:
כאשר a,bו c -קבועים
f)n( = a∙n + b
f)n( = a∙n2 + b∙n + c
מעריכיות (אקספוננציליות):
f(n) = 2n
3
© Keren Kalif
ניתוח זמן ריצה -מוטיבציה
כאשר אנחנו מריצים את התוכניות שלנו ,נראה לנו שהן
רצות מאוד מהר ,ואנחנו לא עוצרים לחשוב כמה עבודה
באמת מבוצעת ע"י המחשב
ב"עולם האמיתי" לעיתים יש חשיבות לכל מיקרו שנייה
שהתוכנית רצה
נרצה לדעת להעריך האם התוכנית שכתבנו יעילה,
כלומר כמה עבודה המחשב באמת מבצע
נרצה לבחון האם יש דרך לכתוב את התוכנית בצורה
יותר יעילה
4
© Keren Kalif
זמן ריצה -הגדרה
זמן ריצה של תוכנית הוא סדר גודל של מספר הפעולות
שהתוכנית מבצעת ביחס לגודל הקלט
סדר גודל אינו מספר מדויק אלא הערכה של מספר
הפעולות המבוצעות בתוכנית
5
© Keren Kalif
ניתוח זמן ריצה – זמן ריצה קבוע לעומת
זמן ריצה תלוי משתנה
כמה זמן לוקח למחשב לחשב את:
;x = x + y
כמה זמן לוקח למחשב לחשב את:
)for (i=1 ; i <= n ; i++
;x += i
6
© Keren Kalif
התשובה תלויה במהירות המחשב ,אך הנחה סבירה היא
שפעולה זו על אותו מחשב בזמנים שונים תיקח זמן זהה
במקרה זה זמן הריצה תלוי בגודלו של nשאינו ידוע מראש,
ולכן צריך לקחתו בחשבון בזמן הניתוח התיאורטי ,שכן יהיה
הבדל משמעותי אם n=10או ...n=100,000,000
ניתוח זמן ריצה – זמן ריצה קבוע )O(1
כאשר מספר הפעולות של התוכנית קבוע בכל הרצה,
נאמר כי זמן הריצה הוא קבוע ,ונסמנו בO(1) -
)(void main
{
;int num
;“ cout << “Please enter a number:
;cin >> num
;cout << “The number is ” << num << endl
}
7
© Keren Kalif
בתוכנית זו מספר הפעולות תמיד יהיה זהה ,לא משנה מה ערכו
של num
ניתוח זמן ריצה – זמן ריצה קבוע )O(1
מציאת מי המספר המינימלי ומי המקסימלי:
)(void main
{
;int num1, num2, min, max
;“ cout << “Please enter 2 numbers:
;cin >> num1 >> num2
;min = num1
;max = num2
)if (min > num2
{
בעת חישוב ניתוח זמן ריצה נסתכל תמיד על המקרה
;min = num2
הגרוע ביותר ,כלומר המקרה בו יהיו הכי הרבה
;max = num1
פעולות ולכן בדוגמא זו נניח כי ה if -מבוצע
}
}
8
© Keren Kalif
עדיין במקרה זה מספר הפעולות קבוע בכל הרצה ,אפילו אם
ערכם של num1ו num2 -מאוד גדול ,ולכן זמן הריצה של
תוכנית זו הוא )O(1
ניתוח זמן ריצה – תלות בגודל הקלט
(לינארי)
חישוב עצרת:
)(void main
{
;int num, fact=1
מספר הפעולות בתוכנית זו תלוי בערכו של :num
התוכנית תבצע תמיד את הפעולות הקבועות של
קבלת הקלט והדפסת התוצאה ,אבל מספר
;“ cout << "Enter a number:
הפעמים שהלולאה תרוץ תלוי בקלט.
;cin >> num
)for (int i=1 ; i <= num ; i++
;fact *= i
;cout << num << “! = “ << fact << endl
}
9
© Keren Kalif
מספר הפעולות בתוכנית זו הוא ) O(1עבור הפעולות הקבועות ועוד ) O(1פעולות בכל
איטרציה של הלולאה ,ומאחר ויש numאיטרציות:
)O(main) = O(1) + num*O(1) = O(1) + O(num*1) = O(1) + O(num
כאשר numמאוד גדול זמן הריצה הקבוע זניח ולכן נאמר כי:
)O(main) = O(1) + O(num) = O(num
ניתוח זמן ריצה – תלות בגודל הקלט
(לינארי) ()2
הדפסת המספרים הזוגיים עד מספר מסוים:
)(void main
{
;int num
;“ cout << "Please enter a number:
;cin >> num
;“ cout << "All even numbers from 1 to “ << num << “:
) for (int i=0 ; i < num ; i+=2
; “ “ << cout << i
;cout << endl
}
מספר הפעולות בתוכנית זו הוא ) O(1עבור הפעולות הקבועות ועוד ) O(1פעולות בכל
איטרציה של הלולאה ,ומאחר ויש num/2איטרציות:
)O(main) = O(1) + (num/2)*O(1) = O(1) + O((num/2)*1) = O(1) + O(num/2) =O (num/2
כאשר numמאוד גדול זמן הריצה הקבוע זניח ולכן נאמר כי:
)O(main) = O(num/2) = O(num
10
© Keren Kalif
ניתוח זמן ריצה – תלות בגודל הקלט
)(ריבועי
void main()
{
int width, height;
:הדפסת מלבן
cout << "Enter a rectangle's width and height: ";
O(1)
cin >> width >> height;
for (int i=1 ; i <= height ; i++)
{
for (int j=1 ; j <= width ; j++)
width*O(1) = O(width)
cout << “*”;
cout << endl;
}
heigth*O(width) =
O(height*width)
}
O(height *width) :סה"כ זמן הריצה של התוכנית
width == height == n אם
O(n2) סדר גודל זמן הריצה היה
11
© Keren Kalif
ניתוח זמן ריצה – תלות בגודל הקלט
(ריבועי)
)(void main
{
;int num
הדפסת משולש:
;" cout << "Please enter the base of the triangle:
;cin >> num
בדוגמא זו מספר הפעולות בלולאה
הפנימית שונה בכל איטרציה ,ולכן נבדוק
ביתר קפידה כמה פעולות באמת
מתבצעות :באיטרציה הראשונה של
הלולאה הראשית לולאה הפנימית תרוץ
פעם אחת ,באיטרציה השנייה פעמיים וכו'..
)for (int i=1 ; i <= num ; i++
{
)for (int j=1 ; j <= i ; j++
;”*“ << cout
;cout << endl
}
}
סדר גודל זמן הריצה של התוכנית הוא מספר הפעולות בסה"כ של הלולאה הראשית:
,1+2+…+numוזוהי סדרה חשבונית שסכומה:
)O(main) = O(num*(num+1)/2) = O((num2+num)/2) = O(num2 + num)= O(num2
12
© Keren Kalif
ניתוח זמן ריצה – תלות בגודל הקלט
(לוגריתמי)
הדפסת חזקה:
)(void main
{
;int num
;“ cout << "Please enter a number:
;cin >> num
;“ cout << "All 2 powers till “ << num << “:
)for (int i=1 ; i <= num ; i*=2
;“ “ << cout << i
;cout << endl
{
מספר הפעולות בתוכנית זו הוא ) O(1עבור הפעולות הקבועות ועוד ) O(1פעולות בכל
איטרציה של הלולאה ,אך מהי כמות האיטרציות של הלולאה?
13
© Keren Kalif
ניתוח זמן ריצה – תלות בגודל הקלט
(לוגריתמי)
למשל עבור :n=128
כמות האיטרציות היא כמות הפעמים שנכפיל ב 2 -עד שנגיע
ל: n -
1248163264128
אפשר לשאול כמה פעמים הכפלנו את 2בעצמו עד קבלת
:128
2? = 128
וזוהי בדיוק פעולת ה:log -
log2128
לכן ,כמות הפעולות שתרוץ עבור לולאה שקצב
ההתקדמות שלה הוא כפל/חילוק הוא log
14
© Keren Kalif
ניתוח זמן ריצה לוגריתמי
כלומר ,ככל שבסיס הלוג יותר גדול,
כך כמות הפעולות קטנה (יותר יעיל)
)for (int i=1 ; i <= 240 ; i*=2
…..
כמות האיטרציות:
256128643216842 1
log2256 = 8
15
© Keren Kalif
)for (int i=1 ; i <= 240 ; i*=3
…..
כמות האיטרציות24381931 :
log3243 = 5
השוואת סדרי גודל
כאשר אנו כותבים תוכנית נשאף שזמן הריצה יהיה נמוך
ככל שניתן
נזכור כי:
)O(1) < O(log3n) < O(log2n) < O(n) < O(n2) < O(n3
16
© Keren Kalif
חיבור סדרי גודל
void foo(int n, int m)
{
for (int i=1 ; i <= n; i++)
cout << i;
cout << endl;
for (int i=1 ; i <= m; i++)
cout << i;
}
,m- לn מאחר ולא ידוע לנו היחס בין
O(n+m) נאמר שסדר הגודל הוא
17
© Keren Kalif
דוגמא :2קבל מספר והחזר מהי הספרה
המופיעה הכי הרבה פעמים
אופציה :1לספור כמה פעמים מופיעה הספרה 1ע"י
לולאה על כל המספר ,הספרה 2וכו'
אופציה :2מיון דליים
18
© Keren Kalif
) ,10*O(nכאשר nהוא מספר הספרות במספר
)10*O(n) = O(n
) ,O(nכאשר nהוא מספר הספרות במספר
int countDigits1(int num)
O(n)
{
int max=0,
maxCount=0;
for (int i = 0; i < 10;
i++)
{
int temp =
num;
int count = 0;
while (temp >
0)
{
if
(temp % 10 == i)
count++;
temp /= 10;
}
if (count >
maxCount)
{
הקוד
int countDigits2(int num)
{
int counters[10];
O(n)
while (num > 0)
{
counters[num %
10]++;
num /= 10;
}
int max = 0;
for (int i = 1; i < 10; i++)
if (counters[i] >
counters[max])
max = i;
return max;
}
19
© Keren Kalif
ביחידה זו למדנו:
מהו ניתוח זמן ריצה
ניתוחי זמן ריצה בסיסיים
20
© Keren Kalif
מוטיבציה
הגדרה
קבוע
לינארי
ריבועי
לוגריתמי