Professional Documents
Culture Documents
מבוא למדעי המחשב סיכום
מבוא למדעי המחשב סיכום
2021
באדיבות מדור אקדמיה ,אגודת הסטודנטים ,אוניברסיטת בן גוריון.
www.bgu4u.co.il
תוכן עניינים
הרצאה – 1הכרת הקורס ,אלגוריתם 2 .................................................................................................
הרצאה – 2מתחילים לתכנת 5 ...........................................................................................................
הרצאה – 3אלמנטים בסיסיים בשפה 8 ...............................................................................................
הרצאה – 4מערכים 13 .....................................................................................................................
הרצאה – 5פונקציות 16 ...................................................................................................................
הרצאה – 6חיפוש ומיון 19 ................................................................................................................
הרצאה – 7המשך מיון ,חתימות 23 ....................................................................................................
הרצאה – 8מחרוזות וטיפוסים עוטפים 27 ............................................................................................
הרצאה – 9בעיית הסיפוק הבוליאני 31 ........................................................................................ SAT
הרצאה – 10רקורסיה 32 ................................................................................................................ 1
הרצאה – 11רקורסיה 36 ................................................................................................................ 2
הרצאה – 12מבוא לתכנות מובנה עצמים 39 ..................................................................................... 1
הרצאה – 13מבוא לתכנות מובנה עצמים 43 ..................................................................................... 2
הרצאה – 14מבוא לתכנות מובנה עצמים 45 ..................................................................................... 3
הרצאה – 15מבוא לתכנות מובנה עצמים 49 ..................................................................................... 4
הרצאה – 16ממשקים 52 ..................................................................................................................
הרצאה – 17המשך ממשקים 55 ........................................................................................................
הרצאה – 18עצים בינאריים 59 ..........................................................................................................
הרצאה – 19עצי חיפוש בינאריים 64 ..................................................................................................
הרצאה – 20איטראטורים על עצים ,מחסנית( ,)Stackתור(67 ..................................................... )Queue
הרצאה – 21שימושים במחסנית ,ביטויים בנוסח 72 .................................................................. Postfix
הרצאה – 22גרפים 76 ................................................................................................................... 1
הרצאה – 23גרפים 80 ................................................................................................................... 2
הרצאה – 24מיון רקורסיבי82 ..................................................................................... memoization ,
הרצאה – 25המשך 85 ................................................................................................ memoization
25.10.18
הרצאה 1
כללי:
מיכל שמש shemesh@cs.bgu.ac.il
משרד 37/319
שעות קבלה יום ה' 10-12
אתר הקורס www.cs.bgu.ac.il/~intro191
דיקנאט הסטודנטים
פנינה ישראלי – עו"ס
pninai@bgu.ac.il
08-6528584
אלגוריתם
סדרת הוראות שביצוען יובל אותנו לפתרון הבעיה.
5תכונות לאלגוריתם ע"פ :Knuth
סופיות .1
מוגדרות .2
קלט .3
פלט .4
אפקטיביות (מחזיר תשובה נכונה) .5
ניתן לתאר אלגוריתם בכל צורה/שפה שהיא ,על עוד הוא מובן לכותב ולמבצע.
בעיה לדוגמה:
קלט :מס' שלם וחיובי X
פלט :מס' הספרות של X
2
דוגמה לאלגוריתם:
חילוף מותנה
קלט :שני מספרים x, y
פלט :אותם שני מספרים x, yכך ש x≤y
x=2 x=4 x=1 דוגמהx=2 x=4 x=3 :
y=5 y=4 y=3 y=5 y=4 y=1
GCD
בעיית מציאת המחלק המשותף המקסימלי – Greatest Common Divisor
קלט m, n :חיוביים שלמים
פלטGCD(m,n) :
*תזכורת i :מחלק את mאם שארית החלוקה של mב i-היא .0
מחלקים
1 2 3 4 6 8 12 16 24 48 m=48
1 2 3 5 6 10 15 30 n=30
GCD(48,30)=6
3
פעולת מציאת שארית מסומנת ב %-ונקראת .moduloהשארית מסומנת ב.)remainder( r-
0≤r< n ,r = m%n ↔ m = p × n + r
האלגוריתם של אוקלידס:
m n r קלט m,n :שלמים חיוביים .1
30 48 30 r ← m%n .2
48 30 18 כל עוד ()r≠0 .3
30 18 12 m←n .3.1
n ←r .3.2
18 12 6
r←m%n .3.3
12 6 0
פלטn : .4
האלגוריתם תמיד עוצר ומחזיר תשובה נכונה לכל קלט .בכל שלב m,nמקבלים ערכים חדשים.m’,n’ :
קבוצת המחלקים המשותפים של = m,nקבוצת המחלקים המשותפים של ’ .m’,nניתן להוכיח בהכלה דו כיוונית.
4
26.10.18
הרצאה 2
מתחילים לתכנת
5
import java.util.Scanner;
public class DIGITS {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int x = myScanner.nextInt();
int counter = 1;
while (x >= 0) {
x = x/10
counter = counter+1;
}
System.out.println(counter);
}
}
√m הקטן או שווה לp מחלקm- נוכיח שקיים ל. פריקm- נניח ש.m>1 נתון:הוכחה
p×q=m וגם1<p≤q<m שלמים כך שp,q פריק ← קיימיםm
p=q -נניח ש •
p×q=p×p=m
p2 =m
p=√m
) (ללא הגבלת הכלליותp<q נניח.p≠q :אחרת •
p×q<p×p=m
p2 <m
p<√m
6
import java.util.Scanner;
public class IsPrime {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int number = myScanner.nextInt();
boolean isPrime =true;
int divisor = 2;
while (divisor*divisor <= number & isPrime) {
if (number%divisor == 0){
isPrime = false;
}
divisor = divisor+1;
}
System.out.println(isPrime);
}
7
28.10.18
3 הרצאה
אלמנטיים בסיסיים בשפה
:משתנים
. ניתן לרשום בו ערך.משתנה הוא מקום בזכרון בעל שם וטיפוס
:דוגמאות
type name value
int n 50
int number 2
boolean isPrime true
Scanner myScanner ?
boolean isPrime; , int n; :)על כל משתנה צריך להצהיר (ההצהרה תתבצע פעם אחת
isPrime = true , n = 50; :לפני שעושים שימוש במשתנה יש לבצע השמה מתאימה
: טיפוסים פרייטיביים8 java-ב
long(64 bit), int(32 bit), short(16 bit), byte(8 bit) :שלמים .1
double(64 bit), float (32 bit) :ממשיים .2
boolean (8 bit) :שקר/אמת .3
char (16 bit) :תו .4
byte = המספר המינימלי שניתן לייצג ע"י1 + byte המספר המקסימלי שניתן לייצג ע"י
8
ביטויים אריתמטיים
ביטוי אריתמטי הוא ביטוי חשבוני .ביטוי חשבוני מורכב מ:
סוגריים אופרטורים משתנים ערכים
)( + a 2
- b -1
* c -17.5
%
סדר פעולות
כפל וחילוק קודמים לחיבור וחיסור
int x = 3 + 4 – 2 * 5 * 5
אם לא בטוחים – סוגריים.
העמסת אופרטורים
אופרטור יכול לפעול בצורה שונה בהתאם לאופרנדים (=לנתונים) עליהם הוא פועל.
דוגמה :אופרטור החילוק
type name value
;int i = 5/2
int i 2
double x 2.0 ;double x = 5/2
double y 2.5
double z 2.5 ;double y = 5.0/2
;double z = 5.0/2.0
9
דוגמה נוספת:
;)System.out.println(“The answer is: “+6+3
”“The answer is: 6
”“The answer is 63
.The answer is 63
ביטויים בוליאניים
מורכבים מ:
ליטרלים (ערכים) true, false •
משתנים (מטיפוס )boolean •
פעולות השוואה<= ,>= ,< ,> ,!= ,== : •
פעולות לוגיות&& ,|| ,)and( & ,)or( | ,)not( ! : •
ביטוי בוליאני מורכב כך:
ליטרל או משתנה •
<ביטוי בוליאני><אופרטור><ביטוי בוליאני> •
<ביטוי אריתמטי><אופרטור><ביטוי אריתמטי> •
<ביטוי בוליאני>! •
אופרטורים סדרתיים:
יהיו aו b-ביטויים בוליאניים
הביטוי – a&b , a|bמחשבים קודם כל את aבנפרד ואת bבנפרד ואח"כ מופעל האופרטור. •
הביטוי a&&b , a||bפועלים סדרתית .קודם כל מחושב .aלפי תוצאת החישוב של aמוחלט האם לחשב •
את bואז מופעל האופרטור .דוגמה:
;double x = 0
) - (x != 0) && (100/x ==2לאחר חישוב הביטוי הראשון יתקבל falseוהאופרטור לא יופעל.
;double x = 0
)(x != 0) & (100/x ==2
false שגיאה
10
רק אז,false מחזירa אם. והאופרטור לא יופעלb אין צורך לבדוק אתtrue מחזירa אם- || באופרטור
.b האופרטור יופעל ויבדוק את
block משפט
{ { -משפט בלוק הוא אוסף משפטים לביצוע סדרתי עטופים ב
משפטי תנאי
if ({ )ביטוי בוליאני
.
בלוק פקודות.
.
{
if else משפט
if ()תנאי בוליאני
}{בלוק פקודות
else
}{בלוק פקודות
for לולאת
for (<)>קידום<;>תנאי<;>אתחול
}{בלוק פקודות
: נוכל לכתוב גם כךAllPrimes את התכנית
import java.util.Scanner;
public class AllPrimes {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int n = myScanner.nextInt();
int number = 2
while (number <= n){
boolean isPrime =true;
For (int divisor = 2; divisor*divisor<=number & is prime; divisor = divisor+1){
if (number%divisor == 0)
isPrime = false;
divisor = divisor+1;
}
if else (isPrime)
System.out.println(isPrime);
number = number+1
}
}
}
11
( scopeטווח החיים) של משתנה:
משתנה קיים אך ורק בתוך הבלוק שבו הוא הוצהר .כאשר יוצאים מהבלוק ,טבלת הערכים של אותו בלוק נמחקת
ואיתה כל המשתנים שהוצהרו בה.
אם משתנה הוגדר מחוץ לבלוק וערכו השתנה בתוך הבלוק ,הערך החדש שלו נשאר.
12
1.11.18
הרצאה 4
תזכורת -תוכנית המדפיסה את כל הראשוניים עד n
;import java.util.Scanner
{ public class AllPrimes
{)public static void main(String[] args
;)Scanner myScanner = new Scanner(System.in
int n = myScanner.nextInt(); //50
{)for (int number =2 ; number <= n; number = number +1
;boolean isPrime =true
;int divisor = 2
{ )for (int divisor=2; divisor*divisor <= number & is prime; divisor = divisor+1
)if (number%divisor == 0
;isPrime = false; = divisor+1
}
)if (isPrime
;)System.out.println(number
}
}
}
מערכים
הגדרה :רצף תאים מטיפוס מסויים בזכרון.
הצהרה.int[] arr = new int [3]; :
המספר שבסוגריים מסמן את מספר התאים שמוקצים .חייבת להיות התאמה בין הטיפוסים.
= arrקיצור של ,arrayמערך
המקומות של arrמסומנים משמאל לימין ונספרים מ.0
את הערכים של arrבדרך כלל מאתחלים ל.0-
;]int[] arr1 = new int[3
;int x = 3
;arr1[0]=1
;arr1[1] = 2
;arr1[2] = arr[1]+1
13
;}int[] arr2 = {1,2,3
arr1 – S.o.p(arr1 == arr2); //falseו arr2מצביעים על מקומות שונים ולכן יודפס .false
;int y = 3
S.o.p (x == y); //true
int [] arr3 = arr2
S.o.p (arr2 == arr3); //true
כדי להדפיס מערך מסויים צריך לוודא שהוקצה עבורו מקום בזכרון ,כלומר שהוא לא .null
14
arr2 לולאה המדפיסה את ערכי התאים של
for (int i=0; arr2!=null && i < arr2.length; i = i+1){
System.out.println(arr2[i]);
}
System.out.println(number);
}
}
}
15
2.11.18
הרצאה 5
פונקציות חריגות וTesting-
פונקציה היא בלוק של פקודות שמאוגדות יחד .יש לה שם ותפקיד.
כדי "להתחיל" פונקציה כותבים .public static
פונקציית Main
סדר הכתיבה של הפונקציות בתוך המחלקה לא משנה ,כיוון שהתכנית מיד תחפש קודם כל את פונקציית .main
הפונקציה יכולה לקרוא לפונקציה השניה כמה פעמים שתרצה.
בפונקציה תמיד תהיה הצהרה על משתנה שישלח אותנו לפונקציה הבאה .כדי לחזור לפונקציית mainנכתוב
)( returnבהתאם למשתנה שהוצהר.
דוגמה לפונקציה למציאת GCD
;import java.util.Scanner
{ public class GCD
{)public static void main(String[] args
;)Scanner myScanner = new Scanner(System.in
;)(int m = myScanner.nextInt
;)(int n = myScanner.nextInt
;)int result = gcd(m,n
;)System.out.println(“The gcd of “ +x+ “and “ +y+ “is: “ +result
}
}
16
מבנה הפוקנציה
public static <return value type><name>({)רשימת הפרמטרים
.
int output;
.
.
.
return output;
}
אם לא.) (כלומר כלוםvoid אך ניתן לציין שהערך שמחזירה הפונקציה היא,הפונקציה תמיד מחזירה ערך מסויים
.return רוצים שהפונקציה תחזיר ערך מסויים אפשר גם לוותר על השורה
דוגמאות נוספות
פונקציה למציאת מחלקים של מספר
import java.util.Scanner;
public class Divisors {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int n = myScanner.nextInt();
int divisor = findDivisor(n);
if (divisor == -1)
System.out.println(n+” is prime”);
else
System.out.println(divisor +” divides ”+n);
}
} //end of class
17
//assume n>0, 1<divisor<n
public static boolean isDivisor(int n, int divisor){
return (n&divisor == 0);
}
**continuing from main(next function)**
System.out.println(“Testing “ + n1 + “: “);
if (findDivisor(n3) != -1)
System.out.println(“error“);
:) הראשונה שכתבנוmain שבודקת את נכונות הפונקציות (יכולה להחליף את פונקצית הmain דוגמה לפונקציית
import java.util.Scanner;
public class Divisors {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int n1 = 25;
int n2 = 100;
int n3 = 31;
System.out.println(“Testing “ + n1 + “: “)
if (isDivisor (n1, findDivisor(n1)))
System.out.println(“success!”);
else
System.out.println(“error”);
}
} //end of class
**back to isDivisor**
היא,פונקציית בדיקה (ופונקציות באופן כללי) לא צריכה לדעת כיצד פועלות הפונקציות האחרות איתן הן עובדות
.צריכה רק את שמות הפונקציה ואת שמות הפרמטרים
בעיית המיון
. מסודרים בסדר לא יורד, מערך עם אברי מערך הקלט: פלט. מערך של מספרים שלמים:קלט
{1, 2, 5, 7, 10} :דוגמה למערך ממויין
?בהינתן מערך של מספרים – כיצד נוודא שהוא ממויין
- isSorted פונקציית
import java.util.Scanner;
public class isSorted {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int[] arr = {5,7,3,2};
boolean ans = isSorted(arr);
System.out.println(“ans”);
} //end of class
18
2.11.18
6 הרצאה
חיפוש ומיון
void דוגמה עם פונקציה מסוג
import java.util.Scanner;
public class Change {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int a = 3;
int b = 5;
change (a,b);
System.out.println(a + “, “ + b);
} //end of class
.“3, 5” לא מחזירה ערך בסוף ולכן במקרה זה הפלט יהיהvoid פונקציה מסוג
דוגמה זו באה להמחיש את העבודה עם פונקציות וטיפוסים פרימיטיביים וכי טבלת הנתונים נמחקת בסוף כל מחזור
.חיים של הפונקציה
דוגמה נוספת
import java.util.Scanner;
public class ChangeAarray {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int[] arr = {1, 2, 5, 4};
printArray(arr);
change (a,b);
System.out.println(a + “, “ + b);
} //end of class
19
: תעביר אותנו לפונקציה הבאהprintArray קריאה לפונקציה
public static int printArray(int a, int b){
if (arr == null)
System.out.println(arr);
else{
System.out.println(“{ “);
for (int element: arr)
System.out.println(element+” “);
System.out.println(“}”);
}
return;
}
בעיית החיפוש
. key ) מערך של מסרים שלמים (יתכן והוא ריק) ומפתח (מספר שלם: קלט.1
. אם לא נמצא בו-1 מיקום המפתח במערך או: פלט.2
8 5 2 מפתח {1, 2, 5, 5, 7} :דוגמה
-1 3 2 1 פלט
. לא משנה איזה, יוחזר מיקום אחד,כאשר קימיים מס' מיקומים
20
חיפוש ליניארי
.)מעבר ובדיקה של כל הערכים (עד מציאת מיקום המפתח או עד סוף המערך אם לא קיים בו
import java.util.Scanner;
public class LinearSearch {
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
int[] arr = {1, 2, 5, 4};
int key = 4;
System.out.println(arr, key);
//arr != null
public static linearSearch(int[] arr, int key){
if (arr == null)
throw new NullPointerExeption();
int output = -1;
for (int i=0; i < arr.length & output == -1; i = i+1){
if (arr[i] == key)
output = i;
}
return output;
}
-1 0 3 10 10 17 52 60 63
0 1 2 3 4 5 6 7 8
21
הקוד
//arr != null, arr is sorted.
{)public static int binarySearch(int[], int key
;}int[] arr = {1, 2, 5, 4
;int key = 4
)if (arr == null
;)(throw new IllegalArgumentExeption
;int output = -1
;boolean found = false
;int low = 0
;int high = arr.length-1
{)while (low <= high & !found
;int middle = (low+high)/2
{)if (arr[middle]==key
;found = true
;output = middle
}
)else if (arr[middle]<key
;low = middle+1
else
;high = middle-1
}
;return output
} //end of class
חיפוש ביניארי לוקח log nפעולות .במדעי המחשב בסיס הלוג הוא תמיד !!2
בעיית המיון
קלט :מערך של מספרים שלמים
פלט :מערך עם אברי מערך הקלט ,מסודרים בסדר לא יורד.
-7 -6 0 1 1 2 2 10 וכן הלאה ,עד למצב שבו כל האיברים ממוינים
0 1 2 3 4 5 6 7
22
4.11.18
הרצאה 7
פונקציית - SelectionSortהמשך
פונקציית main
;import java.util.Scanner
{ public class Sort
{)public static void main(String[] args
;)Scanner myScanner = new Scanner(System.in
;}int[] arr = {1, 0, 7, 3, -1 ,6
;)SelectionSort (arr
}printArray (arr); //{-1 0 1 3 6 7
}
}
23
{)public static void insertionSort(int[] arr
)if (arr == null
;)(throw new IllegalArgumentExeption
{)for (int i=1; i<arr.length; i=i+1
;)insert (arr, i
}
}
24
import java.util.Scanner;
public class Signatures {
public static int div2(int n){
Scanner myScanner = new Scanner(System.in);
return n/2;
{
public static double div2(double d){
Scanner myScanner = new Scanner(System.in);
return d/2;
}
public static void main(String[] args]{
int x = 5;
double y = 5.0;
System.out.println(div2(x)); //2
System.out.println(div2(y)); //2.5
}
}
מערכים דו מימדיים
.מערכים שהתאים שלהם מכילים מערכים אחרים – מטריצות
import java.util.Scanner;
public class Signatures {
public static void main(String[] args]{
int size = 3;
int[] arr = new int[size];
int[][] 2darr = new int [size][];
2darr = new int[size][4];
2darr[1][0] = 7;
2darr[2][3] = 2;
2darr = {{1,2}, {}, {3}, null}
System.out.println(2darr[2].length); //1
}
0 1 2 3
0 F F T T
1 F F T T
2 T T F T
3 T T T F
25
import java.util.Scanner;
public class BigTrip {
public static boolean hasLegalSteps(boolean[][] flights, int[] tour]{
boolean ans = true;
for {int i=0; i<tour.length-1 & ans; i=i+1){
if flighs[[tour[i]][tour[i+1]] == false)
ans = false;
}
return ans & flights[tour[tour.length-1]][0])
}
}
26
8.11.18
8 הרצאה
מחרוזת וטיפוסים עוטפים
String - מחרוזת
String - טיפוס המייצר אוסף של תווים
ניתן ליצור סטרינג חדש באותו שם ולהגדיר ערך. – לא ניתן לשנות אותן אחרי שיצרנו אותןImmutable מחרוזות הן
.אחר
String str1 = new String(“Hello”);
String srtr2 = “world!”
String str3 = new String();
String str4 = new String(“hello”);
String str5 = “”;
String str6 = null
String str = ”world!!”
System.out.println(str1 == str4); //false
String str7 = str1.substring(2);
String str8 = Str1 + “ “ + str2;
27
: כמה שיטותString לטיפוס
length .1
System.out.println(str1.length()); //5
System.out.println(str3.length()); //0
System.out.println(str6.length()); //RunTime error
יש סוגריים כיוון שלטיפוס יש שיטה כלשהי שבה הוא משתמשstr1.length() ב,בניגוד למערכים
equals .2
שיטה בוליאנית שבודקת אם סטרינג שווה לסטרינג אחר
System.out.println(st1.equals(str4)); //true
מאותחלstr1 – ללא תתקבל פה שגיאת זמן ריצה כיSystem.out.println(st1.equals(str6)); //false
str6לערך מסויים וניתן לבדוק אותו מול
str6 – תתקבל שגיאת זמן ריצה כיSystem.out.println(str6.equals(str1)); //RunTime error
. ואין איך לבדוק אותוnullמאותחל ב
charAt .3
i שיטה שבודקת את ערך התו שבמקום
System.out.println(str1.charAt(0)); //’H’
System.out.println(str.charAt(0)); //RunTime error
indexOf .4
יוחזר האינדקס הראשון, אם התו מופיע מספר פעמים.שיטה שבודקת את האינדקס של התו שהכנסנו
System.out.println(str1.indexOf(‘l’)); //’2’
System.out.println(str1.indexOf(‘A’)); //’-1’
substring .5
שיטה שמדפיסה (או יוצרת – תלוי אם הגדרנו מחרוזת חדשה) תת מחרוזת לפי האינדקסים שהגדרנו לה
) (לא כוללm (כולל אותו) עד האינדסק הi) – המחרוזת תדפיס מהמספר הi, m( בסוגרים
System.out.println(str1.substring(0,3)); // “Hel”
בגוגלString API Java לחפש,*כדי לקבל עוד מידע ולחפש עוד שיטות
: ותו כלשהו ומחזירה את מספר המופעים של התו במחרוזתnullנכתוב פונקציה המקבלת מחרוזת שונה מ
28
16 ,10 ,8 מספרים בבסיס
.10 נרצה לחשב את ערכה המספרי בבסיס.16 ,10 ,8 נתונה לנו מחרוזת המייצגת מספר שלם ואי שלילי בבסיס
0x יש קידומת16 למספרים בבסיס,0 יש קידומת8 למספרים בבסיס
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
:מימוש חלופי
public static int toInt(char ch){
//1 אם התו אינו חוקי תחזיר.10 ומחזירה את ערכה המספרי בבסיס16 הפונקציה מקבלת תו המייצג ספרה בבסיס
String digits = “0123456789ABCDEF”
return.indexOf(ch).
}
29
טיפוסים עוטפים
ב javaלכל טיפוס פרימיטיבי יש מחלקה עוטפת מתאימה .המחלקה תכתב עם אות גדולה וצריך להגדיר אותה.
למחלקות אלה שיטות כמו של מחרוזות.
((boolean – Boolean ,int – Integer
;)Integer n = new Integer(42
;)Boolean B = New Boolean(false
;Integer n2 = 42
System.out.println(n+3); //45
30
11.11.18
הרצאה 9
בעיית הסיפוק הבוליאני SAT -
בעיה :בהינתן נוסחה בתחשיב הפסוקים ,האם יש לה השמה מספקת?
תחשיב הפסוקים הוא בעצם אוסף של בעיות בוליאניות .נוסחה בתחשיב הפסוקים בנויה מדיסיונקציות (ביטויים
לוגיים שמפריד ביניהם האופרטור "או" |) שמחוברות ביניהן עם האופרטור &.
באופן כללי ,כל ביטוי המיוצג ב JAVAע"י האופרטורים & | ! הוא ביטוי בוליאני ולכן הוא נחשב כנוסחה בתחשיב
הפסוקים.
את נוסחת הפסוקים שיצרנו נכניס כקלט לפותרן ה SATוכפלט נקבל השמה מספקת (אם יש כזו).
הקלט לפותרן ה SATחייב להיות נוסחה בצורת .CNF
כיצד נראית נוסחת ?CNF
נוסחת CNFבנויה כמערך דו מימדי של .int
כל שורה מייצגת דיסיונקציה והשורות ביחד מייצגות קוניונקציה
("מחוברות" ביניהן עם האופרטור &).
לכל ביטוי לוגי יש ייצוג מספרי .הייצוג המספרי מתחיל מ1
(ולא מ) .0את המספר נכניס למערך בהתאם לבעיה שנרצה
לפתור .אם נרצה לייצג שלילה של הביטוי ,נכניס אותו כמספר
שלילי.
פותרן ה SATיחזיר לנו בחזרה השמה ( )assignmentהמיוצגת כמערך חד מימדי בוליאני .הערך במקום ה 0-לא
רלוונטי כיוון שהביטויים הלוגיים שלנו ממוספרים מ 1ומעלה.
אם אין השמה מספקת ,יוחזר מערך .null
מהי השמה מספקת?
השמה מספקת CNFאם היא מספקת את כל הפסוקיות שלו. .1
השמה מספקת פסוקית אם היא מספקת לפחות ליטרל אחד. .2
השמה מספקת ליטרל חיובי Xאם היא מציבה בו ערך "אמת". .3
השמה מספקת ליטרל שלילי ¬Xאם היא מציבה ב Xערך "שקר". .4
31
15.11.18
10 הרצאה
)1 מבוא לחשיבה רקורסיבית (רקורסיה
n פונקציית העצרת של
פתרון איטראטיבי
n>=0 ,n פונקציית העצרת של
f(n) = 1*2*3*…..*n
f(0) = 1
public static int factorial (int n){
int output = 1;
for (int i=2; i<=n; i = i+1){
output = output*i;
}
return output;
}
פתרון רקורסיבי
n! = 1*2*3*…..*(n-1)*n
32
רקורסיה היא פונקציה שמחשבת ערך ע"י קריאה לעצמה.
קטן 😊 קבוע וקטן (לא תלוי ב)n סדר גודל של n פתרון איטראטיבי
33
הפונקציה מחזירה את מספר הדרכים לחלק nחלזונות לזוגות n ,זוגי//n>=0 ,
{)public static int pm (int n
;int output
{)if (n==0
;output = 1
}
{else
;)output = (n-1)*pm(n-2
}
;return output
}
פתרון איטראטיבי
הפונקציה מחזירה את מספר הדרכים לחלק nחלזונות לזוגות n ,זוגי//n>=0 ,
{)public static int pm (int n
;int output = 1
{)for (int i=3; i<n; i = i+2
;output = output*i
}
;return output
}
גדול ☹ קבוע וקטן (לא תלוי ב)n סדר גודל של n פתרון איטראטיבי
סדרת פיבונאצ'י
סדרת פיבונאצ'י מוגדרת כך שכל איבר שווה לסכום שני האיברים הקודמים לו1, 1, 2, 3, 5, 8, 13, 21, 34… :
34
פתרון רקורסיבי
//assumes n>=0
{)public static int fib (int n
;int output
{)if (n==0 | n==1
;output = 1
}
{else
;)output = fib(n-1)+fib(n-2
}
;return output
}
פתרון איטראטיבי
//assumes n>=0
{)public static int fib (int n
;int output
{)if (n==0 | n==1
;output = 1
}
{else
;int f0 = 1, f1 =1
{)for (int i=2; i<=n; i = i+1
;output = f0 + f1
;f0 = f1
;f1 = outpout
}
}
;return output
}
ספיידרמן
ספיידרמן מטפס על בניין בעל nקומות .בכל צעד יכול לקפוץ קומה 1או .2
בכמה דרכים שונות יכול ספיידרמן להגיע לקומה ה?n
דוגמה:
אם n=4
2+2 .1
1+1 +2 .2
1+2+1 .3
2+1+1 .4
1 + 1+1+1 .5
פתרון רקורסיבי
נשים לב כי הנוסחה הרקורסיבית לספיידרמן ,היא בדיוק הנוסחה המדוייקת לפיבונאצ'י
35
18.11.18
11 הרצאה
2 רקורסיה
בשיטה רקורסיביתGCD פתרון בעיית
public static int gcd (int x, int y){
int output;
if (x%y == 0){
output = y;
}
else{
output = gcd(y, x%y);
}
return output;
}
היפוך מחרוזת
“abcd” :קלט
“dcba” :פלט
//assumes s != null
public static String reverse (String s){
String output;
if (s.length() == 0){
output = s;
}
else{
output = reverse(s.substring(1)) + s.charAt(0);
}
return output;
}
מגדלי האנוי
36
בכל שלב מותר להעביר רק דסקית אחת .אסור להניח דסקית על דסקית קטנה ממנה.
נעביר ברקורסיה n-1דסקיות מ a -ל .b-נזיז דסקית מ a-ל.b-
נזיז דסקית מ a-ל.c-
נעביר ברקורסיה n-1דסקיות מ b-ל.c-
{)public static void hanoi (int n, char source, char dest, char extre
{)if (n>0
;)hanoi (n-1, source, extra, dest
;)System.out.println(“move sisk from “ + source + “ to “ + dest
;)hanoi (n-1, extra, dest, source
{
}
37
//n >= 0, k >= 0
public static int choice (int n, int k({
int output;
if (k>n){
output = 0;
}
else if (k == 0 | k == n) {
output = 1;
}
else{
output = choice(n-1, k) + choice(n-1, k-1);
}
return output;
}
//acc ולכל אחת מהן שרשר אתn איברים מתוךk הדפס את כל האפשרויות לבחור
public static void printAllChoices (int n, int k, String acc){
int output;
if (k <= n){
if(k==0){
System.out.println(acc);
}
else{
printAllChoices (n-1, k, acc); //n בלי
printAllChoices (n-1, k-1, acc + “ “ + n); //n עם
}
}
38
22.11.18
12 הרצאה
מבוא לתכנות מונחה עצמים
n – תכנית המדפיסה את כל הראשוניים עד4 תזכורת משיעור
public static int primesArray(int n){
Scanner myScanner = new Scanner(System.in);
int[] primes = new int[n];
int numberOfPrimes = 0; //מונה את הראשוניים שנמצאו עד כה ומספר לנו מהו האינדקס של התא הפנוי הבא
for (int number =2 ; number <= n; number = number +1){
boolean isPrime =true;
for (int primesIndex = 0; primesIndex < numberOfPimes && primes[primesIndex]*primes[primesIndex] <= number; primesIndex = primesIndex+1{
if(number%primes[primesIndex] == 0)
isPrime = false;
}
if (isPrime){
primes[numberOfPrimes] = number;
numberOfPrimes = numberOfPrimes+1;
}
System.out.println(number);
}
}
}
הוא לא טיפוסObject - על אף ש. שמייצגת כל משתנה שאינו פרימיטיביJAVA היא מחלקה מופשטת בObject
)Object o1 = i1 הוא יכול להצביע למקום בזכרון ע"י השמה של משתנה לא פרימיטבי אחר (כמו,פרימיטיבי
.Integer הוא גםObject לא כל.Object הוא גם, ובאופן כללי כל משתנה שאינו פרימיטיבי,Integer כל
39
ניתן ליצור מערך מסוג .Objectכאמור Object ,יכול לייצג טיפוסים שונים ,לכן כך ניתן לייצר מערך בעל טיפוסים
שונים.
40
public class DynamicArray {
שדות private static int DEFAULT_CAPACITY = //ביצוע השמה
fields private Object[] data;
private int size;
private int incrementSize;
}
: שנזכרנו בו בתחילת השיעור4 נשכתב את הקוד משיעור
}
return primes;
}
41
מימוש הבנאים
.X יש את השםX לכל הבנאים של מחלקה
public DynamicArray{
this(DEFAULT_CAPACITY);
{
42
25.11.2018
הרצאה 13
מבוא לתכנות מובנה עצמים – 2רשימה משורשרת
במחלקה Objectשתי שיטות חשובות:
boolean equals(Object) .1
מבצעת השוואה לוגית בין העצם המפעיל את השיטה לעצם המתקבל כפרמטר.
השיטה מחזירה trueכאשר הערכים של שני האובייקטיבים שווים.
String toString() .2
השיטה מחזירה מחרוזת המתארת את האובייקט.
היתרון של הרשימה המשורשרת הוא שניתן לבצע שינויים במערך – לא מוגבלים מבחינת מקום ומבחינת הקצאת
תאים ,ניתן להכניס איברים באמצע המערך.
רשימה מקושרת בנויה מאוסף של חוליות .הרשימה שומרת כל ערך/נתון בחוליה .החוליות מקושרות אחת לשניה
באמצעות הפניות.
אוסף החוליות יוצר אוביי קט שנקרא רשימה .הרשימה מתאפיינת ע"י החוליה הראשונה .כלומר ,החוליה הראשונה
מגדירה את אופי הרשימה .אנחנו לא רוצים לאפשר לנתון הראשון בחוליה הראשונה להיות null
43
public class LinkedList{ //הרשימה
private Link first;
public LinkedList(){
first = null; //הבנאי הריק
}
public boolean isEmpty(){
return first == null;
}
public void addFirst(Object element){
if (element == null)
throw new IllegalArgumentException();
if (isEmpty())
first = new Link(element);
else
first = new Link(element, first);
}
public int size(){
int counter = 0;
for (Link curr = first; curr != null; curr = curr.getNext()){
counter = counter + 1;
}
return counter;
}
public boolean remove(Object element){
//השירה מסירה את החוליה הראשונה ברשימה המכילה את אלמנט
//יוחזר אמת אם"ם התבצעה הסרה
if (element == null)
throw new IllegalArgumentException();
Link prev = first, curr = first;
boolean removed = false;
while (curr != null & !removed){
if (currr.getData().equals(element)){
if (curr == first)
first = first.getNext();
else
prev.setNext(curr.getNext());
removed = true;
}
else {
prev = curr;
curr = curr.getNext();
}
return removed;
}
public String toString(){
String output = “”;
Link curr = first;
while (curr != null){
output = output + curr.toString() +” “;
curr = curr.getNext;
}
return output;
}
הרצאה 14
מבוא לתכנות מונחה עצמים – 3המחלקה ,Objectהורשה ,דריסה
המחלקה Objectמייצגת את הרעיון המופשט של "עצם" ,דבר מאוד מאוד כללי.
השיטה equalsבמחלקה Objectפועלת כמו האופרטור == .השוואה לוגית של Objectים היא בבחינת המקום בזכרון
ולא יותר זה.
;)(Object o1 = new Object
;)(Object o2 = new Object
o1 == o2; //false
;Object o3 = o2
o2 == o3; //true
S.op(o1.toString()); //java.lang.Object@2a139a55
;) // S.o.p(o1עובר קומפילציה ,ג'אווה תפעיל את השיטה toStringבעצמה
o1.equals(o2); //false
o2.equals(o3); // true
הרחבה/הורשה
כל מחלקה מרחיבה את המחלקה .Objectכל רעיון שנתאר הוא קודם כל עצם .ז"א ,כל רעיון הוא גם Objectבבסיסו,
ובנוסף לכל רעיון/מחלקה יש מאפיינים נוספים שייחדו אותה (וזה מה שמבדיל Doubleמ Integer-וכו').
כל מחלקה יורשת את השיטות של המחלקה .Object
מה שזה בעצם אומר ,זה שכשיוצרים מחלקה חדשה ,DynamicArrayיש לה "גרעין" שהוא בעצם Objectולכן עם
היווצרה היא מקבלת גם את השיטות toString ,equalsשיש ל Objectוניתן להפעיל אותן עליה גם ללא להגדיר אותן
כשיטות של המחלקה החדשה.
45
כלל הבצל
כשאנחנו מפעילים שיטה על מופע מסויים ,החיפוש אחריה מתחיל מבחוץ פנימה .כלומר ,ממחלקת הבן (המחלקה
המרחיבה) למחלקת האב .השיטה הראשונה שתמצא היא זו שתופעל.
דריסה
ניתן ליצור שיטה חדשה בעלת אותו השם ובעלת אותה חתימה (כפי שהיא מופיעה במחלקת האב) במחלקה
המרחיבה .כשנפעיל את השיטה בזמן ריצה ,השיטה שנמצאת במחלקה המרחיבה יותר היא זו שתופעל .כך בעצם
דורסים את השיטה שנמצאת במחלקת האב ומונעים את הפעלתה.
46
אם הגדרנו, כלומר. מתייחסת לאיך שהוגדר העצםreference , ההפניה. נקבע רק בזמן ריצהInstance typeה
. כדי שהקומפיילר יעביר את זהcasting נצטרך לבצע,String ונרצה לממש עליו שיטה שלObjectסטרינג חדש כ
.מחלקת האב יכולה להצביע על מחלקת הבן אך לא להפך
instanceof האופרטור
<var name> instanceof <type>
.type מצביע בפועל על מופע של המחלקהvarname אם בזמן ריצה המשתנהtrue זהו אופרטור בוליאני שיחזיר
.false אחרת יחזיר
.false תמיד יחזיר,null שיוגדר כערךvarname כל משתנה
.true יחזירו,Object מול הטיפוסinstanceof כשתופעל עליו השיטה,)null (שערכו אינוvarname כל משתנה
String s = new String (“Hello”);
Integer i = new Integer (3);
Object o = i;
S.o.p (s instanceof String); //true
s = null;
S.o.p (s instanceof String); //false
S.o.p (s instanceof Object); //false;
S.o.p (o instanceof Integer); //true
S.o.p (o instanceof String); //false
S.o.p (i instanceof Object); //true
47
:DynamicArray במחלקה
public boolean equals (Object other){
boolean isEqual = true;
if (!(other instanceof DynamicArray)){
isEqual = false;
}
else if (size() != ((DynamicArray)other).size()){
isEqual = false;
}
else {
for (int i=0; i<size() & isEqual ; i=i+1){
if (!get(i).equals(((DynamicArray)other).get(i)){
isEqual = false;
}
}
}
return isEqual;
}
//methods
public void add(Object element){
if (!(element instanceof Integer))
throw new IllegalArgumentException();
super.add(element);
}
public Object set(int index, Object element){
if (!(element instanceof Integer))
throw new IllegalArgumentException();
return super.set(index, element);
}
public int sum() {
int sum = 0;
for (int i = 0; i < size(); i = i + 1)
sum = sum + (Integer) get(i);
return sum;
}
}
48
2.12.18
הרצאה 15
מבוא לתכנות מובנה עצמים ,Generics – 4ממשקים
מערך דינאמי גנרי
נרצה להגדיר מחלקה של מערך דינאמי של טיפוס לא ידוע ,Tולתת למשתמש לקבוע מהו %בזמן ריצה.
כאשר אנחנו לא יודעים איזה טיפוסים אנו רוצים שה DynamicArray-יקבל ,במקום ליצור מחלקה של
,DynamicArrayניתן ליצור מחלקה של DynamicArrayמטיפוס Tכלשהו .בזמן אמת ,בזמן ריצה ,כאשר המחשב
יקבל מהמשתמש את הטיפוס ,Tהוא יפעיל את השיטות הרלוונטיות אליו.
כיוון שבחלק מהבנאים והשיטות לא נוכל להבטיח בוודאות שהמערך הדינאמי שלנו הוא מאותו טיפוס Tשהוגדר ,נציב
סימן שאלה ? במקום בו מצהירים על טיפוס המחלקה.
"?" ב JAVAמכונה ,wild cardהוא מתנהג כמו ג'וקר ולמעשה יכול להחליף כל דבר.
49
public class DynamicArray <T> implements List<T> { //הסבר על ליסט בהמשך
private Object[] data; //שדות – ללא שינוי מהמחלקה הדינאמית הרגילה
private int size;
נכתוב זאת. נכתוב מחלקה מרחיבה למחלקה מטיפוס ספציפי,אחרי יצירת מערך דינאמי שיכול לקבל כל טיפוס
public class DynamicIntegerArray extends DynamicArray<T>{..} :בצורה זו
ממשקים
.)ממשק הוא הגדרה של התנהגות בלבד (ולא מימוש
. ומאפשר לייצג רעיון מופשט ע"י טיפוס,ממשק מגדיר טיפוס ע"י אפיון תכונות
. משתמשים כדי לממש את הממשקimplements במילה. לממשקjava זאת מילה שמורה בinterface המילה
50
public class interface List <T>{
public int size(){…}
public void add(T element){…}
public void add(int index, T element
public T set (
public T get(int index){
:
:
}
}
//:במחלקה אחרת
List<Integer> myList = new DynamicArray<Integer>();
myList.add(32); //לא מתקמפל
myList.add(0,32); //עובר בשלוםם
:ברשימות
51
6.12.18
16 הרצאה
המשך ממשקים
הקבוצה תממש את, כלומר.) אין חזרות,נכיר ממשק נוסף המתאר את הרעיון המתמטי של קבוצה (אין חשיבות לסדר
.הממשק
52
public class SetAsDynamicArray <T> implements Set<T>{
//fields
private List<T> elements;
//constructors
public SetAsDynamicArray(){
elements = new DynamicArray<T>();
}
//methods
public int size(){
return elements size;
}
public boolean contains(T element){
return elements.contains(element);
}
public boolean isEmpty(){
return elements.isEmpty();
}
public boolean remove(T element){
return elements.remove(element);
}
public boolean add(T element){
if (element == null){
throw new IllegalArgumentException();
if (!contains(element)){
elements.add(element);
return true;
}
return false;
}
public Iterator <T> iterator(){
return element.iterator();
}
לצורך כך נגדיר שני רעיונות שעובדים.אנחנו צריכים להגדיר שיטה שמאפשר לעבור באופן סדרתי על מבנה הנתונים
. הרעיון שגורם למבנה הנתונים לאפשר "מעבר" עליו והרעיון של לולאה כעצם:ביחד
:שני הרעיונות האלו ייוצגו ע"י שני ממשקים מתאימים
. מייצג לולאה (מעבר יחיד חד פעמי) על איברי מבנה הנתוניםIterator<T> הממשק.1
public interface Iterator <T>{
public boolean hasNext();
public T next();
}
. יש למבנה זה איטראטור,משמע
53
public class DynamicArray <T> implements List<T>{
public Iterator<T> iterator(){
return new DynamicArrayIterator(this);
}
}
:sets במחלקה
public static <T> boolean subset (Set<T> setA, Set<T> setB)
boolean isSubset = true;
Iterator<T> iterA = setA.iterator();
while (iterA.hasNext() & isSubset){
isSubset = setB.contains(iterA.next());
}
}
54
13.12.18
17 הרצאה
המשך ממשקים
:דוגמה
List<String> guests = new SetAsDynamicArray<>();
List<String> guests = new SetAsLinkedList<>(); :או לחילופין אפשר לכתוב//
guests.add("super-man");
guests.add("spider-man");
Iterator<String> iter = guests.iterator();
while(iter.hasNext){ S.o.p(iter.next());}
55
איטראטור מספרי פיבונאצ'י
public class FibonacciIterator implements Iterator<Integer>{
private int maxValue;
private int prevValue; //האיבר האחרון שהוחזר
private int nextValue; //האיבר הבא שיוחזר
public FibonacciIterator (int maxValue){
this.maxValue = maxValue;
nextValue = 1;
nextValue = 0;
{
public Integer hasNext(){
return next value <= maxValue;
}
public Integer next(){
if (!hasNext())
throw new NoSuchElementException(); //צריך לייבא מג'אווה
Integer output = nextValue;
nextValue = nextValue + prevValue;
prevValue = output;
return output;
}
}
//main-ב
Iterator<Integer> fibIter = new FibbonaciIterator(100);
while (fibIter.hasNext()){
System.out.println(fibIter.next());
}
for-each לולאת
,)for-each( ניתן לבצע לולאה בכתיב מקוצרIterable<T> כאשר בידינו (עצם) מופע של מחלקה המממשת את
. שניתן לעבור עליו,iterable מאפשרת לנו לעשות את זה עבור כל עצם שהואJava .שלמה ללא תנאים
:נכתוב את זה כך
for (T element: iterableObject){
action with element;
}
56
מושג הסדר הטבעי
ועוד...,Integer, String, :מוג הסדר הטבעי קיים עבור מספר טיפוסים
:Comparable הרעיון הזה מיוצג ע"י הממשק
public static <T extends Comparable<T>> void insert insertionSort (T[] arr, int i){
T value = arr[i];
while (i>0 && arr[i-1].compareTo(value)>0){
arr[i] = arr[i-1];
i = i-1;
}
arr[i] = value;
}
comparator
.comparator – משתמשים בגורם חיצוני שמבצע השוואה,כאשר אין סדר טבעי
:הרעיון של משווה חיצוני מיוצג ע"י הממשק
57
public class Student{
private int id;
private String name;
:
:
}
מיון הכנסה
:השוואה-כעת נכתוב מיון הכנסה גם עבור טיפוסים שאינם בני
public static <T> void insertionSort (T[] arr, Comparator<T> comp){
for (int i=1; i<arr.length; i=i+1){
insert (arr,i)
}
}
public <T> void insert insertionSort (T[] arr, int i, Comparator<T> comp){
T value = arr[i];
while (i>0 && comp.compare(arr[i-],value)>0){
arr[i] = arr[i-1];
i = i-1;
}
arr[i] = value;
}
58
16.12.18
הרצאה 18
עצים בינאריים – Binary Trees
עצים בינאריים תומכים בפעולות הבאות בצורה יעילה:
הכנסה
הוצאה
חיפוש
מבנה העץ:
עץ בינארי הוא מבנה נתונים המייצג עץ מושרש המורכב מקודקודים/צמתים ()node
הקודקוד "העליון" בעץ הוא השורש
כל קודקוד מכיל נתון (מידע) מסוים
כל קדקוד מכיל בנוסף הפניות לשני בנים :בן ימני ובן שמאלי (הקודקוד יכול להכיל הפניה ליותר משני בנים ,אך אנחנו
מדברים על עצים בינארים)
מבנה העץ הוא רקורסיבי :כל קודקוד הוא שורש של תת-עץ כלשהו
לכל קודקוד יש לכל היותר אב אחד .רק לשורש אין אב.
59
BinaryNode & BinaryTree
המחלקה BinaryTreeמשמשת כמחלקה עוטפת למחלקה BinaryNodeשכן מבנה הנתונים הוא העץ עצמו,
והשיטות הציבוריות שלו הן ממשק המשתמש.
המשתמש לא מכיר את המחלקה .BinaryNode
הגדרות:
צומת Aהוא אב ( )parentשל צומת Bאם Bהוא בן ( )childשמאלי או בן ימני של .A .1
צומת Bהוא צאצא ( )successorשל צומת Aאם: .2
• ,B = A
• Bהוא בן (שמאלי או ימני) של ,A
• Bהוא צאצא של בן (שמאלי או ימני) של .A
צומת Aהוא אב קדמון ( )ancestor/predecessorשל צומת Bאם Bהוא צאצא של .A .3
תת העץ המושרש בצומת Aהוא תת הגרף המכיל את כל הצאצאים של .A .4
עומק של צומת הוא מספר הקשתות במסלול מהצומת אל שורש העץ (לכן עומק השורש הוא )0 .5
גובה של צומת שווה למספר הקשתות המקסימאלי במסלול מהצומת לעלה בתת העץ שלו (לכן גובה של .6
עלים הוא )0
גובה של עץ שווה לגובה של שורש העץ. .7
גודל של עץ שווה למספר הצמתים בעץ. .8
הכנסה Insert
הכנסת נתון לעץ תהיה שרירותית ,ללא חשיבות לתא בו הוכנס הנתון.
בהינתן איבר שאמור להתווסף לעץ:
בהסתברות ,1/2הכניסו את האיבר לתת העץ השמאלי ,ובהסתברות 1/2לתת העץ הימני -
הוספת איבר ,כמו פעולות רבות אחרות על עץ ,היא פעולה רקורסיבית -
60
סריקה של עצים
ישנן מספר דרכים לעבור באופן סדרתי על כל צמתי העץ:
inOrder .1
עוברת על איברי העץ בסדר ממויין מקטן לגדול
• מעבר על תת העץ השמאלי (אם קיים)
• מעבר על השורש
• מעבר על תת העץ הימני (אם קיים)
:preOrder .2שורש ,שמאל ,ימין
:postOrder .3שמאל ,ימין ,שורש
61
public class BinaryNode<T> {
protected T data;
protected BinaryNode<T> left;
protected BinaryNode<T> right;
if (isEmpty())}
root = new BinaryNode<>(element);
{
else}
root.insert(element);
}
{
public boolean contains(T element) {
if (isEmpty())
return false;
else
return root.contains(element);
}
public int height(){
if (isEmpty())
return -1;
else
return root.height();
}
public int size(){
if (isEmpty())
return 0;
else
return root.size();
}
public boolean equals (Object other) {
boolean isEqual = true;
if (!(other instanceof BinaryTree<?>))}
isEqual = false;
{
else if (isEmpty())}
isEqual = )(BinaryTree<?>)other).isEmpty();
{
else}
root.equals(((BinaryTree<?>)other).root);
}
return isEqual;
{
public void inOrder() {
if(!isEmpty())
root.inOrder();
}
{
63
20.12.18
הרצאה 19
עצי חיפוש בינאריים
הרעיון של עצי חיפוש בינאריים:
כל האיברים בתת העץ השמאלי קטנים מהאיבר בשורש ,וכל האיברים בתת העץ •
הימני גדולים מהאיבר בשורש
תנאים אלו מתקיימים גם ביחס לשורש העץ כולו ,וגם בכל אחד מתתי העצים של •
העץ.
*בקורס זה לא נאפשר כפילויות בעץ.
תחזוק של מבנה נתונים התומך בפעולות חיפוש ,הכנסה והוצאה הוא פעולה בסיסית ביותר.
בעץ בינארי נבצע log nפעולות(צעדים) כדי למצוא/לחפש/להכניס איבר מסויים.
המחלקה BinarySearchTreeלא מממשת את המחלקה comparableכדי שהיא לא תוגבל רק לטיפוסים
שמממשים את comparableבעצמם.
אם אכן רוצים לעשות חיפוש על עץ בינארי שמכיל עצמים שהם comparableמטבעם ,צריך לכתוב להם מחלקה
.comparator
**לטיפוסים שהם comparableיש את השיטה compareTo
**לטיפוסים שהם לא comparableצריך לכתוב comparatorשיכיל את השיטה compareשמקבלת כקלט שני
אובייקטים.
אם למשל מדובר בעץ של טיפוסים מסוג :Integer
{ >public class IntegerComparator implements Comparator<Integer
{)public int compare(Integer i1, Integer i2
{)if (i1 == null
;)(throw new NullPointerException
}
;)return i1.compareTo(i2
}
}
64
public class BinarySearchTree<T> extands BinaryTree<T>{
}
{
65
public class BinarySearchNode<T> extands BinaryNode<T>{
66
23.12.18
20 הרצאה
Queue תור,Stack מחסנית,Tree Iterator
Stack הממשק
הפעולה הראשונה שמתבטלת זוundo (כשעושיםword כמו למשל שמירת פעולות ב,ממשק שמוכר לנו כבר
.' מנגנון הקריאה לפונקציות וכו,)האחרונה שבוצעה
public interface Stack<T>{
//Returns true iff this stack is empty.
public boolean isEmpty();
//Removes the object at the top of this stack and returns that object.
public T pop();
StackAsDynamicArray המחלקה
public class StackAsDynamicArray<T> implements Stack<T> {
private DynamicArray<T> array ;
public StackAsDynamicArray() {
this.array = new DynamicArray<>() ;
}
public T pop() {
if (isEmpty)
throw new NoSuchElementException();
return array.remove(array.size()-1) ;
}
public T peek() {
if (isEmpty)
throw new NoSuchElementException();
return array.get(array.size()-1) ;
}
}
67
:stackדוגמה לשימוש ב
//a part of some main function
Stack<String> st = new StackAsDynamicArray();
st.push("man");
st.push("bites");
st.push("dog");
while(!st.isEmpty()) {
System.out.print(st.pop() + " ");
}
System.out.println();
// will print 'dog bites man'
איטראטורים על עצים
public class BinaryTree<T> implements Iterable<T>{
protected BinaryNode<T> root;
... //all the methods we've seen already
//Default method
public Iterator<T> inOrderIterator() {
return new BinaryTreeInOrderIterator<>(root);
}
//) אחכ הבנים משמאל לימין וכן הלאה,מעבר על העץ לפי רמות (קודם השורש
public Iterator<T> bfsIterator() {
return new BinaryTreeBFSIterator<>(root);
}
68
מימוש האיטראטורים
InOrder Iterator
public class BinaryTreeInOrderIterator<T> implements Iterator<T>{
private Stack<BinaryNode<T>> stack;
public BinaryTreeInOrderIterator(BinaryNode<T> root) {
stack = new StackAsDynamicArray<>();
prepareNext(root); //making sure the stack is legal
}
public T next() {
if(!hasNext())
throw new NoSuchElementException();
BinaryNode<T> node = stack.pop();
if (node.right != null)
prepareNext(node.right);
return node.data;
}
}
PreOrder Iterator
public class BinaryTreePreOrderIterator<T> implements Iterator<T>{
private Stack<BinaryNode<T>> stack;
public T next() {
if(!hasNext())
throw new NoSuchElementException();
BinaryNode<T> node = stack.pop();
if (node.right != null)
stack.push(node.right);
if (node.left != null)
stack.push(node.left);
return node.data;
}
}
69
BFS Itertator
public class BinaryTreeBFSIterator<T> implements Iterator<T>{
private Stack<BinaryNode<T>> q;
public T next() {
if(!hasNext())
throw new NoSuchElementException();
BinaryNode<T> node = q.dequeue();
if (node.left != null)
q.enqueue(node.left);
if (node.right != null)
q.enqueue(node.right);
return node.data;
}
}
– תורQueue הממשק
כמו למשל הקלדה במקלדת (האות הראשונה שתוקלד היא. הוא ממשק שכבר מוכר לנוQueue גם הממשק
.'הראשונה שתופיע במחשב) וכד
public interface Queue<T> {
//Returns true if this queue is empty.
public boolean isEmpty();
//Removes the object at the front of this queue and returns that object.
public T dequeue();
QueueAsLinkedList המחלקה
70
public class QueueAsLinkedList<T> implements Queue<T>{
private List<T> list;
public QueueAsLinkedList() {
list = new LinkedList<>();
}
public T peek() {
if(isEmpty())
throw new NoSuchElementException();
return list.get(0);
}
}
BFS Itertator
public class BinaryTreeBFSIterator<T> implements Iterator<T>{
private Stack<BinaryNode<T>> q;
public T next() {
if(!hasNext())
throw new NoSuchElementException();
BinaryNode<T> node = q.dequeue();
if (node.left != null)
q.enqueue(node.left);
if (node.right != null)
q.enqueue(node.right);
return node.data;
}
}
71
שוויון בין עצי חיפוש בינאריים
. מושג ההשוואה משתכלל,)כאשר מדובר בעצי חיפוש (המייצגים סדר
. מבנה העץ לא מעניין לבדיקת שוויון.שני עצים שווים כאשר הם מייצגים את אותו הסדר
:העצים הבאים שווים
}
if (isEqual)
isEqual = thisIter.hasNext() == otherIter.hasNext();
}
return isEqual;
}
72
27.12.18
הרצאה 21
שימוש במחסניות ,שערוך ביטוי בנוסח postfix
ביטויים בנוסח Postfix
ישנם שלושה נוסחים בהם מקובל להשתמש בכתיבת ביטוי מתמטי:
– Infix .1כאשר אופרטור הפעולה נכתב בין שני האופרנדים (למשל )1+2
– Prefix .2כאשר אופרטור הפעולה נכתב לפני האופרנד (למשל )sinx
– Postfix .3כאשר אופרטור הפעולה נכתב אחרי האופרנד (למשל !)n
Infixהוא הנוסח הנפוץ ביותר אבל עשוי להיות מסורבל לפענוח באופן ממוחשב כאשר מדובר בביטוי מסובך או ארוך,
לכן נרצה להמיר ביטויים בנוסח infixלביטויים בנוסח .postfix
ניתן לרשום כל ביטוי כעץ:
73
חישוב ערך של ביטוי בנוסח Postfix
מימוש ראשון
בהינתן ביטוי בצורת ,postfixיש לחשב את ערכו.
נייצג מספר כ integerואופרטור פעולה כ.string
נייצר קלט באופן הבאObject[] pfExpr = {5,2,3,4,"+",7,5,"+","*",11,"+","*","+",9,"*"} :
נכתוב פונקציה סטטית בשם evaluateהמחשבת את ערך הביטוי באמצעות מחסנית.
בכל פעם שנראה מספר ,נכניס אותו כאינטג'ר למחסנית .כשנפגוש מחרוזת (כלומר אופרטור) ,נשלוף מהמחסנית
את שני המספרים האחרונים שהכנסנו ,נפעיל עליהם את האופרטור ,ונחזיר את התוצאה למחסנית.
74
מימוש שני
.במימוש זה האופרטורים מבצעים את הפעולה
. מייצג עצם שיודע כיצד לפעול על מחסניתStackOperator הממשק
מבצע,) על המחסנית – מוציא ומכניס ערכיםapplied( האופרטור מופעל,postfix בהינתן מחסנית לחישוב ביטוי
.'חישובים וכו
. נמצאת בממשק רק כדי להזכיר למשתמש לדרוס אותהtoString **השיטה
//StackOperator הממשק
public Interface StackOperator{
public void apply(Stack<Integer> st);
public String toString();
}
//המחלקה המממשת
public class IntConstantOperator implements StackOperator{
//פעולת חיבור
public class IntPlusOperator implements StackOperator{
//פעולת כפל
public class IntMultOperator implements StackOperator{
75
//המחלקה המממשת
public class PostfixEvaluator2{
//אופרטור-השימוש בסטאק
public static int evaluate (StackOperator[] exp){
Stack<Integer> st = new StackAsDynamicArray<>();
for (StackOperator so: exp){
so.apply(st);
}
int ans = st.pop();
return ans;
}
מימוש שלישי
אח"כ מפעילים עליו את חלק הקוד שבנינו.StackOperator לוקחים את סטרינג הקלט והופכים אותו למערך של
.2 במימוש
public class ExpressionParser {
76
30.12.18
הרצאה 22
גרפים – Graphs
גרף בנוי מקבוצת קודקודים ( )Vertices/Nodesוקבוצת קשתות ( .)Edgesלגרף nקודקודים שממוספרים מ 0ועד n-1
ומיוצגים ע"י .Integer
קבוצת הקודקודים מסומנת באות Vוקבוצת הקשתות מסומנת ב .Eבקבוצת הקשתות קיימים זוגות סדורים .כל זוג
סדור מסמן קשר בין שני קודקודים.
הקשתות מציינות אם קיים קשר בין שני קודקודים true ,אם כן ו falseאם לא.
אחרי שיצרנו גרף לא ניתן להוסיף לו קודקודים נוספים.
אנחנו נתעסק בגרפים שאינם מכוונים (כלומר הקשתות אינן מכוונות ,כל קשת מייצגת קשר בשני הכיוונים) וחסרי
קשתות עצמיות (אין קודקוד המחובר לעצמו בקשת).
דוגמה:
}V = {0, 1, 2, 3
}>E = {<0,3>, <1,3>, <1,2>, <2,3
מושגים:
– degreeמספר הקשתות שיש לקודקוד.
degree(2) = 2
– neighborsקבוצת הקודקודים שמחוברים לקודקוד מסויים בקשת.
}neighborsOf(3) = {0,1,2
( Connectivityקשירות) – גרף יקרא ק שיר אם מכל קודקוד ניתן להגיע לכל הקודקודים האחרים
{ public interface Graph
; )(public int numberOfVertices
; )(public int numberOfEdges
; )public boolean containsEdge(int i, int j
; )public void addEdge(int i, int j
; )public void removeEdge(int i, int j
; )public int degree(int v
; )public Set<Integer> neighborsOf(int v
; )(public Set<Edge> edgeSet
}
ייצוג של קשתות
{ public class Edge
קודקוד שמאלי בזוגprotected int left ; //
קודקוד ימני בזוגprotected int right ; //
77
המשמעות היא לא שלא ניתן ליצור אינסטנס של.מחלקה אבסטרקטית היא מחלקה שמייצגת אובייקט מופשט
. לא ניתן לייצר אובייקטים מסוג המחלקה, זאת אומרת.new המחלקה באמצעות המילה
.)שיטה אבסטרקטית היא שיטה שתופיע במחלקת האב אך תמומש במחלקת הבת (בערך כמו ממשק
. גם המחלקה עצמה חייבת להיות אבסטרקטית,** אם במחלקה יש כמה שיטות אבסטרקטיות
public abstract class AbstractGraph implements Graph {
// fields
final private int nVertices ;
// constructors
public AbstractGraph(int nVertices) {
this.nVertices = nVertices ;
}
//methods
public int numberOfVertices(){
return nVertices;
}
78
:ייצוג גרף/שתי שיטות נפוצות למימוש
– סמוךadjacent**
– מטריצת שכנויותAdjacencyMatrix .1
. מסמן כי לא קיימת קשתF , מסמן כי קיימת קשתT .ייצוג במטריצה סימטרית
0 1 2 3
0 F F F T
1 F F T T
2 F T F T
3 T T T F
– רשימת שכנויותAdjacencyList .2
.ייצוג ברשימה שבה כל חוליה מפנה לרשימת השכנים שלה
// fields
private boolean[][] edges ;
// constructors
public GraphAsAdjacencyMatrix(int nVertices) {
super (nVertices);
edges = new boolean[nVertices][nVertices];
for (int i=0; i<nVertices; i=i+1)
for (int j=0; j<nVertices; j=j+1)
edges[i][j] = false;
}
//methods
public boolean containsEdge(int i, int j){
if (!rangeCheck(i,j){
throw new IllegalArguementException();
}
return edges[i][j]
}
79
GraphAlgorithm – אלגוריתמים הפועלים על גרפים
. המרכזת אלגוריתמים הפועלים על גרפים,GraphAlgorithm ,נגדיר מחלקה אבסטרקטית נוספת
public abstract GraphAlgorithm {
//field
protected Graph input;
//constructors
public GraphAlgorithm(Graph input){
this.input = input;
}
//methods
public abstract Object runAlgorithm();
80
3.1.18
23 הרצאה
המשך גרפים
בעיית קיום מעגל אוילר
. נרצה לדעת האם הגרף אוילריאני,בהינתן גרף
גרף נקרא אוילריאני אם קיים בו מעגל שעובר בכל קודקודיו ומשתמש בכל קשת:הגדרה
.Euler מעגל כזה נקרא מעגל.בדיוק פעם אחת
C = <0, 1, 2, 3, 1, 7, 4, 6, 5, 4, 0> :הגרף בדוגמה הוא אולריאני
:משפט
. גרףG יהי
. זוגיותG קשיר וגם כל דרגות קודקודיG קיים מעגל אוילר אם ורק אםG-ב
81
מציאת מעגל אוילר
נרצה למצוא אותו,אם בגרף קיים מעגל אוילר
public class FindEulerianAlgorithm extends GraphAlgorithm{
82
6.1.18
הרצאה 24
מיון רקורסיביmemoization ,
מיון מיזוגmerge-sort ,
סוג המיון היעיל ביותר הידוע עד היום ,זמן הריצה שלו n∙log n
אלגוריתם רקורסיבי שיש בו חישובים חוזרים של אותן תתי בעיות.
רעיון האלגוריתם – גישת "הפרד ומשול"
83
public static int[] sort (int[] arr){
if (arr == null)
throw new IllegalArgumentException();
if (arr.length < 2)
return arr;
return merge(sort(splitLeft(arr)), sort(splitRight(arr)));
/* מימוש חלופי
int[] arr1 = splitLeft(arr);
int[] arr2 = splitRight(arr);
arr1 = sort(arr1);
arr2 = sort(arr2);
return merge(arr1, arr2);
*/
}
84
memoization
. היא שיטה המאפשרת למנוע חישובים חוזרים של אותן תתי הבעיותMemoization
להפוך את, כלומר.שיטה זו יכולה "להפוך" אלגוריתם רקורסיבי אקספוננציאלי (מעריכי) לאלגוריתם פולינומי
.האלגוריתם ליעיל יותר
סדרת פיבונאצ'י
: נשכתב את האלגוריתם על מנת ליעל אותו.)10 נזכר באלגוריתם לחישוב סדרת פיבונאצ'י (הרצאה
public static int fib (int n){
int[] table = new int[n+1];
for(int i = 0; i < table.length; i = i+1){
table[i] = -1;
}
return fib (table, n);
}
return table[n][k];
{
85
10.1.19
25 הרצאה
memoization המשך
EditDistance – 1 בעיה
.Y- לX הוא המספר המינימלי של פעולות(מותרות) אשר הופכות אתd(X,Y) המרחק,X,Y בהינתן שתי מילים
:הפעולות המותרות הן
insertion הכנסת אות-
deletion מחיקת אות-
substitution החלפת אות-
:דוגמה
d("kitten","sitting")=3
רעיון הרקורסיה
: כךX,Y נסמן את המילים
86
דוגמת ריצה:
87
רעיון הרקורסיה
: אינטרווליםn בהינתן
0 התשובה היא,n==0 אם -
X- נסמן את האינטרוול האחרון ב,אחרת -
with - – נסמן אותו בX נבדוק את משך הזמן המקסימלי של שיבוץ חוקי שמכיל אתo
without - – נסמן אותו בX נבדוק את משך הזמן המקסימלי של שיבוץ חוקי שלא מכיל אתo
:*בדוגמה שלנו
with = length of 5 + MaxUse({1})
without = MaxUse({1,2,3,4})
?X כיצד נמצא בצורה יעילה את הקטעים שלא נחתכים עם
.נמיין את המקטעים לפי זמן הסיום שלהם ולמספרם לפי סדר המיון
ולעצור ברגע, X ומטה ולכל מקטע לבדוק האם הוא מתנגש עםX-1 -כעת ניתן לרוץ על כל המקטעים החל מ
.שמוצאים את המקטע הראשון שלא מתנגש
) האינטרוולים הראשונים במיון (השמאליים במערךi תכיל פתרון עבורtable[i] :n+1 בגודלtable נשתמש בטבלה
//assumes segments is sorted
public static int maxUse (Interval[] segments){
int[] table = new int[source.length()+1][target.length()+1];
for (int i = 0; i < table.length; i = i+1)
table[i] = 0;
return maxUse(table, segments, segments.length-1);
}
88