المصفوفات الثابتة


المصفوفة هي تركيبة من البيانات يتم إنشائها بشكل برمجي في الحاسوب، يمكنها تخزين العديد من العناصر من نفس النوع و كل عنصر يحمل قيمة، يتم حجز مساحة من الذاكرة لتحمل قيمة و مكان كل عنصر بشكل متسلسل، المصفوفة لها سعة ثابتة و لا تتغير خلال وقت التنفيذ لهذا يجب تحديد سعة المصفوفة خلال وقت البرمجة.

- عناصر المصفوفة تتميز عن بعضها من خلال رقم محدد يعطى لكل عنصر يسمى فهرس أو دليل (index). أول عنصر في المصفوفة دائماً يكون دليله 0.
- عند تعريف مصفوفة، يتم حجز المساحة المناسبة من الذاكرة لتخزين عناصر المصفوفة، ولا يتم وضع قيم إفتراضية لعناصر المصفوفة، فإذا قمت بطباعة عناصر المصفوفة بعد عملية الإعلان مباشرة سوف تظهر لك نتائج عشوائية لقيم كانت موجودة مسبقاً في الذاكرة قبل تنفيذ البرنامج.

يتم تعريف المصفوفة في لغة الأسس بالصيغة التالية:

عرف اسم_المصفوفة: مصفوفة[صـنف_البيانات، حجم]؛
def array_name : array[DataType, size];
حيث أن:
  • عرف (def): كلمة محجوزة تستخدم لتعريف المتغيرات.
  • اسم_المصفوفة (array_name): اسم المتغير الذي سيمثل المصفوفة.
  • مصفوفة (array): كلمة محجوزة تمثل هذا الصنف من البيانات.
  • صـنف_البيانات (DataType): تمثل صنف بيانات عناصر المصفوفة.
  • حجم (size): يمثل عدد عناصر هذه المصفوفة.

للوصول إلى عنصر من المصفوفة نضع اسم المصفوفة ودليل العنصر المطلوب بين قوسين هلاليين، ولاننسى أن فهرس المصفوفات يبدأ من الصفر:

مصفوفتي(تسلسل_العنصر)؛
myArray(element_index)

إسناد قيمة لعنصر:

مصفوفتي(تسلسل) = قيمة
myArray(index) = value

لطباعة عنصر من المصفوفة نتبع نفس طرق الطباعة التي تحدثنا عنها سابقاً، فمثلاً لطباعة محتوى العنصر ذو الدليل 0 وبفرض أن عناصر هذه المصفوفة من الصنف int:

مـتم.طـرفية.اطبع("قيمة أول عنصر من المصفوفة هو: %d"، مصفوفتي(0))؛
Srl.Console.print("The value of the first element is: %d",myArray(0));

بينما لو كانت عناصر المصفوفة من الصنف char:

  مـتم.طـرفية.اطبع("قيمة أول عنصر من المصفوفة هو: %c"، مصفوفتي(0))؛
Srl.Console.print("The value of the first element is: %c",myArray(0));

وهكذا..

المثال الأول

تعريف مصفوفة تحوي 3 عناصر من الأعداد الصحيحية ثم طباعتها.

اشمل "مـتم/طـرفية"؛
استخدم مـتم؛
// تعريف مصفوفة من الأعداد الصحيحية تحوي 3 عناصر
عرف مصفوفتي: مصفوفة[صحيح، 3]؛
مصفوفتي(0) = 14؛ // إسناد القيمة 14 للعنصر الأول
مصفوفتي(1) = 57؛
مصفوفتي(2) = 90؛
// حلقة تقوم بالمرور على عناصر المصفوفة وطباعتها
عرف ع: صحيح؛
لكل ع = 0، ع < 3، ++ع {
  طـرفية.اطبع("قيمة العنصر %d هي: %d\ج"، ع، مصفوفتي(ع))؛
}

/*
قيمة العنصر 0 من المصفوفة هي: 14
قيمة العنصر 1 من المصفوفة هي: 57
قيمة العنصر 2 من المصفوفة هي: 90
*/
import "Srl/Console.alusus";
use Srl;
// تعريف مصفوفة من الأعداد الصحيحية تحوي 3 عناصر
def myArray: array[Int,3];
myArray(0) = 14; // إسناد القيمة 14 للعنصر الأول
myArray(1) = 57;
myArray(2) = 90;
// حلقة تقوم بالمرور على عناصر المصفوفة وطباعتها
def index: Int;
for index=0, index<3, index++ {
  Console.print("The value of element %d is: %d\n", index, myArray(index));
}

/*
The value of element 0 is: 14
The value of element 1 is: 57
The value of element 2 is: 90
*/

المثال الثاني

حساب متوسط ومجموع 4 أعداد صحيحة مدخلة.

اشمل "مـتم.طـرفية"؛
استخدم مـتم.طـرفية؛
عرف مصفوفتي: مصفوفة[صحيح، 4]؛ // تعريف مصفوفة من الأعداد الصحيحية تحوي 4 عناصر
عرف معدل: عائم[64]؛ // متغير من الصنف عائم لتخزين المتوسط
عرف مجموع: صحيح[64] = 0؛ // متغير لحساب المجموع من الصنف صحيح
عرف ع: صحيح[64]؛ // عنصر التحكم بالحلقة
// تعريف حلقة وإدخال القيم
لكل ع = 0، ع < 4، ++ع {
  اطبع("أدخل العدد %d \ج"، (ع + 1))؛
  مصفوفتي(ع) = أدخل_صحيح()؛
}
// حساب المجموع
لكل ع = 0، ع < 4، ++ع {
  مجموع = مجموع + مصفوفتي(ع)؛
}
معدل = مجموع ÷ 4.0؛ // حساب المتوسط
اطبع("مجموع الأعداد المدخلة هو: %d\ج"، مجموع)؛ // طباعة المجموع
اطبع("معدل الأعداد المدخلة هو: %0.01f \ج"، معدل)؛ // طباعة المعدل

/*
أدخل العدد 1
3
أدخل العدد 2
2
أدخل العدد 3
3
أدخل العدد 4
2
مجمموع الأعداد المدخلة هو: 10
معدل الأعداد المدخلة هو: 2.50
*/
import "Srl/Console.alusus";
use Srl.Console;
def myArray: array[Int, 4];  // تعريف مصفوفة من الأعداد الصحيحية تحوي 4 عناصر
def avg: float[64]; // متغير من الصنف عائم لتخزين المتوسط
def sum: int[64] = 0; // متغير لحساب المجموع من الصنف صحيح
def i: int[64]; // عنصر التحكم بالحلقة
// تعريف حلقة وإدخال القيم
for i = 0, i < 4, i++{
  print("Enter number %d \n", (i+1));
  myArray(i) = getInt(); // إدخال العدد
}
// حساب المجموع
for i = 0, i < 4, i++{
  sum = sum + myArray(i)
}
avg = sum / 4.0; // حساب المتوسط
print("Sum of entered number is: %d \n", sum); // طباعة المجموع
print("Average of entered number is: %0.01f \n", avg); // طباعة المتوسط

/*
Enter number 1
3
Enter number 2
2
Enter number 3
3
Enter number 4
2
Sum of entered number is: 10
Average of entered number is: 2.50
*/

المصفوفات المرنة (الديناميكية)


- نوع آخر من المصفوفات لكنه أكثر تقدماً و سهولة وحرية في التعامل وصداقة مع الذاكرة.

- هو حاوية تخزن العناصر التي نضيفها فيها بشكل متسلسل وراء بعضها البعض مع إعطاء كل عنصر منهم رقم (Index) (أي كما في المصفوفات العادية). لكن يكمن الفرق الأساسي في أنه يتم حجز مساحة في الذاكرة للعنصر الذي تضيفه فيها في نفس اللحظة، وعند حذف عنصر معين يتم حذف المساحة المحجوزة له وهذا يعطيك تحكماً أكبر في الذاكرة وفي التعامل مع البيانات، ويمكّن البرنامج من حجز ما يحتاج من الذاكرة فقط. كما أن هذا الصنف يتولى مسؤولية إدارة الذاكرة مع مراعاة الأداء وتجنب عمليات النسخ وحجز الذاكرة غير الضرورية. والأهم من ذلك أنه يوجد دوال عديدة للتعامل مع هذا الصنف ويمكنك الاطلاع عليها من هنا

- تعريف مصفوفة ديناميكية من خلال الصنف `مـصفوفة` (Array) -لاحظ الإطالة في الاسم العربي، أي مـصفوفة وليس مصفوفة- ويتم بنفس طريقة المصفوفات العادية لكن يجب أن نقوم أولاً بتضمين الصف مـصفوفة Array الموجود ضمن الوحدة Srl كما يلي:

اشمل "مـتم/مـصفوفة"; // تضمين الصف `مـصفوفة`
عرف اسم_المصفوفة: مـتم.مـصفوفة[صـنف_البيانات]؛ // تعريف مصفوفة ديناميكية
import "Srl/Array.alusus"; // Array تضمين الصف
def array_name: Srl.Array[Data_type]; // تعريف مصفوفة ديناميكية

لتهيئة عناصر المصفوفة بقيم ابتدائية نستخدم الصيغة التالية:

عرف اسم_المصفوفة: مـصفوفة[صـنف_البيانات]({ ع1، ع2، ...، عن })؛
def array_name : Array[Data_type]({ v1,v2,..,vn });

ملاحظة: يمكنك كتابة التعريف السابق بالشكل التالي:

عرف اسم_المصفوفة: مـصفوفة[صـنف_البيانات](عدد_العناصر، ع1، ع2، ...، عن)؛
def array_name: Array[Data_type](num_of_elements, v1, v2, ..., vn);

والفرق كما تلاحظ يكمن في استخدام الأقواس ففي الحالة الأولى وضعنا القيم ضمن قوسين هلاليين ثم قوسين حاصرين وهذا يغنينا عن تحديد عدد العناصر، أما في الحالة الثانية قمنا بحذف القوسين القرآنيين لذلك توجّب علينا تحديد عدد العناصر أولاً.

- في البداية يكون حجم المصوفة الديناميكية يساوي الصفر، ويمكننا التحقق من حجم المصفوفة الديناميكية (عدد عناصرها) في أي وقت من خلال الدالة `هات_الطول` (getLength)

- لإضافة عنصر إلى المصفوفة الديناميكية نستخدم الدالة `أضف` (add).

اسم_المصفوفة.أضف(قيمة); // إضافة عنصر
اسم_المصفوفة.أضف({ قيمة1، قيمة2، ...، قيمة_ن })؛ // إضافة عدة عناصر دفعة واحدة
array_name.add(value); // إضافة عنصر
array_name.add({ value1, value2,.., valueN }); // إضافة عدة عناصر دفعة واحدة

- عند الإعلان عن مصفوفة ديناميكية يتم حجز مساحة ذاكرية مبدئية لها، وعندما تمتلئ هذه المساحة يتم حجز مساحة إضافية، وللاستعلام عن حجم المساحة الكلية نستخدم الدالة `هات_حجم_الصوان` (getBufSize).

مثال:
في المثال التالي سنقوم بتعريف مصفوفة ديناميكية وسنستخدم التوابع السابقة معها.

اشمل "مـتم/طـرفية"؛
اشمل "مـتم/مـصفوفة"؛
استخدم مـتم؛
عرف م1: مـصفوفة[صحيح]؛ // تعريف مصفوفة ديناميكية
اطبع("عدد عناصر المصفوفة هو: %d\ج"، م1.هات_الطول())؛
// عدد عناصر المصفوفة هو: 0
اطبع("حجم الصوان الابتدائي هو: %d\ج"، م1.هات_حجم_الصوان())؛
// حجم الصوان الابتدائي هو: 0
عرف ع: صحيح؛
// إضافة 5 عناصر إلى المصفوفة
لكل ع = 0، ع < 5، ++ع {
  م1.أضف(ع * 2)؛
  // حجم الصوان بعد كل عملية إضافة
  اطبع("حجم الصوان بعد إضافة %d عنصر هو: %d\ج"، ع + 1، م1.هات_حجم_الصوان())؛
}
/*
حجم الصوان بعد إضافة 1 عنصر هو: 2
حجم الصوان بعد إضافة 2 عنصر هو: 2
حجم الصوان بعد إضافة 3 عنصر هو: 3
حجم الصوان بعد إضافة 4 عنصر هو: 4
حجم الصوان بعد إضافة 5 عنصر هو: 6
*/

اطبع("عدد عناصر المصفوفة هو: %d\ج"، م1.هات_الطول())؛
// عدد عناصر المصفوفة هو: 5

// طباعة عناصر المصفوفة.
لكل ع = 0، ع < 5، ++ع {
  اطبع("قيمة العنصر %d هو: %d\ج"، ع، م1(ع))؛
}
/*
قيمة العنصر 0 هو: 0
قيمة العنصر 1 هو: 2
قيمة العنصر 2 هو: 4
قيمة العنصر 3 هو: 6
قيمة العنصر 4 هو: 8
*/
import "Srl/Console.alusus";
import "Srl/Array.alusus";
use Srl;
use Srl.Console;
def a1: Array[Int]; // تعريف مصفوفة ديناميكية
print("Number of elements in the array is: %d \n", a1.getLength());
// Number of elements in the array is: 0
print("Initial buffer size is: %d \n", a1.getBufSize());
// Initial buffer size is: 0
def index: int[32];
// إضافة 5 عناصر إلى المصفوفة
for index = 0, index < 5, index++ {
  a1.add(index * 2);
  // حجم الصوان بعد كل عملية إضافة
  print("Buffer size after adding %d element is: %d \n",index+1, a1.getBufSize());
}
/*
Buffer size after adding 1 element is: 2
Buffer size after adding 2 element is: 2
Buffer size after adding 3 element is: 3
Buffer size after adding 4 element is: 4
Buffer size after adding 5 element is: 6
*/

print("Array size is: %d \n", a1.getLength());
// Array size is: 5

// طباعة عناصر المصفوفة.
for index = 0, index < 5, index++ {
  print("The value of element %d is: %d\n", index, a1(index));
}
/*
The value of element 0 is: 0
The value of element 1 is: 2
The value of element 2 is: 4
The value of element 3 is: 6
The value of element 4 is: 8
*/

- بشكل عام نادراً مانحتاج إلى استخدام الدالة `هات_حجم_الصوان` (getBufSize) (تستخدم في حالات نادرة، على سبيل المثال عندما يتعلق الأمر بتحسين الأداء أو التعامل المنخفض مع الذاكرة).

- غالباً ماتكون نتيجة الدالة getBufSize و getLength متساويتان، لكن ليس بالضرورة دائماً والسبب يعود إلى أن المصفوفة الديناميكية تحاول تقليل عمليات حجز ونسخ الذاكرة، لأنها عمليات بطيئة ولذلك تحجز في العادة ذاكرة أكبر من عدد العناصر الموجودة تحسبا لزيادة عدد العناصر.

- لإضافة عنصر في موقع معين من المصفوفة نستخدم الدالة `احشر` (insert).

اسم_المصفوفة.احشر(تسلسل، قيمة)؛
array_name.insert(index,value);

حيث أن `تسلسل` (index) يمثل تسلسل العنصر الجديد في المصفوفة بعد إضافته.

- لحذف عنصر محدد من المصفوفة الديناميكية نستخدم الدالة `أزل` (remove).

اسم_المصفوفة.أزل(تسلسل)؛
array_name.remove(index);

- لحذف جميع عناصر المصفوفة دفعة واحدة نستخدم الدالة `فرّغ` (clear).

اسم_المصفوفة.فرّغ()؛
array_name.clear();

مثال:
في المثال التالي سنقوم بتعديل الكود السابق بحيث سنقوم بإضافة العدد 88 في الفهرس رقم 2 من المصفوفة م1 (a1)، ثم سنقوم بحذفه، ثم سنقوم بمسح كامل عناصر المصفوفة.

اشمل "مـتم/طـرفية"؛
اشمل "مـتم/مـصفوفة"؛
استخدم مـتم؛
عرف م1: مـصفوفة[صحيح]؛
طـرفية.اطبع("حجم المصفوفة هو: %d\ج"، م1.هات_الطول())؛
طـرفية.اطبع("حجم الصوان الابتدائي هو: %d\ج"، م1.هات_حجم_الصوان())؛
عرف ع: صحيح؛
لكل ع = 0، ع < 5، ++ع {
  م1.أضف(ع * 2)؛
}
// إضافة العنصر 88 في الفهرس 2 (أي الموقع الثالث)
م1.احشر(2، 88)؛
// طباعة عناصر المصفوفة.
لكل ع = 0، ع < 5، ++ع {
  طـرفية.اطبع("قيمة العنصر %d هو: %d\ج"، ع، م1(ع))؛
}
/*
قيمة العنصر 0 هو: 0
قيمة العنصر 1 هو: 2
قيمة العنصر 2 هو: 88
قيمة العنصر 3 هو: 4
قيمة العنصر 4 هو: 6
*/
// حذفه مرة أخرى:
م1.أزل(2)؛
// طباعة عناصر المصفوفة:
لكل ع = 0، ع < 5، ++ع {
  طـرفية.اطبع("قيمة العنصر %d هو: %d\ج"، ع، م1(ع))؛
}
/*
قيمة العنصر 0 هو: 0
قيمة العنصر 1 هو: 2
قيمة العنصر 2 هو: 4
قيمة العنصر 3 هو: 6
قيمة العنصر 4 هو: 8
*/
// حذف جميع العناصر
م1.فرّغ()؛
طـرفية.اطبع("حجم المصفوفة هو: %d\ج"، م1.هات_الطول())؛
// حجم المصفوفة هو: 0
طـرفية.اطبع("حجم الصوان بعد التفريغ: %d\ج"، م1.هات_حجم_الصوان())؛
// حجم الصوان بعد التفريغ: 0
import "Srl/Console.alusus";
import "Srl/Array.alusus";
use Srl;
def a1: Array[Int];
Console.print("The size of the array is: %d \n", a1.getLength ());
Console.print("Initial size of the Buffer is: %d \n", a1.getBufSize ());
def index: int[32];
for index = 0, index < 5, index++ {
  a1.add(index * 2)
}
// إضافة العنصر 88 في الفهرس 2 (أي الموقع الثالث)
a1.insert(2, 88);
// طباعة عناصر المصفوفة.
for index = 0, index < 5, index++ {
  Console.print("The value of the element with index %d is: %d\n",index,a1(index));
}
/*
The value of the element with index 0 is: 0
The value of the element with index 1 is: 2
The value of the element with index 2 is: 88
The value of the element with index 3 is: 4
The value of the element with index 4 is: 6
*/
// حذفه مرة أخرى:
a1.remove(2);
// طباعة عناصر المصفوفة:
for index = 0,index < 5, index++ {
  Console.print("The value of the element with index %d is: %d\n",index,a1(index));
}
/*
The value of the element with index 0 is: 0
The value of the element with index 1 is: 2
The value of the element with index 2 is: 4
The value of the element with index 3 is: 6
The value of the element with index 4 is: 8
*/
// حذف جميع العناصر
a1.clear();
Console.print("The size of the array is: %d \n", a1.getLength());
// The size of the array is: 0
Console.print("Buffer size after cleaning: %d \n", a1.getBufSize());
// Buffer size after cleaning: 0