نوع البيانات المجردة

في علم الحاسوب ، يُعدّ نوع البيانات المجرد ( ADT ) نموذجًا رياضيًا لأنواع البيانات ، يُعرَّف بسلوكه ( دلالاته ) من وجهة نظر مستخدم البيانات ، وتحديدًا من حيث القيم الممكنة، والعمليات الممكنة على بيانات هذا النوع، وسلوك هذه العمليات. يختلف هذا النموذج الرياضي عن هياكل البيانات ، التي تُمثّل تمثيلات ملموسة للبيانات، وتُمثّل وجهة نظر المُنفِّذ، لا المستخدم. على سبيل المثال، تحتوي المكدسة على عمليات دفع/سحب تتبع قاعدة "آخر ما يدخل أول ما يخرج"، ويمكن تنفيذها عمليًا باستخدام قائمة مرتبطة أو مصفوفة. مثال آخر هو المجموعة التي تُخزّن القيم، دون أي ترتيب مُحدد ، ودون قيم مُكررة. لا تُسترجع القيم نفسها من المجموعات؛ بل يتم اختبار قيمة ما للتأكد من انتمائها للحصول على قيمة منطقية "موجود" أو "غير موجود".

تُعدّ أنواع البيانات المجردة (ADTs) مفهومًا نظريًا يُستخدم في الدلالات الرسمية والتحقق من البرامج ، وبشكل أقل تحديدًا، في تصميم وتحليل الخوارزميات وهياكل البيانات وأنظمة البرمجيات . لا تدعم معظم لغات البرمجة الشائعة تحديد أنواع البيانات المجردة بشكل مباشر. مع ذلك، تتوافق العديد من ميزات لغات البرمجة مع جوانب معينة من تطبيق أنواع البيانات المجردة، وغالبًا ما يتم الخلط بينها وبين أنواع البيانات المجردة نفسها؛ وتشمل هذه الميزات الأنواع المجردة ، وأنواع البيانات المبهمة ، والبروتوكولات ، والتصميم التعاقدي . على سبيل المثال، في البرمجة المعيارية ، يُعلن الموديول عن إجراءات تتوافق مع عمليات نوع البيانات المجرد، وغالبًا ما يتضمن ذلك تعليقات تصف القيود. تسمح استراتيجية إخفاء المعلومات هذه بتغيير تطبيق الموديول دون التأثير على برامج العميل ، لكن الموديول يُعرّف نوع البيانات المجرد بشكل غير رسمي فقط. يرتبط مفهوم أنواع البيانات المجردة بمفهوم تجريد البيانات ، وهو مفهوم مهم في البرمجة كائنية التوجه ومنهجيات التصميم التعاقدي لهندسة البرمجيات . [ 1 ]

تاريخ

طُرحت أنواع البيانات المجردة (ADTs) لأول مرة من قِبل باربرا ليسكوف وستيفن ن. زيلز عام 1974، كجزء من تطوير لغة CLU . [ 2 ] كان التحديد الجبري موضوعًا بحثيًا هامًا في علوم الحاسوب حوالي عام 1980، وكان يُعتبر مرادفًا تقريبًا لأنواع البيانات المجردة في ذلك الوقت. [ 3 ] ويستند إلى أساس رياضي في الجبر الشامل . [ 4 ]

تعريف

من الناحية الرسمية، يُشابه نوع البيانات المجردة (ADT) البنية الجبرية في الرياضيات، [ 5 ] إذ يتألف من مجال، ومجموعة من العمليات، ومجموعة من القيود التي يجب أن تستوفيها هذه العمليات. [ 6 ] غالبًا ما يُعرَّف المجال ضمنيًا، على سبيل المثال، الكائن الحر على مجموعة عمليات نوع البيانات المجردة. تشير واجهة نوع البيانات المجردة عادةً إلى المجال والعمليات فقط، وربما بعض القيود المفروضة على العمليات، مثل الشروط المسبقة واللاحقة؛ ولكنها لا تشمل قيودًا أخرى، مثل العلاقات بين العمليات، والتي تُعتبر سلوكًا. يوجد نمطان رئيسيان للمواصفات الرسمية للسلوك، وهما الدلالات البديهية والدلالات التشغيلية . [ 7 ]

على الرغم من أن القيود ليست جزءًا من الواجهة، إلا أنها تظل مهمة لتعريف نوع البيانات المجرد (ADT)؛ فعلى سبيل المثال، تتشابه واجهات إضافة/إزالة العناصر في المكدس والطابور ، ولكن القيود هي التي تميز سلوك "آخر ما يدخل أول ما يخرج" عن سلوك "أول ما يدخل أول ما يخرج". ولا تقتصر القيود على المعادلات فحسب، بل تشمل أيضًا الصيغ المنطقية .fetch(store(S,v))=v

الدلالات البديهية

انطلاقًا من مبادئ البرمجة الوظيفية ، تُعتبر كل حالة من حالات بنية البيانات المجردة كيانًا أو قيمة مستقلة. في هذا السياق، تُنمذج كل عملية كدالة رياضية دون أي آثار جانبية . تُنمذج العمليات التي تُعدّل بنية البيانات المجردة كدوال تأخذ الحالة القديمة كمعامل وتُعيد الحالة الجديدة كجزء من النتيجة. لا يُهم ترتيب تقييم العمليات، فالعملية نفسها المطبقة على نفس المعاملات (بما في ذلك حالات الإدخال نفسها) ستُعيد دائمًا نفس النتائج (وحالات الإخراج). تُحدد القيود كمسلمات أو قوانين جبرية يجب أن تُحققها العمليات.

الدلالات التشغيلية

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

العمليات المساعدة

غالباً ما تقتصر عروض أنظمة البيانات الآلية (ADTs) على العمليات الرئيسية فقط. أما العروض الأكثر شمولاً فتتضمن عادةً عمليات إضافية على أنظمة البيانات الآلية، مثل:

  • create()، مما ينتج عنه نسخة جديدة من نوع البيانات المجردة (ADT)؛
  • compare(s, t)، الذي يختبر ما إذا كانت حالات مثيلين متكافئة بمعنى ما؛
  • hash(s)، والتي تحسب دالة تجزئة قياسية من حالة المثيل؛
  • print(s)أو show(s)، الذي ينتج تمثيلاً قابلاً للقراءة البشرية لحالة المثال.

هذه الأسماء توضيحية وقد تختلف بين المؤلفين. في تعريفات أنواع البيانات المجردة ذات النمط الإجرائي، نجد غالبًا أيضًا ما يلي:

  • initialize(s)، الذي يهيئ نسخة تم إنشاؤها حديثًا sلمزيد من العمليات، أو يعيد ضبطها إلى "حالة أولية" ما؛
  • copy(s)، مما يضع المثال sفي حالة مكافئة لحالة t؛
  • clone(t)، الذي يقوم بـ screate()، copy(s, t)، ويعيد s؛
  • free(s)أو destroy(s)، الذي يستعيد الذاكرة والموارد الأخرى المستخدمة بواسطة s.

لا تُعدّ هذه freeالعملية عادةً ذات صلة أو معنى، لأنّ أنواع البيانات المجردة (ADTs) كيانات نظرية لا "تستخدم الذاكرة". مع ذلك، قد يكون من الضروري استخدامها عند الحاجة إلى تحليل مساحة التخزين التي تستخدمها خوارزمية تستخدم نوع البيانات المجردة. في هذه الحالة، يلزم وجود بديهيات إضافية تُحدّد مقدار الذاكرة التي يستخدمها كل مثيل من أنواع البيانات المجردة، كدالة لحالته، ومقدار الذاكرة التي يُعيدها إلى مجمع الذاكرة free.

الأنواع المقيدة

غالبًا ما يُقيّد تعريف نوع البيانات المجردة (ADT) القيم المخزنة لمثيلاته، بحيث تقتصر على عناصر مجموعة محددة X تُسمى نطاق تلك المتغيرات. على سبيل المثال، قد يُقيّد متغير مجرد لتخزين الأعداد الصحيحة فقط. وكما هو الحال في لغات البرمجة، قد تُسهّل هذه القيود وصف الخوارزميات وتحليلها ، وتُحسّن من سهولة قراءتها.

التداخل

في أسلوب التشغيل، غالبًا ما يكون من غير الواضح كيفية التعامل مع حالات متعددة، وما إذا كان تعديل حالة واحدة قد يؤثر على الحالات الأخرى. يُعرّف أسلوب شائع لأنواع البيانات المجردة (ADTs) العمليات كما لو كانت حالة واحدة فقط موجودة أثناء تنفيذ الخوارزمية، وتُطبّق جميع العمليات على تلك الحالة. على سبيل المثال، قد تحتوي مكدسة على العمليتين push( x ) و pop()، اللتين تعملان على المكدسة الوحيدة الموجودة. يمكن إعادة كتابة تعريفات أنواع البيانات المجردة بهذا الأسلوب بسهولة للسماح بوجود حالات متعددة متزامنة من نوع البيانات المجردة، وذلك بإضافة مُعامل حالة صريح (مثل S في مثال المكدسة أدناه) إلى كل عملية تستخدم أو تُعدّل الحالة الضمنية. لا يمكن تعريف بعض أنواع البيانات المجردة تعريفًا ذا معنى دون السماح بوجود حالات متعددة، على سبيل المثال عندما تأخذ عملية واحدة حالتين مختلفتين من نوع البيانات المجردة كمعاملات، مثل unionعملية على مجموعات أو compareعملية على قوائم.

يُدمج أسلوب تعدد الحالات أحيانًا مع مبدأ التداخل ، أي أن نتيجة الدالة create() تختلف عن أي حالة يستخدمها الخوارزمية بالفعل. قد تُعيد تطبيقات أنواع البيانات المجردة استخدام الذاكرة وتسمح لتطبيقات الدالة create() بإنتاج حالة مُنشأة مسبقًا؛ ومع ذلك، فإن تحديد ما إذا كانت هذه الحالة "مُعاد استخدامها" يُعد أمرًا صعبًا في شكلية أنواع البيانات المجردة.

بشكلٍ أعم، يمكن تعزيز هذه البديهية لاستبعاد التداخل الجزئي مع حالات أخرى، بحيث يُفترض أن أنواع البيانات المجردة المركبة (مثل الأشجار أو السجلات) وأنواع البيانات المجردة المرجعية (مثل المؤشرات) منفصلة تمامًا. على سبيل المثال، عند توسيع تعريف متغير مجرد ليشمل السجلات المجردة ، فإن العمليات على الحقل F لمتغير سجل R تتضمن بوضوح F ، وهو حقل منفصل عن R ولكنه جزء منه . تنص بديهية التداخل الجزئي على أن تغيير حقل في متغير سجل واحد لا يؤثر على أي سجلات أخرى.

تحليل التعقيد

يُدرج بعض المؤلفين أيضًا التعقيد الحسابي ("التكلفة") لكل عملية، سواءً من حيث الوقت (لعمليات الحساب) أو المساحة (لتمثيل القيم)، للمساعدة في تحليل الخوارزميات . على سبيل المثال، يمكن تحديد أن كل عملية تستغرق نفس الوقت وأن كل قيمة تشغل نفس المساحة بغض النظر عن حالة نوع البيانات المجرد (ADT)، أو أن هناك "حجمًا" لنوع البيانات المجرد وأن العمليات خطية أو تربيعية، وما إلى ذلك، بالنسبة لحجم نوع البيانات المجرد. وقد أدرج ألكسندر ستيبانوف ، مصمم مكتبة القوالب القياسية للغة C++ ، ضمانات التعقيد في مواصفات STL، مُبررًا ذلك بما يلي:

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

ألكسندر ستيبانوف [ 8 ]

ويخالف مؤلفون آخرون هذا الرأي، بحجة أن نوع البيانات المجردة للمكدس هو نفسه سواء تم تنفيذه باستخدام قائمة مرتبطة أو مصفوفة، على الرغم من اختلاف تكاليف التشغيل، وأن مواصفات نوع البيانات المجردة يجب أن تكون مستقلة عن التنفيذ.

أمثلة

متغير مجرد

يمكن اعتبار المتغير المجرد أبسط أنواع البيانات المجردة غير التافهة، وله دلالات المتغير الإجرائي. وهو يقبل عمليتين، fetchو store. غالبًا ما تُكتب التعريفات الإجرائية بدلالة المتغيرات المجردة. في الدلالات البديهية، يكونV{\displaystyle V}أن يكون نوع المتغير المجرد وX{\displaystyle X}يكون نوع محتوياته fetchدالةVX{\displaystyle V\to X}وهي storeدالة من النوعV×XV{\displaystyle V\times X\to V}الشرط الرئيسي هو أن fetchتُعيد الدالة دائمًا القيمة x المستخدمة في آخر storeعملية على نفس المتغير V ، أي fetch(store(V,x)) = xx = 0. قد نشترط أيضًا أن storeتُستبدل القيمة بالكامل store(store(V,x1),x2) = store(V,x2).

في دلالات العمليات، يُمثل fetch( V ) إجراءً يُعيد القيمة الحالية في الموقع V ، بينما يُمثل store( V , x ) إجراءً من voidنوع إرجاع يُخزن القيمة x في الموقع V. وتُوصَف القيود بشكل غير رسمي بأن عمليات القراءة تتوافق مع عمليات الكتابة. وكما هو الحال في العديد من لغات البرمجة، غالبًا ما تُكتب العملية store( V , x ) على النحو Vx (أو ما شابه ذلك)، ويُفترض وجود fetch( V ) ضمنيًا كلما استُخدم متغير V في سياق يتطلب قيمة. فعلى سبيل المثال، يُفهم عمومًا أن VV + 1 هو اختصار لـ store( V , fetch( V ) + 1).

في هذا التعريف، يُفترض ضمنيًا أن الأسماء دائمًا ما تكون مميزة: تخزين قيمة في متغير U لا يؤثر على حالة متغير مميز V. ولتوضيح هذا الافتراض، يمكن إضافة القيد التالي:

  • إذا كان U و V متغيرين متميزين، فإن المتتالية { store( U , x ); store( V , y ) } تعادل { store( V , y ); store( U , x ) }.

لا يُشير هذا التعريف إلى نتيجة تقييم fetch( V ) عندما تكون V غير مُهيأة ، أي قبل إجراء أي storeعملية عليها . يمكن منع جلب البيانات قبل تخزينها، أو تحديد نتيجة معينة لها، أو تركها غير مُحددة. توجد بعض الخوارزميات التي تعتمد كفاءتها على افتراض أن هذا الإجراء fetchقانوني، وتُعيد قيمة عشوائية ضمن نطاق المتغير.

مجموعة مجردة

المكدس المجرد هو بنية بيانات تُدخل فيها البيانات أولاً، وتُعرَّف عمومًا بثلاث عمليات رئيسية: pushإدخال عنصر بيانات إلى المكدس، popوإزالة عنصر بيانات منه، peekوالوصول topإلى عنصر بيانات في أعلى المكدس دون إزالته. يتضمن تعريف المكدس المجرد الكامل أيضًا دالة منطقيةempty ( S ) وعملية create() تُعيد نسخة أولية من المكدس.

في علم الدلالة البديهية، السماحS{\displaystyle S}أن يكون نوع حالات المكدس وX{\displaystyle X}قد تكون أنواع القيم الموجودة في المكدس هيصusح:SXS{\displaystyle push:S\to X\to S}،صoص:S(S،X){\displaystyle pop:S\to (S,X)}،تoص:SX{\displaystyle top:S\to X}،جرهـأتهـ:S{\displaystyle create:S}، وهـمصتy:Sب{\displaystyle empty:S\to \mathbb {B} }في الدلالات البديهية، يُعد إنشاء المكدس الأولي عملية "بسيطة"، ويعيد دائمًا نفس الحالة المميزة. لذلك، غالبًا ما يُشار إليه برمز خاص مثل Λ أو "()". emptyويمكن كتابة مُسند العملية ببساطة على النحو التالي:s=Λ{\displaystyle s=\Lambda }أوsΛ{\displaystyle s\neq \Lambda }.

تكون القيود كما يلي pop(push(S,v))=(S,v): top(push(S,v))=v[ 9 ] ( ) = T (المكدس المُنشأ حديثًا فارغ)، ( ( S , x ) ) = F (إضافة عنصر إلى المكدس تجعله غير فارغ). لا تُحدد هذه البديهيات تأثير ( s ) أو ( s )، إلا إذا كانت s حالة مكدس مُعادة من دالة . بما أن ( s) تجعل المكدس غير فارغ، يُمكن تعريف هاتين العمليتين على أنهما غير صالحتين عندما s = Λ. من هذه البديهيات (وعدم وجود آثار جانبية)، يُمكن استنتاج أن (Λ, x ) ≠ Λ. أيضًا، ( s , x ) = ( t , y ) إذا وفقط إذا كان x = y و s = t .emptycreateemptypushtoppoppushpushpushpushpush

كما هو الحال في بعض فروع الرياضيات الأخرى، من المعتاد افتراض أن حالات المكدس هي فقط تلك التي يمكن إثبات وجودها من البديهيات في عدد محدود من الخطوات. في هذه الحالة، يعني ذلك أن كل مكدس هو سلسلة منتهية من القيم، تصبح مكدسًا فارغًا (Λ) بعد عدد محدود من popالخطوات. لا تستبعد البديهيات المذكورة أعلاه، في حد ذاتها، وجود مكدسات لانهائية (يمكن popتكرارها إلى ما لا نهاية، وفي كل مرة تُنتج حالة مختلفة) أو مكدسات دائرية (تعود إلى الحالة نفسها بعد عدد محدود من popالخطوات). على وجه الخصوص، لا تستبعد هذه البديهيات الحالات s التي يكون فيها pop( s ) = s أو push( s , x ) = s لبعض قيم x . ومع ذلك، بما أنه لا يمكن الحصول على مثل هذه الحالات من حالة المكدس الأولية بالعمليات المعطاة، يُفترض أنها "غير موجودة".

في التعريف العملي للمكدس المجرد، لا تُرجع الدالة push( S , x ) أي قيمة، بينما تُرجع الدالة pop( S ) القيمة كنتيجة، ولكن ليس الحالة الجديدة للمكدس. وبالتالي، يوجد قيد ينص على أنه لأي قيمة x وأي متغير مجرد V ، فإن تسلسل العمليات { push( S , x ); Vpop( S )} يُكافئ Vx . وبما أن التعيين Vx ، بحكم التعريف، لا يُمكنه تغيير حالة S ، فإن هذا الشرط يعني أن Vpop( S ) يُعيد S إلى الحالة التي كانت عليها قبل push( S , x ). ومن هذا الشرط، ومن خصائص المتغيرات المجردة، يتبين، على سبيل المثال، أن التسلسل:

{ push( S , x ); push( S , y ); Upop( S ); push( S , z ); Vpop( S ); Wpop( S ) }

حيث x و y و z هي أي قيم، و U و V و W هي متغيرات متميزة مثنى مثنى، فإن ذلك يكافئ ما يلي:

{ Uy ; Vz ; Wx }

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

  • لأي قيم x و y وأي مجموعات متميزة S و T ، فإن التسلسل { push( S , x ); push( T , y ) } يكافئ { push( T , y ); push( S , x ) }.

التسلسل الهرمي للازدهار

ومن الأمثلة الأكثر تعقيدًا تسلسل Boom الهرمي لأنواع البيانات المجردة: الشجرة الثنائية، والقائمة، والحقيبة، والمجموعة. [ 10 ] يمكن تعريف جميع أنواع البيانات هذه بثلاث عمليات: null ، التي تُنشئ حاوية فارغة؛ وsingle ، التي تُنشئ حاوية من عنصر واحد؛ و append ، التي تجمع حاويتين من النوع نفسه. ويمكن بعد ذلك تحديد المواصفات الكاملة لأنواع البيانات الأربعة بإضافة القواعد التالية تباعًا على هذه العمليات:

يمثل الصفر الحياد الأيسر والأيمن للشجرةappend(null,A) = A, append(A,null) = A.
تُضاف القوائم التي تُلحق البيانات التي تكون ترابطيةappend(append(A,B),C) = append(A,append(B,C)).
تُضفي الحقائب سهولة التنقلappend(B,A) = append(A,B).
وأخيرًا، المجموعات أيضًا متطابقةappend(A,A) = A.

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

member(X,single(Y)) = eq(X,Y)
member(X,null) = false
member(X,append(A,B)) = or(member(X,A), member(X,B))

يجب توخي الحذر لضمان ثبات الدالة وفقًا للقواعد ذات الصلة بنوع البيانات. ضمن كل فئة من فئات التكافؤ التي تنطوي عليها المجموعة الفرعية المختارة من المعادلات، يجب أن تعطي الدالة النتيجة نفسها لجميع عناصرها.

تفريغ الشحنات الشائعة

بعض أنواع البيانات المجردة الشائعة، والتي أثبتت فائدتها في مجموعة كبيرة ومتنوعة من التطبيقات، هي

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

نوع بيانات رسومي مجرد

في عام 1979، تم اقتراح امتداد لأنواع البيانات المجردة (ADT) في مجال رسومات الحاسوب، وهو نوع بيانات رسومي مجرد (AGDT). [ 11 ] وقد قدمه كل من نادية ماغنانات تالمان ودانيال تالمان . توفر أنواع البيانات الرسومية المجردة مزايا أنواع البيانات المجردة مع إمكانية إنشاء كائنات رسومية بطريقة منظمة.

تطبيق

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

على سبيل المثال، يمكن تحديد الأعداد الصحيحة كنوع بيانات مجرد (ADT)، مُعرَّف بالقيمتين 0 و1، وعمليات الجمع والطرح والضرب والقسمة (مع مراعاة القسمة على صفر) والمقارنة، وما إلى ذلك، وفقًا للمسلمات الرياضية المعروفة في الجبر المجرد، مثل التجميعية والتبديلية، وما إلى ذلك. مع ذلك، في الحاسوب، تُمثَّل الأعداد الصحيحة عادةً كأعداد ثنائية ثابتة العرض ، 32 بت أو 64 بت . يجب على المستخدمين الانتباه إلى مشكلات هذا التمثيل، مثل تجاوز السعة الحسابية ، حيث يُحدد نوع البيانات المجرد نتيجة صحيحة، لكن التمثيل غير قادر على استيعاب هذه القيمة. ومع ذلك، في كثير من الأحيان، يمكن للمستخدم تجاهل هذه المشكلات واستخدام التنفيذ كما لو كان نوع البيانات المجرد.

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

لمنع اعتماد العملاء على التنفيذ، غالبًا ما يُغلّف نوع البيانات المجرد (ADT) كنوع بيانات مبهم أو مُعرّف من نوع ما، [ 12 ] في وحدة نمطية واحدة أو أكثر ، تحتوي واجهتها على توقيع العمليات فقط (عدد وأنواع المعاملات والنتائج). وبذلك، يُمكن إخفاء تنفيذ الوحدة النمطية - أي أجسام الإجراءات وبنية البيانات المُستخدمة - عن معظم عملاء الوحدة. وهذا يُتيح تغيير التنفيذ دون التأثير على العملاء. أما إذا كان التنفيذ مكشوفًا، فيُعرف حينها بنوع البيانات الشفاف.

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

تتسم مواصفات بعض لغات البرمجة بالغموض المتعمد فيما يتعلق بتمثيل أنواع البيانات المدمجة، حيث تُحدد فقط العمليات التي يمكن إجراؤها عليها. ولذلك، يمكن اعتبار هذه الأنواع "أنواع بيانات مجردة مدمجة". ومن الأمثلة على ذلك المصفوفات في العديد من لغات البرمجة النصية، مثل Awk و Lua و Perl ، والتي يمكن اعتبارها تطبيقًا للقائمة المجردة.

في لغة المواصفات الرسمية ، يمكن تعريف أنواع البيانات المجردة (ADTs) بشكل بديهي، وتتيح اللغة بعد ذلك معالجة قيم هذه الأنواع، مما يوفر تنفيذًا مباشرًا وفوريًا. على سبيل المثال، تسمح عائلة لغات البرمجة OBJ بتعريف المعادلات للمواصفات وإعادة كتابتها لتشغيلها. مع ذلك، فإن هذه التطبيقات التلقائية عادةً ما تكون أقل كفاءة من التطبيقات المخصصة.

مثال: تطبيق المكدس المجرد

كمثال على ذلك، إليك تطبيق للمكدس المجرد أعلاه بلغة البرمجة C.

واجهة نمطية أمرية

قد تكون واجهة المستخدم ذات النمط الإجرائي كالتالي:

// النوع: تمثيل مثيل المكدس (سجل مبهم) typedef struct { // التنفيذ هنا } Stack ;// النوع: قيمة مخزنة في مثيل مكدس (عنوان عشوائي) typedef void * Item ;// ينشئ نسخة جديدة فارغة من المكدس Stack * stack_create ( void );// يضيف عنصرًا في أعلى المكدس void stack_push ( Stack * s , Item x );// يزيل العنصر العلوي من المكدس ويعيده Item stack_pop ( Stack * s );// يتحقق مما إذا كانت المكدسة فارغة bool stack_is_empty ( Stack * s );

يمكن استخدام هذه الواجهة بالطريقة التالية:

#include <stack.h>int main () { Stack * s = stack_create (); // إنشاء نسخة جديدة فارغة من المكدس int x = 17 ;// يضيف عنوان x في أعلى المكدس stack_push ( s , & x ); // يزيل عنوان x من المكدس ويعيده Item y = stack_pop ( s );if ( stack_is_empty ( s )) { // يقوم بشيء ما إذا كانت المكدسة فارغة printf ( "المكدسة فارغة!" ); } }

يمكن تنفيذ هذه الواجهة بطرق عديدة. قد يكون التنفيذ غير فعال بشكل تعسفي، لأن التعريف الرسمي لنوع البيانات المجردة (ADT) المذكور أعلاه لا يحدد مقدار المساحة التي يمكن أن يستخدمها المكدس، ولا المدة الزمنية التي يجب أن تستغرقها كل عملية. كما أنه لا يحدد ما إذا كانت حالة المكدس sتستمر بعد استدعاء الدالة xpop(s).

عمليًا، ينبغي أن يُحدد التعريف الرسمي أن المساحة تتناسب مع عدد العناصر المُضافة والتي لم تُحذف بعد؛ وأن كل عملية من العمليات المذكورة أعلاه يجب أن تنتهي في وقت ثابت، بغض النظر عن هذا العدد. وللامتثال لهذه المواصفات الإضافية، يمكن للتنفيذ استخدام قائمة مرتبطة، أو مصفوفة (مع إمكانية تغيير حجمها ديناميكيًا) بالإضافة إلى عددين صحيحين (عدد العناصر وحجم المصفوفة).

واجهة ذات نمط وظيفي

تُعدّ تعريفات أنواع البيانات المجردة ذات النمط الوظيفي أكثر ملاءمةً للغات البرمجة الوظيفية، والعكس صحيح. مع ذلك، يُمكن توفير واجهة ذات نمط وظيفي حتى في لغة إجرائية مثل لغة C. على سبيل المثال:

// النوع: تمثيل مثيل المكدس (سجل مبهم) typedef struct { // التنفيذ هنا } Stack ;// النوع: قيمة مخزنة في مثيل مكدس (عنوان عشوائي) typedef void * Item ;// تُعيد حالة المكدس الفارغ Stack * stack_is_empty ( void );// يضيف عنصرًا في أعلى حالة المكدس ويعيد حالة المكدس الناتجة Stack * stack_push ( Stack * s , Item x );// يزيل العنصر العلوي من حالة المكدس ويعيد حالة المكدس الناتجة Stack * stack_pop ( Stack * s );// تُعيد العنصر العلوي من حالة المكدس Item stack_top ( Stack * s );

انظر أيضاً

الاقتباسات

  1. "القراءة 10: أنواع البيانات المجردة" . معهد ماساتشوستس للتكنولوجيا.
  2. ليسكوف وزيلز 1974 .
  3. إهريج، هـ. (1985). أساسيات التحديد الجبري 1 - المعادلات والدلالات الأولية . سبرينغر-فيرلاغ. ISBN 0-387-13718-1.
  4. فيشلر، فولفغانغ (1992). الجبر الشامل لعلماء الحاسوب . سبرينغر-فيرلاغ. ISBN 0-387-54280-9.
  5. رودولف ليدل (2004). الجبر المجرد . سبرينغر. ISBN 978-81-8128-149-4.، الفصل 7، القسم 40.
  6. ديل ووالكر 1996 ، ص 3.
  7. ديل ووالكر 1996 ، ص 4.
  8. ستيفنز، آل (مارس 1995). "آل ستيفنز يُجري مقابلة مع أليكس ستيبانوف" . مجلة دكتور دوبز . تم الاطلاع عليه بتاريخ 31 يناير 2015 .
  9. بلاك، بول إي. (24 أغسطس 2005). "الدلالات البديهية" . قاموس الخوارزميات وهياكل البيانات . تم الاسترجاع في 25 نوفمبر 2023 .
  10. بونكنبورغ، ألكسندر (1994). "التسلسل الهرمي للنمو". البرمجة الوظيفية، غلاسكو 1993. ورش عمل في الحوسبة. ص 1-8 . CiteSeerX 10.1.1.49.3252 . doi : 10.1007/978-1-4471-3236-3_1 . ISBN   978-3-540-19879-6.
  11. د. ثالمان، ن. ماغنانات ثالمان (1979). تصميم وتنفيذ أنواع البيانات الرسومية المجردة . معهد مهندسي الكهرباء والإلكترونيات. doi : 10.1109/CMPSAC.1979.762551 .، وقائع المؤتمر الدولي الثالث لبرمجيات الحاسوب وتطبيقاتها (COMPSAC'79)، معهد مهندسي الكهرباء والإلكترونيات، شيكاغو، الولايات المتحدة الأمريكية، الصفحات 519-524
  12. روبرت سيدجويك (1998). الخوارزميات في لغة سي . أديسون/ويسلي. رقم ISBN 978-0-201-31452-6.، التعريف 4.4.

مراجع

  • ليسكوف، باربرا ؛ زيلز، ستيفن (1974). "البرمجة باستخدام أنواع البيانات المجردة". وقائع ندوة ACM SIGPLAN حول لغات البرمجة عالية المستوى جدًا . نشرة SIGPLAN. المجلد  9. الصفحات 50-59 . CiteSeerX 10.1.1.136.3043 . doi : 10.1145/800233.807045 .  
  • ديل، نيل؛ ووكر، هنري م. (1996). أنواع البيانات المجردة: المواصفات، والتطبيقات، والتنفيذات . جونز وبارتليت ليرنينج. ISBN 978-0-66940000-7.

للمزيد من القراءة