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

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

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

المجموعة المتعددة هي نوع خاص من المجموعات حيث يمكن أن يظهر عنصر ما عدة مرات في المجموعة.

نظرية الأنواع

في نظرية الأنواع ، تُعرَّف المجموعات عمومًا بدالة المؤشر (الدالة المميزة): وبناءً على ذلك، فإن مجموعة من القيم من النوعأ{\displaystyle A}قد يُشار إليه بـ2أ{\displaystyle 2^{A}}أوP(أ){\displaystyle {\mathcal {P}}(A)}(يمكن نمذجة الأنواع الفرعية والمجموعات الفرعية بواسطة أنواع التحسين ، ويمكن استبدال مجموعات القسمة بمجموعات جزئية .) الدالة المميزةF{\displaystyle F}من مجموعةS{\displaystyle S}يُعرَّف على النحو التالي:

F(x)={1،لو xS0،لو xS{\displaystyle F(x)={\begin{cases}1,&{\mbox{if }}x\in S\\0,&{\mbox{if }}x\not \in S\end{cases}}}

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

العمليات

العمليات الأساسية في نظرية المجموعات

يمكن تعريف عمليات جبر المجموعات على النحو التالي :

  • union(S,T): تُرجع اتحاد المجموعتين S و T.
  • intersection(S,T): تُعيد تقاطع المجموعتين S و T.
  • difference(S,T): تُرجع الفرق بين المجموعتين S و T.
  • subset(S,T): دالة منطقية تختبر ما إذا كانت المجموعة S مجموعة جزئية من المجموعة T.

المجموعات الثابتة

العمليات النموذجية التي قد توفرها بنية المجموعة الثابتة S هي:

  • is_element_of(x,S): يتحقق مما إذا كانت القيمة x موجودة في المجموعة S.
  • is_empty(S): يتحقق مما إذا كانت المجموعة S فارغة.
  • size(S)أو : تُرجع عدد العناصر في S.cardinality(S)
  • iterate(S): تُرجع دالة تُرجع قيمة إضافية واحدة لـ S في كل استدعاء، بترتيب عشوائي.
  • enumerate(S): تُرجع قائمة تحتوي على عناصر S بترتيب عشوائي.
  • build(x1,x2,…,xn,): ينشئ بنية مجموعة بقيم x 1 ، x 2 ، ... ، x n .
  • create_from(collection): ينشئ بنية مجموعة جديدة تحتوي على جميع عناصر المجموعة المعطاة أو جميع العناصر التي تم إرجاعها بواسطة المكرر المعطى .

المجموعات الديناميكية

تتضمن هياكل المجموعات الديناميكية عادةً ما يلي:

  • create(): ينشئ بنية مجموعة جديدة فارغة في البداية.
    • create_with_capacity(n): ينشئ بنية مجموعة جديدة، فارغة في البداية ولكنها قادرة على استيعاب ما يصل إلى n عنصرًا.
  • add(S,x): يضيف العنصر x إلى S ، إذا لم يكن موجودًا بالفعل.
  • remove(S, x): يزيل العنصر x من S ، إذا كان موجودًا.
  • capacity(S): تُرجع هذه الدالة الحد الأقصى لعدد القيم التي يمكن أن تحتويها المجموعة S.

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

عمليات إضافية

هناك العديد من العمليات الأخرى التي يمكن (من حيث المبدأ) تعريفها وفقًا لما سبق، مثل:

  • pop(S): تُعيد عنصرًا عشوائيًا من S ، وتحذفه من S. [ 1 ]
  • pick(S): تُعيد عنصرًا عشوائيًا من المجموعة S. [ 2 ] [ 3 ] [ 4 ] وظيفيًا، يمكن تفسير المُعدِّل popعلى أنه زوج من المُحدِّدات (pick, rest),حيث restتُعيد المجموعة التي تتكون من جميع العناصر باستثناء العنصر العشوائي. [ 5 ] يمكن تفسيره من حيث iterate. [ أ ]
  • map(F,S): تُرجع مجموعة القيم المميزة الناتجة عن تطبيق الدالة F على كل عنصر من عناصر S.
  • filter(P,S): تُرجع المجموعة الفرعية التي تحتوي على جميع عناصر S التي تحقق شرطًا معينًا P.
  • fold(A0,F,S): تُرجع القيمة A | S | بعد تطبيقها على كل عنصر e من لبعض العمليات الثنائية F. يجب أن تكون F تجميعية وتبديلية حتى يكون هذا مُعرّفًا جيدًا.Ai+1 := F(Ai, e)
  • clear(S): حذف جميع عناصر S .
  • equal(S1', S2'): يتحقق مما إذا كانت المجموعتان المعطيتان متساويتين (أي تحتويان على جميع العناصر نفسها فقط).
  • hash(S): تُرجع قيمة تجزئة للمجموعة الثابتة S بحيث إذا كانequal(S1, S2)hash(S1) = hash(S2)

يمكن تعريف عمليات أخرى للمجموعات التي تحتوي على عناصر من نوع خاص:

  • sum(S): تُعيد مجموع جميع عناصر المجموعة S وفقًا لتعريف معين لـ "المجموع". على سبيل المثال، بالنسبة للأعداد الصحيحة أو الحقيقية، يمكن تعريفها على النحو التالي : .fold(0, add, S)
  • collapse(S): عند إعطاء مجموعة من المجموعات، أعد اتحادها. [ 6 ] على سبيل المثال، collapse({{1}, {2, 3}}) == {1, 2, 3}. يمكن اعتبارها نوعًا من sum.
  • flatten(S): عند إعطاء مجموعة تتكون من مجموعات وعناصر ذرية (عناصر ليست مجموعات)، تُعيد هذه الدالة مجموعةً عناصرها هي العناصر الذرية للمجموعة الأصلية ذات المستوى الأعلى أو عناصر المجموعات التي تحتويها. بعبارة أخرى، تُزيل مستوىً من التداخل - مثل `[1]` - collapse,ولكن مع السماح بالعناصر الذرية. يمكن القيام بذلك مرة واحدة، أو عن طريق تسطيح متكرر للحصول على مجموعة من العناصر الذرية فقط. [ 7 ] على سبيل المثال، flatten({1, {2, 3}}) == {1, 2, 3}.
  • nearest(S,x): تُرجع العنصر من S الأقرب قيمة إلى x (بحسب مقياس معين ).
  • min(S)، : تُرجع أصغر/أكبر عنصر في المجموعة S.max(S)

التطبيقات

يمكن تنفيذ المجموعات باستخدام هياكل بيانات متنوعة ، توفر مفاضلات مختلفة بين الوقت والمساحة للعمليات المختلفة. صُممت بعض هذه التنفيذات لتحسين كفاءة عمليات متخصصة للغاية، مثل nearestالدمج والحذف union. أما التنفيذات المصنفة على أنها "للاستخدام العام" فتسعى عادةً إلى تحسين عمليات الدمج element_ofوالحذف addوالتجزئة delete. يتمثل أحد التنفيذات البسيطة في استخدام قائمة ، مع تجاهل ترتيب العناصر والحرص على تجنب القيم المتكررة. هذا التنفيذ بسيط ولكنه غير فعال، لأن عمليات مثل تحديد عضوية المجموعة أو حذف عنصر ما تستغرق وقتًا من رتبة O ( n )، حيث تتطلب مسح القائمة بأكملها. [ ب ] غالبًا ما تُنفذ المجموعات باستخدام هياكل بيانات أكثر كفاءة، لا سيما أنواع مختلفة من الأشجار أو جداول التجزئة .

بما أن المجموعات يمكن تفسيرها كنوع من الخرائط (بواسطة دالة المؤشر)، فإنها تُنفذ عادةً بنفس طريقة الخرائط (الجزئية) ( المصفوفات الترابطية ) - حيث تكون قيمة كل زوج من المفتاح والقيمة إما من النوع الواحد أو قيمة حارس (مثل 1) - أي شجرة بحث ثنائية متوازنة ذاتيًا للمجموعات المرتبة (والتي يكون زمنها O(log n) لمعظم العمليات)، أو جدول تجزئة للمجموعات غير المرتبة (والذي يكون زمنه O(1) في المتوسط، ولكن O(n) في أسوأ الحالات، لمعظم العمليات). ويمكن استخدام جدول تجزئة خطي مرتب [ 8 ] لتوفير مجموعات مرتبة ترتيبًا حتميًا.

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

my %elements = map { $_ => 1 } @elements ;

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

يمكن تنفيذ عمليات المجموعات المنطقية باستخدام عمليات أبسط ( popمثل clearدمج المجموعات add)، ولكن قد تُحقق الخوارزميات المتخصصة حدودًا زمنية تقاربية أقل. على سبيل المثال، إذا تم تنفيذ المجموعات كقوائم مُرتبة، فإن الخوارزمية البسيطة لدمج المجموعات ستستغرق وقتًا يتناسب مع طول المجموعة S مضروبًا في طول المجموعة T ؛ بينما ستُنجز إحدى خوارزميات دمج القوائم المهمة في وقت يتناسب مع m + n . علاوة على ذلك، توجد هياكل بيانات مجموعات متخصصة (مثل هيكل بيانات الاتحاد والبحث ) مُحسَّنة لواحدة أو أكثر من هذه العمليات، على حساب عمليات أخرى.union(S,T)

الدعم اللغوي

كانت لغة باسكال من أوائل اللغات التي تدعم المجموعات ؛ وتتضمنها الآن العديد من اللغات، سواء في اللغة الأساسية أو في مكتبة قياسية .

  • في لغة C++ ، توفر مكتبة القوالب القياسيةset (STL) فئة القالب، والتي تُنفذ عادةً باستخدام شجرة بحث ثنائية (مثل شجرة الأحمر والأسود ). كما توفر مكتبة STL الخاصة بشركة SGIhash_set فئة القالب التي تُنفذ مجموعة باستخدام جدول تجزئة. يدعم C++11unordered_set فئة القالب هذه، والتي تُنفذ باستخدام جدول تجزئة. في المجموعات، تُعد العناصر نفسها هي المفاتيح، على عكس الحاويات المتسلسلة، حيث يتم الوصول إلى العناصر باستخدام موضعها (النسبي أو المطلق). يجب أن يكون لعناصر المجموعة ترتيب ضعيف صارم.
  • توفر مكتبة Rust القياسيةHashSet الأنواع العامة BTreeSet.
  • توفر لغة جافا Setواجهة لدعم المجموعات (مع HashSetالفئة التي تنفذها باستخدام جدول تجزئة)، SortedSetوالواجهة الفرعية لدعم المجموعات المرتبة (مع TreeSetالفئة التي تنفذها باستخدام شجرة بحث ثنائية).
  • يوفر إطار عمل Foundation من Apple (جزء من Cocoa ) فئات Objective-C التاليةNSSet : NSMutableSetو NSCountedSetو NSOrderedSetو و NSMutableOrderedSet. وتوفر واجهات برمجة تطبيقات CoreFoundation أنواع CFSet و CFMutableSet للاستخدام في لغة C.
  • يحتوي بايثون على أنواع setمدمجةfrozenset منذ الإصدار 2.4، ومنذ الإصدارين 3.0 و2.7، يدعم القيم الحرفية للمجموعات غير الفارغة باستخدام صيغة الأقواس المعقوفة، على سبيل المثال: {x, y, z}; يجب إنشاء المجموعات الفارغة باستخدام set()، لأن بايثون يستخدم {}لتمثيل القاموس الفارغ.
  • يوفر إطار عمل .NET الفئات العامة التي تنفذHashSet الواجهة SortedSetالعامة ISet.
  • تتضمن مكتبة فئات SmalltalkSet كلاً من `and` و` IdentitySetand`، حيث تستخدم `alquality` و`include` لاختبار التضمين على التوالي. توفر العديد من اللهجات صيغًا مختلفة للتخزين المضغوط ( NumberSet``, CharacterSet``)، وللترتيب (` OrderedSet`, SortedSet``, إلخ)، أو للمراجع الضعيفة (` WeakIdentitySet`).
  • تتضمن المكتبة القياسية للغة روبيset وحدة تحتوي على Setفئات SortedSetتقوم بتنفيذ المجموعات باستخدام جداول التجزئة، وتسمح الأخيرة بالتكرار بترتيب تصاعدي.
  • تحتوي المكتبة القياسية لـ OCamlSet على وحدة نمطية تقوم بتنفيذ بنية بيانات مجموعة وظيفية باستخدام أشجار البحث الثنائية.
  • يوفر تطبيق GHC للغة Haskell وحدةData.Set نمطية تقوم بتنفيذ المجموعات غير القابلة للتغيير باستخدام أشجار البحث الثنائية. [ 9 ]
  • توفر حزمة Tcl Tcllib وحدة نمطية تقوم بتنفيذ بنية بيانات مجموعة تعتمد على قوائم TCL.
  • تحتوي مكتبة Swift القياسية على Setنوع، منذ Swift 1.2.
  • تم تقديم JavaScriptSet ككائن مدمج قياسي مع معيار ECMAScript 2015 [ 10 ] .
  • تحتوي المكتبة القياسية لـ Erlangsets على وحدة نمطية.
  • تحتوي لغة Clojure على صيغة حرفية للمجموعات المجزأة، كما أنها تنفذ المجموعات المصنفة.
  • يدعم برنامج LabVIEW المجموعات بشكل أصلي، بدءًا من الإصدار 2019.
  • توفر آداAda.Containers.Hashed_Sets الحزم والملفات Ada.Containers.Ordered_Sets.

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

مجموعة متعددة

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

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

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

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

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

العمليات النموذجية على الحقائب:

  • contains(B, x): يتحقق مما إذا كان العنصر x موجودًا (مرة واحدة على الأقل) في الحقيبة B
  • is_sub_bag(B1, B2): يتحقق مما إذا كان كل عنصر في الحقيبة B 1 يظهر في B 1 ليس أكثر من ظهوره في الحقيبة B 2 ؛ ويشار إليه أحيانًا باسم B 1B 2 .
  • count(B, x): تُرجع عدد مرات ظهور العنصر x في الحقيبة B ؛ ويُشار إليها أحيانًا بـ B # x .
  • scaled_by(B, n): بالنظر إلى عدد طبيعي n ، تُرجع حقيبة تحتوي على نفس العناصر الموجودة في الحقيبة B ، باستثناء أن كل عنصر يظهر m مرة في B يظهر n * m مرة في الحقيبة الناتجة؛ ويشار إليه أحيانًا بـ nB.
  • union(B1, B2): تُرجع حقيبة تحتوي فقط على تلك القيم التي تظهر إما في الحقيبة B 1 أو الحقيبة B 2 ، باستثناء أن عدد مرات ظهور القيمة x في الحقيبة الناتجة يساوي ( B 1 # x) + ( B 2 # x)؛ ويُشار إليها أحيانًا بـ B 1B 2 .

المجموعات المتعددة في لغة SQL

في قواعد البيانات العلائقية ، يمكن أن يكون الجدول مجموعة (رياضية) أو مجموعة متعددة، اعتمادًا على وجود قيود التفرد على بعض الأعمدة (مما يحوله إلى مفتاح مرشح ).

يسمح SQL بتحديد الصفوف من جدول علائقي: ستؤدي هذه العملية بشكل عام إلى مجموعة متعددة، ما لم DISTINCTيتم استخدام الكلمة الرئيسية لإجبار الصفوف على أن تكون جميعها مختلفة، أو يتضمن التحديد المفتاح الأساسي (أو مفتاح مرشح).

في لغة ANSI SQL، يمكن استخدام الكلمة MULTISETالمفتاحية لتحويل استعلام فرعي إلى تعبير مجموعة:

حدد التعبير 1 ، والتعبير 2 ... من اسم الجدول ...

عبارة SELECT عامة يمكن استخدامها كتعبير استعلام فرعي لاستعلام آخر أكثر عمومية، بينما

MULTISET ( SELECT expression1 , expression2 ... FROM table_name ...)

يحول الاستعلام الفرعي إلى تعبير مجموعة يمكن استخدامه في استعلام آخر، أو في تعيينه لعمود من نوع المجموعة المناسب.

انظر أيضاً

ملحوظات

  1. على سبيل المثال، في لغة بايثون،pickيمكن تنفيذ ذلك على فئة مشتقة من الفئة المدمجةsetعلى النحو التالي:
    class Set ( set ): def pick ( self ): return next ( iter ( self ))
  2. يمكن إدخال العنصر في وقت O (1) ببساطة عن طريق الإدخال في النهاية، ولكن إذا تجنب المرء التكرارات، فإن هذا يستغرق وقتًا قدره O ( n ).

مراجع

  1. بايثون: pop()
  2. إدارة ومعالجة هياكل البيانات المعقدة: ورشة العمل الثالثة حول نظم المعلومات والذكاء الاصطناعي، هامبورغ، ألمانيا، 28 فبراير - 2 مارس 1994. وقائع المؤتمر، تحرير كاي فون لوك، هاينز ماربورغر، ص 76
  3. مشكلة بايثون رقم 7212 : استرجاع عنصر عشوائي من مجموعة دون حذفه؛ راجع الرسالة رقم 106593 بخصوص الاسم القياسي
  4. ميزة روبي: إضافة Set#pick و Set#pop
  5. التركيب الاستقرائي للبرامج الوظيفية: التخطيط الشامل، وطي البرامج المحدودة، وتجريد المخططات عن طريق الاستدلال القياسي، أوتي شميد ، سبرينغر، 21 أغسطس 2003، ص 240
  6. الاتجاهات الحديثة في تحديد أنواع البيانات: ورشة العمل العاشرة حول تحديد أنواع البيانات المجردة بالاشتراك مع ورشة عمل COMPASS الخامسة، سانتا مارغريتا، إيطاليا، 30 مايو - 3 يونيو 1994. أوراق مختارة، المجلد 10، تحرير إيجيديو أستيسيانو، جيانا ريجيو، أندريه تارليكي، ص 38
  7. روبي: flatten()
  8. وانغ، توماس (1997)، جدول التجزئة الخطي المصنف ، مؤرشف من الأصل في 12 يناير 2006
  9. ستيفن آدامز، " المجموعات الفعالة: عملية موازنة " ، مجلة البرمجة الوظيفية 3(4):553-562، أكتوبر 1993. تم الاطلاع عليه في 2015-03-11.
  10. "مواصفات لغة ECMAScript 2015 - ECMA-262 الإصدار السادس" . www.ecma-international.org . تاريخ الاطلاع: 11 يوليو 2017 .