מבוא למדעי המחשב הממשקים Iterable,Set ו- Iterator
תוכן עניינים מבנה נתונים
מבנה נתונים מבנה נתונים הוא container של עצמים שמוגדרות עליו מספר פעולות למשל קבוצה של עצמים (אוסף ללא חזרות) עם הפעולות: הוספת איבר לקבוצה, מחיקת איבר מהקבוצה, חיפוש איבר בקבוצה, בדיקה האם הקבוצה ריקה או לא ומה הגודל שלה וכדומה את הפעולות נהוג להגדיר באמצעות ממשק ולממש את הממשק באמצעות מחלקה (אחת או יותר) כדי שאפשר יהיה ליצור אובייקט שישמש container לעצמים עם הפעולות הרצויות
תוכן עניינים מבנה נתונים הממשק קבוצה (Set)
הממשק Set public interface Set<T> { int size(); boolean isempty(); boolean add(t element); boolean contains(t element); boolean remove(t element);
מימוש Set באמצעות מערך דינאמי public class SetAsDynamicArray<T> implements Set<T> { private DynamicArray<T> elements; Type Inference public SetAsDynamicArray() { elements = new DynamicArray<>(); public int size() { return elements.size(); public boolean isempty() { return elements.isempty(); public boolean add(t element) { boolean ans = false; if (!contains(element)) { elements.add(element); ans = true; return ans; public boolean contains(t element) { return elements.contains(element); public boolean remove(t element) { return elements.remove(element); public String tostring() { return elements.tostring();
שימוש public static void main(string[] args) { Set<Integer> integerset1 = new SetAsDynamicArray<>(); integerset1.add(1); integerset1.add(1); integerset1.add(2); System.out.println(integerSet1); // {1, 2 Set<Integer> integerset2 = new SetAsDynamicArray<>(); integerset2.add(2); integerset2.add(3); integerset2.add(2); System.out.println(integerSet2); // {2, 3
תוכן עניינים מבנה נתונים הממשק Iterator
איטרציה הצורך לעבור על קבוצה של איברים (איטרציה על האיברים) הוא צורך מוכר ואוניברסלי למשל על האיברים של קבוצת נתונים מסוג,Set כדי להוסיף למחלקה SetAsDynamicArray בנאי מעתיק שמקבל כפרמטר אובייקט מסוג Set (לאו דווקא מסוג,(SetAsDynamicArray או כדי להוסיף למחלקה שיטה שמבצעת איחוד (union) של this עם עצם מסוג Set (לאו דווקא מסוג (SetAsDynamicArray מתבקש פתרון סטנדרטי להבדיל ממערך בו לכל איבר יש אינדקס ואפשר בלולאה על האינדקס לעבור על כל איברי המערך במקרה הכללי אין פתרון דומה בשפה עצמה הפתרון ש- Java מציעה הוא בעזרת שני ממשקים Iterator Iterable
איטרציה למה ממשקים? הממשקים מבטאים תבנית של פעולה (ללא מימוש) המימוש שלהם יכול להיעשות בדרכים שונות (בהתאם לנסיבות) מימוש יחיד יכול לשמש מבני נתונים שונים (בהתאם לדמיון ביניהן) שימוש בממשקים מאפשר לכתוב קטעי קוד אבסטרקטיים
הממשק Iterator מגדיר צורה סטנדרטית לעבור על קבוצה של נתונים public interface Iterator<T> { boolean hasnext(); T next();
למספרים Iterator טבעיים public class NaturalNumbersIterator implements Iterator<Integer> { private int nextnumber, maxnumber; public NaturalNumbersIterator(int maxnumber) { nextnumber = 1; this.maxnumber = maxnumber; public boolean hasnext() { return nextnumber <= maxnumber; public Integer next() { if (!hasnext()) throw new NoSuchElementException(); int output = nextnumber; nextnumber = nextnumber + 1; return output; public static void main(string[] args) { Iterator<Integer> iter = new NaturalNumberIterator(100); while (iter.hasnext()) System.out.println(iter.next());
למספרי Iterator פיבונצ'י public class FibonacciIterator implements Iterator<Integer> { private int currentvalue, nextvalue, maxvalue; public FibonacciIterator(int maxvalue) { currentvalue = 1; nextvalue = 1; this.maxvalue = maxvalue; public boolean hasnext() { return currentvalue <= maxvalue; public Integer next() { if (!hasnext()) throw new NoSuchElementException(); int result = currentvalue; currentvalue = nextvalue; nextvalue = nextvalue + result; return result; public static void main(string[] args) { Iterator<Integer> iter = new FibonacciIterator(100); while (iter.hasnext()) System.out.println(iter.next());
Iterator למערכים public class ArrayIterator<T> implements Iterator<T> { private T[] array; private int size; private int index; public ArrayIterator(T[] array, int size) { this.array = array; this.size = size; index = 0; public boolean hasnext() { return index < size; public T next() { if (!hasnext()) throw new NoSuchElementException(); index = index + 1; return array[index - 1];
Iterator לרשימות מקושרות public class LinkedListIterator<T> implements Iterator<T> { private Link<T> first; public LinkedListIterator(Link<T> first) { this.first = first; public boolean hasnext() { return first!= null; public T next() { if (!hasnext()) throw new NoSuchElementException(); T data = first.getdata(); first = first.getnext(); return data;
תוכן עניינים מבנה נתונים הממשק Iterator הממשק Iterable
public interface Iterable<T> { Iterator<T> iterator(); הממשק Iterable עכשיו שיש בידנו שיטה סטנדרטית לעבור על קבוצה של נתונים, נחזור למבנה הנתונים set ונגדיר אותו בעזרת הממשק השני כ- Iterable המשמעות: מבנה הנתונים יודע לתת Iterator שאותחל באברים של מבנה הנתונים למשל, SetAsDynamicArray יחזיר אובייקט מסוג ArrayIterator מאותחל במערך של איברי הקבוצה ו- SetAsLinkedList יחזיר אובייקט מסוג LinkedListIterator שמאותחל ברשימה המקושרת של איברי הקבוצה Iterable Iterator boolean hasnext() T next() Program Iterator<T> iterator().1 מבקשת Iterator 3. פועלת על ה- Iterator
הממשק Iterable כל Iterator מאפשר מעבר יחיד על האיברים Iterable Iterator boolean hasnext() T next() Program Iterator<T> iterator().1 מבקשת Iterator 3. פועלת על ה- Iterator
Iterator למה שה- Iterable לא יהיה בעצמו? Iterable מאפשר מימוש מחוץ למחלקה למשל, לכל מבני הנתונים שמשתמשים במערך מספיק לממש Iterator אחד מאפשר לתוכנית לבקש בו-זמנית מספר Iterator -ים מאותו אובייקט חשוב בתוכניות עם מקביליות (אבל - לא רק) Iterator boolean hasnext() T next() Program Iterator<T> iterator().1 מבקשת Iterator 3. פועלת על ה- Iterator
התמונה הסופית public interface Iterable<T> { Iterator<T> iterator(); Iterable Iterator boolean hasnext() T next() Program Iterator<T> iterator().1 מבקשת Iterator 3. פועלת על ה- Iterator
תוכן עניינים מבנה נתונים הממשק Iterator הממשק Iterable הוספת Iterable לממשק List
הוספת Iterable לממשק List public interface List<T> extends Iterable<T> { int size(); boolean isempty(); void add(t element); void insert(int index, T element); T set(int index, T element); T get(int index); boolean remove(t element); boolean contains(t element); הוספה לממשק מחייבת כל מחלקה שמממשת את הממשק
השינוי הנדרש מ- DynamicArray List היא DynamicArray מכוון ש- public Iterator<T> iterator() { return new ArrayIterator<>(data, size); Type Inference
השינוי הנדרש מ- LinkedList List היא LinkedList מכוון ש- public Iterator<T> iterator() { return new LinkedListIterator<>(first); Type Inference
שימוש public static void main(string[] args) { List<String> daguests = new DynamicArray<>(); daguests.add("hellokitty"); daguests.add("taz"); Iterator<String> daiterator = daguests.iterator(); while (daiterator.hasnext()) System.out.println(daIterator.next()); List<String> llguests = new LinkedList<>(); llguests.add("hellokitty"); llguests.add("taz"); Iterator<String> lliterator = llguests.iterator(); while (lliterator.hasnext()) System.out.println(llIterator.next());
List<String> daguests = new DynamicArray<>(); List<String> llguests = new LinkedList<>(); שימוש daguests List llguests List DynamicArray data size Object[] int 2 LinkedList first Link
daguests.add("hellokitty"); daguests.add("taz"); llguests.add("hellokitty"); llguests.add("taz"); שימוש daguests List llguests List DynamicArray data size Object[] int 2 LinkedList first Link "HelloKitty" Taz" "HelloKitty" Taz"
Iterator<String> daiterator = daguests.iterator(); שימוש daguests List DynamicArrayIterator index size int int 0 2 array DynamicArray DynamicArray data size Object[] int 2 "HelloKitty" Taz"
while (daiterator.hasnext()) System.out.println(daIterator.next()); HelloKitty שימוש daguests List DynamicArrayIterator index size int int 1 2 array DynamicArray DynamicArray data size Object[] int 2 "HelloKitty" Taz"
while (daiterator.hasnext()) System.out.println(daIterator.next()); HelloKitty Taz שימוש daguests List DynamicArrayIterator index size int int 2 2 array DynamicArray DynamicArray data size Object[] int 2 "HelloKitty" Taz"
Iterator<String> lliterator = llguests.iterator(); שימוש llguests List LinkedListIterator current Link LinkedList first Link "HelloKitty" Taz"
while (lliterator.hasnext()) System.out.println(llIterator.next()); HelloKitty שימוש llguests List LinkedListIterator current Link LinkedList first Link "HelloKitty" Taz"
while (lliterator.hasnext()) System.out.println(llIterator.next()); HelloKitty Taz שימוש llguests List LinkedListIterator current Link LinkedList first Link "HelloKitty" Taz"
תוכן עניינים מבנה נתונים הממשק Iterator הממשק Iterable הוספת Iterable לממשק List הוספת Iterable לממשק Set
הוספת Iterable לממשק Set public interface Set<T> extends Iterable<T> { int size(); boolean isempty(); boolean add(t element); boolean contains(t element); boolean remove(t element);
השינוי הנדרש מ- SetAsDynamicArray Set הוא SetAsDynamicArray מכוון ש- public Iterator<T> iterator() { return elements.iterator();?setaslinkedlist מה עם
תוכן עניינים (אובייקטים מסוג (Set מבנה נתונים הממשק Iterator הממשק Iterable הוספת Iterable לממשק List הוספת Iterable לממשק Set מחלקה של פונקציות סטטיות לקבוצות
(AA BB) הפונקציה IsSubset Generic Method public class Sets { public static <T> boolean issubset(set<t> seta, Set<T> setb) { boolean issubset = true; Iterator<T> iterb = setb.iterator(); while (iterb.hasnext() && issubset) issubset = seta.contains(iterb.next()); return issubset;
(AA BB) הפונקציה union public class Sets { public static <T> Set<T> union(set<t> seta, Set<T> setb) { Set<T> union = new SetAsDynamicArray<>(); Iterator<T> iterseta = seta.iterator(); Iterator<T> itersetb = setb.iterator(); while (iterseta.hasnext()) union.add(iterseta.next()); while (itersetb.hasnext()) union.add(itersetb.next()); return union;
(AA BB) הפונקציה union public class Sets { public static <T> Set<T> union1(set<t> seta, Set<T> setb) { Set<T> union = new SetAsDynamicArray<>(); for (T element : seta) union.add(element); for (T element : setb) union.add(element); return union; כל מה ש- Iterable
(AA BB) הפונקציה intersection public class Sets { public static <T> Set<T> intersection(set<t> seta, Set<T> setb) { Set<T> intersection = new SetAsDynamicArray<>(); for(t element : seta) if (setb.contains(element)) intersection.add(element); return intersection;
שימוש public static void main(string[] args) { Set<Integer> integerset1 = new SetAsDynamicArray<>(); integerset1.add(1); integerset1.add(1); integerset1.add(2); System.out.println(integerSet1); // {1, 2 Set<Integer> integerset2 = new SetAsDynamicArray<>(); integerset2.add(2); integerset2.add(3); integerset2.add(2); System.out.println(integerSet2); // {2, 3 System.out.println (Sets.<Integer>union(integerSet1, integerset2)); // {1, 2, 3