هياكل البيانات في جافا: المنظم السري للبيانات! 🗂️

مرحباً بك في عالم هياكل البيانات في جافا! تخيل أن لديك مجموعة من الكتب. يمكنك وضعها في كومة عشوائية، أو ترتيبها على رف، أو وضعها في حقيبة. كل طريقة لها مزاياها: الكومة سريعة للإضافة، الرف مرتب وسهل البحث، والحقيبة سهلة الحمل. هياكل البيانات في البرمجة هي تلك الطرق المختلفة لتنظيم وتخزين البيانات في ذاكرة الحاسوب، بحيث يمكن الوصول إليها وتعديلها بكفاءة. في هذا الدرس، سنتعرف على أهم الهياكل الأساسية التي تقدمها لغة جافا.


لماذا نستخدم هياكل البيانات؟ 🤔

بدون هياكل منظمة، ستكون بياناتنا عبارة عن متغيرات مفردة ومبعثرة. تخيل أنك تريد تخزين أسماء 100 طالب. هل ستنشئ 100 متغير مثل student1, student2...؟ هذا غير عملي أبداً! هنا يأتي دور هياكل البيانات لتقدم لنا حلاً ذكياً:

  • التنظيم: تجميع البيانات ذات الصلة معاً.
  • الكفاءة: عمليات البحث والإضافة والحذف تكون أسرع.
  • إعادة الاستخدام: هياكل جاهزة وموثوقة من خلال "إطار عمل المجموعات" (Collections Framework) في جافا.

إطار عمل المجموعات (Collections Framework) 📦

جافا تقدم مكتبة قوية تسمى Collections Framework تحتوي على واجهات (Interfaces) وتصنيفات (Classes) جاهزة لتنفيذ هياكل البيانات الأكثر شيوعاً. هذا يعني أنك لست مضطراً لبرمجة هذه الهياكل من الصفر، بل تستخدمها مباشرة. سنركز اليوم على أربعة أنواع رئيسية.


1. المصفوفات (Arrays) – البنية الأساسية

المصفوفة هي أبسط هيكل بيانات. تخيلها كصف من الصناديق المرقمة، كل صندوق يحتفظ بقيمة.

  • حجم ثابت: عند إنشائها، يجب تحديد عدد الصناديق (الحجم) ولا يمكن تغييره لاحقاً.
  • فهرس رقمي: نصل للبيانات باستخدام رقم الفهرس، يبدأ من الصفر.

مثال واقعي: تخزين درجات 5 طلاب.

// إنشاء مصفوفة من الأعداد الصحيحة لحفظ الدرجات
int[] grades = new int[5];

// تعبئة المصفوفة
grades[0] = 95; // الدرجة الأولى في الصندوق رقم 0
grades[1] = 87;
grades[2] = 72;
grades[3] = 90;
grades[4] = 88;

// الوصول لعنصر
System.out.println("The third student's grade: " + grades[2]); // prints: 72

2. القوائم (Lists) – المصفوفات الذكية والمتغيرة

القوائم تشبه المصفوفات، لكنها ذكية ومرنة! أشهر أنواعها ArrayList.

  • حجم ديناميكي: تكبر وتصغر تلقائياً عند إضافة أو حذف عناصر.
  • تحتفظ بترتيب الإضافة: العنصر الأول يضاف في الموضع 0، ثم 1، وهكذا.
  • تسمح بالتكرار: يمكن أن تحتوي على نفس القيمة أكثر من مرة.

مثال واقعي: قائمة تسوق يمكن إضافة عناصر لها في أي وقت.

// استدعاء المكتبة اللازمة أولاً
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // إنشاء قائمة من النصوص (أسماء العناصر)
        ArrayList<String> shoppingList = new ArrayList<>();

        // إضافة عناصر - ستزيد القائمة حجمها تلقائياً
        shoppingList.add("تفاح");
        shoppingList.add("خبز");
        shoppingList.add("حليب");
        shoppingList.add("تفاح"); // مسموح بالتكرار!

        // الحصول على عنصر
        System.out.println("أول عنصر في القائمة: " + shoppingList.get(0));

        // معرفة حجم القائمة
        System.out.println("عدد العناصر: " + shoppingList.size()); // ستطبع: 4

        // إزالة عنصر
        shoppingList.remove("خبز");
        System.out.println("عدد العناصر بعد الإزالة: " + shoppingList.size()); // ستطبع: 3
    }
}

3. المجموعات (Sets) – للتخزين الفريد

المجموعة (Set) هي كيس لا يرتب عناصره، والأهم من ذلك، لا يسمح بالتكرار. إذا حاولت إضافة عنصر موجود مسبقاً، فلن يضيفه. أشهر نوع هو HashSet.

  • لا تسمح بالتكرار: كل عنصر فريد.
  • لا تحفظ ترتيباً معيناً للإضافة.

مثال واقعي: مجموعة أرقام الهواتف المسجلة في مسابقة (لا يمكن أن يتسجل نفس الرقم مرتين).

import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet<String> phoneNumbers = new HashSet<>();

        phoneNumbers.add("0501111111");
        phoneNumbers.add("0502222222");
        phoneNumbers.add("0501111111"); // هذا الرقم موجود مسبقاً، لن يتم إضافته!

        System.out.println("الأرقام الفريدة: " + phoneNumbers);
        // قد يطبع: [0502222222, 0501111111] (لا ترتيب محدد)
    }
}

4. الخرائط (Maps) – التخزين بالمفتاح والقيمة

الخريطة (Map) هي هيكل فريد يخزن البيانات على شكل أزواج: مفتاح وقيمة. مثل القاموس: الكلمة هي "المفتاح" والمعنى هو "القيمة". نستخدم المفتاح للوصول للقيمة مباشرة وبسرعة. أشهر نوع هو HashMap.

  • المفاتيح فريدة: لا يمكن تكرار المفتاح نفسه.
  • الوصول سريع: إعطني المفتاح، أعطيك القيمة مباشرة.

مثال واقعي: تخزين رواتب الموظفين (رقم الموظف هو المفتاح، الراتب هو القيمة).

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        // الخريطة: المفتاح Integer (رقم الموظف), القيمة Double (الراتب)
        HashMap<Integer, Double> employeeSalaries = new HashMap<>();

        // إضافة البيانات
        employeeSalaries.put(101, 5000.0); // الموظف رقم 101 راتبه 5000
        employeeSalaries.put(102, 6200.5);
        employeeSalaries.put(103, 4800.75);

        // الحصول على راتب موظف باستخدام رقمه (المفتاح)
        double salary = employeeSalaries.get(102);
        System.out.println("راتب الموظف 102: " + salary); // ستطبع: 6200.5

        // تجديد راتب موظف
        employeeSalaries.put(101, 5500.0); // نستخدم نفس المفتاح لتحديث القيمة
    }
}

ملخص سريع: أيهما تختار؟ 🎯

  • Array: عندما تعرف عدد العناصر مسبقاً ولن يتغير.
  • ArrayList: عندما تحتاج قائمة مرتبة، قد تكبر أو تصغر، وتسمح بالتكرار. (الأكثر استخداماً).
  • HashSet: عندما تريد ضمان أن جميع العناصر فريدة ولا يهمك ترتيبها.
  • HashMap: عندما تريد ربط بيانات ببعضها (مفتاح/قيمة) والوصول السريع عبر المفتاح.