460 likes | 636 Views
תרגול 2 – מערכים ופונקציות. מבוא לתכנות. היום בתרגול. 1. מערך חד-מימדי: מה זה מערך ולמה צריך אותו? איך מגדירים? איך זה נראה בזכרון? דוגמאות לשימוש במערך חד-מימדי. השוואה בין משתנה פרימיטיבי למשתנה שאינו פרימיטיבי. 2. פונקציות. מערך חד-מימדי.
E N D
תרגול 2 – מערכים ופונקציות מבוא לתכנות
היום בתרגול 1. מערך חד-מימדי: • מה זה מערך ולמה צריך אותו? • איך מגדירים? איך זה נראה בזכרון? • דוגמאות לשימוש במערך חד-מימדי. • השוואה בין משתנה פרימיטיבי למשתנה שאינו פרימיטיבי. 2. פונקציות
מערך חד-מימדי • מערך הינו מבנה זיכרון המכיל מספר ערכים מאותו טיפוס, גודל המערך נקבע כאשר הוא נוצר (בזמן ריצה) ולאחר מכן הוא קבוע. • אילו טיפוסים אנו מכירים?
מערך - מאפיינים • משתנה שאינו פרימיטיבי • מבנה מסודר של ערכים. • לכל ערך יש מקום. • כל איברי המערך הם מאותו סוג. • מערך יכול להכיל כל טיפוס פרימיטיביוכן טיפוסים שאינם פרימיטיביים כפי שנלמד בהמשך
הצורך במערך • יש צורך לשמור מספר גדול של משתנים מאותו סוג. • זהו מבנה מאורגן המאגד בתוכו קבוצה גדולה של ערכים שניתן לעבור עליהם באופן שיטתי.
הגדרת מערך • כמו כל משתנה, גם מערך צריך הגדרה והשמה. //declares an array of integers int[] myArray; • ההגדרה מורכבת מטיפוס המערך ומשם המערך. • הסוגריים המרובעים לאחר הטיפוס מציינים שהמשתנה המוגדר הוא מסוג מערך.
הקצאת זכרון • ההגדרה עצמה אינה מקצה זיכרון עבור המערך, אלא רק מכריזה על קיומו ויש ליצור (על ידי הקצאת זיכרון) את המערך. // create an array of integers myArray = new int[5]; myArray 0 0 0 0 0 טבלת משתנים
הקצאת זכרון באמצעות משתנה int size = 5; int[] myArray; myArray = new int[size];
length –גודל המערך int size = 5; int[] myArray; myArray = new int[size]; System.out.println(myArray.length(; // prints 5 size = 6; מה לדעתכם תדפיס כעת השורה הבאה? System.out.println(myArray.length);
null – ערך מיוחד • משתנים המצביעים על מערכים יכולים גם לקבל השמה לערך המיוחד null: • myArray = null; • בטבלת המשתנים ערכו של המשתנה myArray הוא המיוחד הקבוע null. myArray null
שאלה • מה נקבל כאשר נבקש myArray.length לפני שהקצינו את המערך? int[] myArray; System.out.println(myArray.length); • תשובה: שגיאת קומפילציה, הקומפיילר מזהה את השגיאה ועוצר את תהליך הקומפילציה.
שאלה • ואם נבקשmyArray.length כאשר נעשתה לו השמה ?null int[] myArray = null; System.out.println(myArray.length); • תשובה: שגיאת זמן ריצה (מסוג NullPointerException) המציינת שניסינו לפנות למשתנה שערכו הוא null, הקומפיילר אינו מזהה את השגיאה.
שאלה • ובמקרה: int[] myArray = new int[0]; System.out.println(myArray.length);מה יודפס למסך? • תשובה: 0
הגדרה והקצאה בשורה אחת • int[] myArray = new int[5]; • int[] aSmallPrimes ={2,3,5,7,11}; myArray 0 0 0 0 0 aSmallPrimes 2 3 5 7 11
מספור תאים במערך • אם במערך יש n תאים המערכת מתייחסת אליהם ע"י המספרים 0…n-1
פנייה לאיבר (תא) במערך int[] aaSmallPrimes= {2,3,5,7,11}; • קריאת ערך מתא במערך : int num = aaSmallPrimes[3] * 2; // num = 7*2 = 14
פנייה לאיבר במערך • aaSmallPrimes[3] = 13; • num נשאר ללא שינוי
פנייה לאיבר במערך • aaSmallPrimes[5] = 17; • num = aSmallPrimes[-1]; Run Time Error
פנייה לאיבר במערך • int i = 5; myArray[i] = 3; • myArray [i/2] = 1; • בתוך ה-[] יכול להיות ביטוי מתמטי,קריאה לפונקציה וכו', כל עוד התוצאה הינה מטיפוס שלם.
פעולות על מערך //Demonstrates basic array operations class BasicArray { publicstaticvoid main(String[] arg) { int[] aSmallPrimes = {2,3,5,7,11}; System.out.println(aSmallPrimes[0]); 2 aSmallPrimes[0] = 13; System.out.println(aSmallPrimes[0]); 13 System.out.println(aSmallPrimes.length); 5 for(int i=0;i<aSmallPrimes.length;i=i+1) System.out.print(aSmallPrimes[i]+", "); 13, 3, 5, 7, 11, } //main } //class BasicArray 20
איתחול מערך ע"י לולאה //Demonstrate array init with a loop classIntArray { publicstaticvoidmain(String[] arg) { int[] intArray = newint[5]; System.out.println(); for(int i=0;i < intArray.length ;i=i+1) intArray [i] = i*3; for(inti=0;i<intArray.length;i=i+1) System.out.print(intArray[i]+", "); } //main } //class IntArray 0, 3, 6, 9, 12,
משתנה פרימיטיבי int x = 3; int y = x; x=7; • y נשאר ללא שינוי. 3 7 3
משתנה שאינו פרימיטיבי int[] xArray = new int[5]; int[] yArray = xArray; xArray[1] = 6; xArray 0 0 6 0 0 0 yArray
שאלה • מה יקרה בזכרון בזמן הרצת הקוד הבא? int[] myArray; myArray = new int[5]; myArray = new int[10]; myArray 0 0 0 0 0
null כתובת int[] arr1 = null; int[] arr2 = null; System.out.println(arr1==arr2); true
מוטיבציה • לעיתים, אנו נזקקים לבצע פעולה מסוימת או לעשות חישוב מסוים מס' רב של פעמים. • במקום לשוב ולכתוב את הקוד מס' רב של פעמים,ניתן לכתוב פונקציה שעושה את הפעולה הרצויה ולקרוא לפונקציה זו בכל פעם שרוצים להשתמש בה. • כבר ראינו את השימוש בפונקציה Math.abs()
מבנה של פונקציה public static <return type> <func name> (<arg1_type> <arg1>, <arg2_type> <arg2>, …) { <function body> } • חתימה של פונקציה מורכבת משם הפונקציה ומרשימת טיפוסי הארגומנטים שהפונקציה מקבלת (מספר, סוגי טיפוסים וסדר) • לכל שתי פונקציות בתכנית חתימה שונה • הערך המוחזר וכן מאפיינים נוספים של פונקציה )כגון public ו- static ) אינם נכללים בחתימה של הפונקציה public staticint foo(int num){…} √ public staticint foo(int num1, double num2){…} √ public static int foo(double num){…} √ public static double foo(int num){…} X
ערך החזרה של פונקציה • יש פונקציות שלא צריכות להחזיר ערך, אלא רק לבצע משהו (למשל פונקציה שמדפיסה מערך). במצב כזה נכתוב מילה void בתור <return value type>. • פונקציה שמחזירה ערך חייבת להכיל את הפקודה <value>”“return)פעם אחת או יותר).
דוגמאות להגדרה ושימוש בפונקציות: • // Shows how to define and use a simple function • publicclass Max{ • // returns the larger number between the arguments • publicstaticdouble max(double dx, double dy){ • double ans; • if(dx < dy) • ans = dy; • else • ans = dx; • return ans; • } • publicstaticvoid main(String[] args){ • double dx1, dx2, dx3; • dx1 = 2; dx2 = 0; dx3 = -1.8; • System.out.println(max(dx1, max(dx2, dx3))); • } • }
publicclass Sum{ publicstaticvoid main(String[] args){ int iLastInd = 10; int iSum = sumNums(lastInd); System.out.println(“The sum of numbers from 1 to “+ iLastInd + “ = “ + iSum ); System.out.println(“The sum of numbers from 1 to “+ 8 + “ = “ + sumNums(8)); } // returns the sum of numbers from 1 to end publicstaticint sumNums(int iEnd) { int iSum = 0; for(int i = 1; i <= iEnd; i = i+1) iSum = iSum + i; return iSum ; } }
Flow of previous func • בזמן קריאה לפונקציה: • השליטה של התכנית שומרת את המיקום הנוכחי שלה ועוברת לפונקציה. • נפתחת סביבה (טבלת משתנים) חדשה שבה מוגדרים הפרמטרים של הפונקציה והמשתנים שמוגדרים בתוך הפונקציה. • ההוראה return (או סיום הפונקציה במקרה של void) סוגרת את הסביבה ומחזירה את השליטה למקום בו היינו לפני הקריאה לפונקציה
public class Sum{ public static void main(String[] args){ int iLastInd = 10; intiSum = iLastInd ); System.out.println(“The sum of numbers from 1 to “+ iLastInd + “ = “ + iSum ); System.out.println(“The sum of numbers from 1 to “+ 8 + “ = “ + sumNums(8)); } // returns the sum of numbers from 1 to end public static int sumNums(int iEnd) { intiSum = 0; for(int i = 1; i <= iEnd; i = i+1) iSum = iSum + i; return iSum ; } } sumNums(10) main 1 55
Passing values/references • iSum in the previous example עוד קצת על פונקציות • הפונקציה הראשית נקראת main וממנה מתחילה ההרצה. • ניתן לכתוב פונקציות נוספות מלבד ה-main. • הפונקציות יכולות לקרוא אחת לשניה. • אפשר להעביר לפונקציה ערכים. • פונקציה יכולה להחזיר ערך אחד בלבד או כלום. • בכל פונקציה אפשר להגדיר משתנים הנקראים משתנים לוקליים,והם מוגדרים רק בתוך הפונקציה (SCOPE)
הדפסת מערך של int-ים publicstatic void printArray(int[] arr) { for(int i=0; i < arr.length; i=i+1) { System.out.print(arr[i]+” “); } System.out.println(); }
חישוב המקדם הבינומי המציין את מספר תתי הקבוצות בגודל k , של קבוצה בגודל n. • publicclass BinCoeff{ • publicstaticvoid main(String[] args) • { • int n = 5 , k = 3; • System.out.print("The number of different subsets of • size " + k + " in a set of size " + n + “ is:" ); • System.out.println(nChooseK(n,k)) ; • } • … • } • /* output : The number of different subsets of size 3 in a set of size 5 is:10 */
// Assumes that n>=0 publicstaticint factorial(int iN) { int iResult = 1; for(int i=2; i <= iN; i = i+1) { result = iResult * i; } return iResult ; } publicstaticint nChooseK(int iN, int iK) { int iAns = 0; if (iN >= iK && iK >=0) ans = factorial(iN)/(factorial(k)*factorial(iN - iK)); return iAns ; }
העברת משתנים לפונקציה ב-Java מועברים בעת קריאה לפונקציה בעלת פרמטרים, הערכים הרשומים בטבלת המשתנים, בין אם מדובר בערך ממש או בכתובת: - אם הפרמטר הוא מטיפוס פרימיטיבי,מה שיעבור לפונקציה הוא הערך של המשתנה , ולכן הפונקציה לא תוכל לשנות את המשתנה המקורי. - אם הפרמטר הוא מטיפוס שאינו פרימיטיבי, כלומר מכיל מצביע לאובייקט (כגון מערך), אז הפונקציה מקבלת את הכתובת, ויכולה לשנות את האובייקט בזיכרון.
דוגמא להעברת פרמטרים מטיפוס פרימיטיבי: publicstaticvoid main(String[] args){ int iX =8; System.out.println(iX ); add5(iX ); System.out.println (iX ); } publicstaticvoid add5(int iX ){ iX = iX +5; System.out.println (iX ); }
אם היינו רוצים לשנות את הערך של x מה היינו עושים? היינו צריכים לשנות את add5 כך שתחזיר ערך ואותו להכניס ל x : publicstaticvoid main(String[] args){ int iX =8; System.out.println(iX ); iX =add5(iX ); System.out.println(iX ); } publicstaticint add5(int iX ) { iX = iX +5; System.out.println(iX ); return iX ; } 41
דוגמא להעברת פרמטרים מטיפוס לא פרימיטיבי: publicstaticvoid main(String[] arg){ int [] arr={1,2,3}; printArray(arr); add5(arr); printArray(arr); } publicstaticvoid add5(int[] arr) { for (int i=0 ; i< arr.length ;i=i+1) arr[i] = arr[i]+5; printArray (arr); } /*output 1 2 3 6 7 8 6 7 8 */ 42
הפונקציה הבאה אמורה להחליף ערכי שני משתנים מטיפוס int, ובכל זאת אינה עובדת. מה הבעיה? publicstaticvoid swap(int a, int b){ int tmp; tmp = a; a = b; b = tmp; } 43
שאלה 4 מבוחן 2004 (17 נק') הפונקציהboolean allDiff(int[] a)מקבלת כקלט מערך של שלמים a ומחזירה "true" אם ורק אם כל אברי המערך שונים זה מזה.ניתן להניח כי מערך הקלטשונה מ- null. השלימו את גוף הפונקציה בדף התשובות.ניקוד מלא יינתן על סמך נכונות הקוד וסגנונו. publicstaticboolean allDiff(int[] a){ boolean ans = true; // השלימו return ans; } 45
פתרון: for(int i = 0; i < a.length-1 && ans; i=i+1) for(int j = i+1; j < a.length && ans; j=j+1) if(a[i] == a[j]) ans = false; 46