1. דף הבית
  2. קורסים אונליין
  3. קורס Javascript אונליין
  4. מבני נתונים בסיסיים: מערך, מחסנית ותור

מבני נתונים בסיסיים: מערך, מחסנית ותור

מערכים הם מבני נתונים בסיסיים בג'אווה סקריפט המאפשרים לאחסן ולתפעל אוספי נתונים. במדריך זה, נחקור את כל מה שצריך לדעת על מערכים, כולל התחביר שלהם, פעולות נפוצות, שיטות עבודה מומלצות וטיפים למניפולציה יעילה של מערכים.
מערכים ב-JS

מבוא למערכים בג'אווה סקריפט

מערכים הם מבני נתונים חיוניים ב-JavaScript המאפשרים לאחסן ולתפעל אוספי נתונים ביעילות. הם מספקים דרך נוחה לארגן ולגשת לערכים מרובים תחת שם משתנה יחיד.

שימוש במערכים בתכנות נדרש מכמה סיבות:

  • קיבוץ נתונים קשורים - מערכים מאפשרים לקבץ פריטי נתונים הקשורים יחד. לדוגמה, אם יש לך רשימה של פירות, תוכל לאחסן אותם במערך במקום במשתנים בודדים.
  • איטרציה על אלמנטים - מערכים מאפשרים איטרציה (מעבר סדרתי) על אלמנטים באמצעות לולאות או פונקציות שונות לטיפול במערכים. הדבר מאפשר לבצע פעולות על כל אלמנט במערך ביעילות.
  • אחסון דינמי - מערכים ב-JavaScript הם דינמיים, כלומר ניתן להוסיף או להסיר אלמנטים באופן דינמי. תכונה זו הופכת אותם למתאימים לתרחישים בהם מספר האלמנטים עשוי להשתנות לאורך זמן.
  • גישה יעילה - מערכים מספקים גישה בזמן קבוע (כלומר בסיבוכיות חישובית נמוכה) לאלמנטים באמצעות האינדקס שלהם. הדבר מאפשר אחזור מהיר של ערכים, דבר שהופך את פעולות המערך ליעילות ומהירות.

כל נתון במערך מכונה "איבר" או "אלמנט". איבר במערך יכול להיות מחרוזת, מספר או כל טיפוס או מבנה נתונים אחר.

דוגמה:

נניח תרחיש בו עלינו לאחסן את ציוני התלמידים בכיתה. ללא מערכים, נוכל להשתמש במשתנים בודדים עבור הציון של כל תלמיד, באופן הבא.

let score1 = 85;
let score2 = 90;
let score3 = 75;
// and so on...

עם זאת, ככל שמספר התלמידים גדל, ניהול משתנים בודדים הופך לבלתי מעשי ונוטה לשגיאות. במקום זאת, שימוש במערך לאחסון הציונים מפשט את הקוד והופך אותו ליעיל יותר. אחסון הציונים באמצעות מערך יראה באופן הבא.

let scores = [85, 90, 75, /* more scores */];

כאשר הציונים מאוחסנים במערך, ניתן לבצע איטרציה (מעבר סדרתי) על איברי המערך ולטפל בכל איבר בנפרד בקלות. כמו כן, ניתן בקלות לעשות מניפולציות על כלל הציונים, כגון חישוב ממוצע, מציאת החציון, מציאת הציון הגבוה ביותר, מיון הציונים ועוד.

הגדרת מערכים בג'אווה סקריפט

הגדרת מערכים נעשית באמצעות המחלקה (class) שנקרא Array (השיטה הישנה) או באמצעות סוגריים מרובעים (השיטה החדשה והמומלצת).

דוגמה:

// Old method
let fruits = new Array("Apple", "Banana", "Orange", "Mango");

// New method
let fruits = ["Apple", "Banana", "Orange", "Mango"];

בדוגמה זו, הגדרנו מערך בשם fruits הכולל 4 איברים מסוג מחרוזת. הגדרנו את המערך ב-2 צורות: באמצעות המחלקה Array ובאמצעות סוגריים מרובעים.

הצגנו את אופן ההגדרת עם Array על מנת שתכירו אותו כאשר אתם קוראים קוד JavaScript ישן, אבל המלצתנו היא להשתמש בהגדרה עם סוגריים מרובעים בלבד, שיטה חדשה ומומלצת יותר, אשר מייצרת קוד קריא יותר.

 

נוכל להגדיר מערכים מבלי לקבוע להם ערכים התחלתיים.

דוגמה:

// Define an empry array
let newArray = new Array();

// Define an array with the length of 5
let arrayWithLength = new Array(5);

בדוגמה זו, המערך newArray הוגדר להיות מערך ריק (נוכל בהמשך להוסיף לו איברים נוספים כמובן). המערך arrayWithLength הוגדר להיות מערך בן 5 איברים, אשר הערך הראשוני שלהם הוא undefined.

עבודה עם מערכים בג'אווה סקריפט

בהנתן מערך, נוכל לגשת לאיבר במקום ה-n שלו באמצעות שימוש בסוגריים מרובעים ובתוכם הספרה n. נשים לב שהאיברים במערך נספרים החל מהמקום 0 ולא מהמקום ה-1. המיקום במערך מכונה בשם אינדקס.

דוגמה:

let fruits = ["Apple", "Banana", "Orange", "Mango"];
console.log(fruits[0]); // Output: "Apple"
console.log(fruits[2]); // Output: "Orange"

בדוגמה זו, אנו מדפיסים בקונסול את ערך האיבר במקום ה-0 (המחרוזת Apple) ואת ערך האיבר במקום ה-2 (המחרוזת Orange).

 

מערכים בג'אווה סקריפט הם ברי-שינוי. נוכל לדוגמה לשנות איברים פנימיים במערך נתון.

דוגמה:

fruits[1] = "Grapes";
console.log(fruits); // Output: ["Apple", "Grapes", "Orange", "Mango"]

בדוגמה זו שינינו במערך fruits מהדוגמאות הקודמות את ערך האיבר במקום ה-1 (אנו רושמים במקום ה-1 ולא האיבר הראשון/השני, כדי למנוע בילבול וכדי שתמיד נזכור שהספירה של האיברים מתחילה מ-0 ולא מ-1). קבענו שהאיבר במקום ה-1 יהיה המחרוזת Grapes במקום המחרוזת Banana שהיתה קודם במיקום זה.

 

חשוב לשים לב לנקודה המבלבלת הבאה: אם מערך הוגדר כקבוע (const), אמנם לא ניתן לשנות את ערך הקבוע, אבל כן ניתן לשנות את האיברים במערך.

דוגמה:

const numbers = [1, 2, 3];

// Attempting to change an element of the constant array
numbers[0] = 4;

console.log(numbers); // Output: [4, 2, 3]

בדוגמה זו, אנו מכריזים תחילה על קבוע בשם numbers שהוא מערך המכיל שלושה איברים: [1,2,3]. לאחר מכן, אנו מנסים לשנות את האיבר במקום ה-0 של המערך על ידי הקצאת ערך חדש (המספר 4). באופן מפתיע, למרות ש-numbers הוכרז כקבוע באמצעות מילת המפתח const, השינוי מצליח, והמערך הופך ל-[4,2,3].

התנהגות זו עשויה להיראות מנוגדת לאינטואיציה, מכיוון שאנו מצפים שקבועים יהיו בלתי ניתנים לשינוי. עם זאת, ב-JavaScript, מילת המפתח const רק מונעת הקצאה מחדש של המשתנה עצמו, כלומר, לא ניתן לבצע השמה מחדש לקבוע numbers. עם זאת, את האיברים הפנימיים שבמערך כן ניתן לשנות.

 

התכונה length של המערך מחזירה את אורך המערך.

דוגמה:

let fruits = ["Apple", "Banana", "Orange", "Mango"];
console.log(fruits.length); // Output: 4

מימוש מחסנית ותור באמצעות מערך בג'אווה סקריפט

ניתן להוסיף איבר חדש למערך בתחילתו או בסופו, ולהסיר את האיבר הראשון או האחרון שלו.

push - מוסיפה איבר בסוף המערך.
pop - מסירה את האיבר האחרון מהמערך.
unshift - מוסיפה איבר בתחילת המערך.
shift - מסירה את האיבר הראשון במערך.

דוגמה:

let fruits = ["Apple", "Banana", "Orange", "Mango"];

// Adding elements to the end of an array
fruits.push("Kiwi");
console.log(fruits); // Output: ["Apple", "Banana", "Orange", "Mango", "Kiwi"]

// Removing the last element from an array
let lastFruit = fruits.pop();
console.log(lastFruit); // Output: "Kiwi"

// Adding elements to the beginning of an array
fruits.unshift("Pineapple");
console.log(fruits); // Output: ["Pineapple", "Apple", "Banana", "Orange", "Mango"]

// Removing the first element from an array
let firstFruit = fruits.shift();
console.log(firstFruit); // Output: "Pineapple"
console.log(fruits); // Output: ["Apple", "Banana", "Orange", "Mango"]

נשים לב שפעולות ההוספה וההסרה משנות את המערך עצמו. בעת הסרה (pop או shift), הערך המוסר מוחזר וניתן להכניסו למשתנה.

 

באמצעות שימוש במערכים וצמד הפונקציות pop ו-push, ניתן לממש מבנה נתונים מסוג "מחסנית", שבו האיבר האחרון שהוכנס הוא גם האיבר הראשון שיוצא. כלומר, שיטת LIFO (Last In First Out).

באופן דומה, ניתן לעשות שימוש בצמד הפונקציות shift ו-unshift למימוש "מחסנית הפוכה". הערכים מוכנסים ומוצאים בשיטה זו מתחילת המערך ולא מסופו, עדין בשיטת LIFO.

דוגמה:

// Initialize an empty stack
let stack = [];

// Push elements onto the stack (push operation)
stack.push("Apple");
stack.push("Banana");
stack.push("Orange");

console.log("Stack after push operations:", stack);

// Pop elements from the stack (pop operation)
let poppedElement1 = stack.pop();
let poppedElement2 = stack.pop();

console.log("Popped elements from the stack:", poppedElement1, poppedElement2);
console.log("Stack after pop operations:", stack);

בדוגמה זו, אנו מתחילים עם מערך ריק, שישמר לנו בתור מחסנית. לאחר מכן, אנו משתמשים בפעולת הדחיפה (push), כדי להוסיף אלמנטים: תחילה מוכנס Apple, לאחר מכן Banana ולסיום Orange. לבסוף, אנו משתמשים בפעולת המשיכה (pop), כדי להסיר אלמנטים מהמחסנית. האלמנטים מוסרים בסדר LIFO, כאשר האחרון שהוכנס הוא הראשון שיוצא: תחילה יוצא Orange, לאחר מכן Banana ולסיום Apple.

 

באמצעות שימוש במערכים וצמד הפונקציות push ו-shift, ניתן לממש מבנה נתונים מסוג "תור", שבו האיבר הראשון שהוכנס הוא גם האיבר הראשון שיוצא. כלומר, שיטת FIFO (First In First Out).

באופן דומה, ניתן לעשות שימוש בצמד הפונקציות unshift להכנסה ו-pop להוצאה למימוש "תור הפוך", שבו הערכים מוכנסים ומוצאים "מהצד השני" של התור (כלומר נשמרים בסדר הפוך במערך), אך זהו עדין תור העובד בשיטת FIFO.

דוגמה:

// Initialize an empty queue
let queue = [];

// Enqueue elements into the queue
queue.push("Apple");
queue.push("Banana");
queue.push("Orange");

console.log("Queue after enqueue operations:", queue);

// Dequeue elements from the queue
let dequeuedElement1 = queue.shift();
let dequeuedElement2 = queue.shift();

console.log("Dequeued elements from the queue:", dequeuedElement1, dequeuedElement2);
console.log("Queue after dequeue operations:", queue);

בדוגמה זו, אנו מתחילים עם מערך ריק, שישמש לנו בתור תור. לאחר מכן, אנו משתמשים בפעולת הדחיפה (push), כדי להוסיף אלמנטים: תחילה מוכנס Apple, לאחר מכן Banana ולסיום Orange. לבסוף, אנו משתמשים בפעולת המשיכה shift, כדי להסיר אלמנטים מהתור. האלמנטים מוסרים בתור בסדר FIFO, כאשר הראשון שהוכנס הוא גם הראשון שיצא: תחילה יוצא Apple, לאחר מכן Banana ולסיום Orange.

שימוש במערכים בג'אווה סקריפט

JavaScript מספק מגוון שיטות מובנות לעבודה עם מערכים. נראה כמה מהחשובות להלן.

slice - מחזירה מערך חלקי בין 2 אינדקסים נתונים.
splice - מסירה ערכים מהמערך ומחליפה אותם בערכים אחרים (המערך המקורי משתנה, והערכים שהוסרו מוחזרים).
concat - מחזירה מערך שכולל חיבור של המערך המקורי עם איברים של מערך נוסף.
indexOf - מציאת האינדקס (המיקום במערך) של איבר נתון.
includes - בודקת אם המערך כולל ערך נתון.
reverse - מחזירה מערך בסדר הפוך מהמערך המקורי.

דוגמאות:

// Extracting a portion of an array
let slicedFruits = fruits.slice(1, 3);
console.log(slicedFruits); // Output: ["Banana", "Orange"]

// Removing elements from an array and/or adding new elements
let removedFruits = fruits.splice(1, 2, "Grapes", "Watermelon");
console.log(removedFruits); // Output: ["Banana", "Orange"]
console.log(fruits); // Output: ["Apple", "Grapes", "Watermelon", "Mango"]

// Concatenating arrays
let moreFruits = ["Strawberry", "Peach"];
let allFruits = fruits.concat(moreFruits);
console.log(allFruits); // Output: ["Apple", "Grapes", "Watermelon", "Mango", "Strawberry", "Peach"]

// Finding the index of an element in an array
let indexOfWatermelon = fruits.indexOf("Watermelon");
console.log(indexOfWatermelon); // Output: 2

// Checking if an array includes a specific element
let includesMango = fruits.includes("Mango");
console.log(includesMango); // Output: true

// Reverse the order of elements in an array
let reversedFruits = fruits.reverse();
console.log(reversedFruits); // Output: ["Mango", "Orange", "Banana", "Apple"]

נשים לב שהפעלת הפונקציות השונות אינה משנה ממש את המערך עצמו (המערך המקורי אינו משתנה), אלא מחזירה מערך חדש מתוקן. זאת בניגוד לפונקציות שראינו קודם (push, pop, unshift, shift) אשר עובדות על המערך המקורי.

מערכים רב מימדיים

JavaScript מאפשר ליצור מערכים רב מימדיים, שהם מערכים המכילים יותר מרמת עומק אחת, כגון מערכים אחרים כאיברים. מערכים אלה יכולים לייצג מטריצות, טבלאות או כל נתון מובנה אחר.

דוגמה:

let matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

console.log(matrix[0]); // Output: [1, 2, 3]
console.log(matrix[0][1]); // Output: 2

בדוגמה זו יצרנו מערך בשם matrix. זהו מערך דו-מימדי, כלומר, שיש לו 2 מימדים. במימד הראשון, המערך כולל 3 איברים, שכל אחד מהם הוא בעצמו מערך. במימד השני, כל מערך פנימי הוא אוסף של 3 איברים מטיפוס מספרי.

הביטוי matrix[0] מחזיר את האיבר במקום ה-0 של המערך matrix, שהוא למעשה המערך [1,2,3]. הביטוי matrix[0][1] מחזיר את האיבר במקום ה-1 של האיבר במקום ה-0 של המערך matrix, כלומר, את האיבר במקום ה-1 של המערך [1,2,3], שהוא למעשה הערך המספרי 2.

 

כפי שיצרנו מערך דו מימדי, יכולנו ליצור מערך תלת מימדי או ארבע מימדי וכן הלאה.

דוגמה למערך תלת מימדי:

let threeDArray = [
    [ // First 2D array (slice)
        [1, 2, 3], // First row of the slice
        [4, 5, 6], // Second row of the slice
        [7, 8, 9]  // Third row of the slice
    ],
    [ // Second 2D array (slice)
        [10, 11, 12],
        [13, 14, 15],
        [16, 17, 18]
    ],
    [ // Third 2D array (slice)
        [19, 20, 21],
        [22, 23, 24],
        [25, 26, 27]
    ]
];

console.log(threeDArray);

איטרציות על מערכים

איטרציה משמעה מעבר סידרתי על איברי המערך איבר-איבר. איטרציות נועדו במטרה לאפשר טיפול קל ויעיל בכל איברי המערך בזה אחר זה.

הדרך הנפוצה ביותר לביצוע איטרציות על מערך היא באמצעות לולאת for.

דוגמה:

const colors = ['red', 'green', 'blue'];

for (let color of colors) {
    console.log(color);
}
// Output:
// red
// green
// blue

בדוגמה זו, עברנו על המערך colors בצורה סדרתית. לכל איבר במערך ביצענו את הקוד שבתוך הסוגריים המסולסלים של מבנה ה-for. מבנה ה-for מכונה "לולאה" וקטע הקוד בתוך הסוגריים המסולסלים מכונה "גוף הלולאה". אפשר לומר כי ביצענו 3 איטרציות של לולאת ה-for. המשתנה color שבגוף הלולאה משמש בכל איטרציה כמיצג של איבר אחר במערך colors שהגדרנו.

 

נוכל לבצע מעבר סידרתי גם על מערכים רב מימדיים. נדגים לולאה על מערך דו מימדי.

let matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

// Using nested loops to iterate over the elements of the multi-dimensional array
for (let i = 0; i < matrix.length; i++) {
    for (let j = 0; j < matrix[i].length; j++) {
        console.log("Element at index [" + i + "][" + j + "]:", matrix[i][j]);
    }
}

בדוגמה זו, לולאת ה-for הראשונה עוברת על כל איברי המערך matrix, החל מהאיבר במקום ה-0 ולאורך matrix.length איברים (כלומר עד האיבר שהאינדקס שלו קטן באחד מהאיבר במקום ה-matrix.length, כיוון שספירת האינדקסים מתחילה ב-0). המערך matrix הינו מערך דו מימדי, לכן, כל איבר במערך ה-matrix הוא מערך חד מימדי. לולאת ה-for הפנימית, עוברת בכל איטרציה של לולאת ה-for החיצונית על איברי המערך הפנימיים יותר, כאשר בכל איטרציה אחת של ה-for החיצוני, מבוצעות מספר איטרציות של ה-for הפנימי. באופן הזה, אנו סורקים לעומק את כל האיברים של המערך הרב מימדי matrix. גוף הלולאה הפנימית מדפיס על המסך את האיבר הנסרק.

בפרקים הבאים נסביר לעומק את נושא הלולאות, נכיר לולאות מסוגים שונים ונדגים שיטות שונות לביצוע איטרציות באמצעות לולאות או פונקציות ייעודיות.

טיפים ושיטות עבודה מומלצות לעבודה עם מערכים

להלן כמה טיפים שיעזרו לכם לעבוד יעיל יותר עם מערכים.

  • השתמש בשמות משתנים תיאוריים - בחר שמות משמעותיים עבור המערכים שלך, כדי לשפר את קריאות הקוד.
  • הימנע משינוי ישיר של מערכים - שקול להשתמש בשיטות מערך המחזירות מערכים חדשים במקום לבצע מוטציה של המערך המקורי.
  • שים לב לערכי ההחזרה - חלק משיטות המערך משנות את המערך המקורי, בעוד שאחרות מחזירות מערכים או ערכים חדשים. הבן את ההתנהגות של כל שיטה, כדי למנוע תוצאות בלתי צפויות.
הוספת תגובה
אנו משתמשים בעוגיות על מנת לשפר את חווית המשתמש באתר. מדיניות הפרטיותאני מסכים