Set (abstract data type)
In computer science, a set is an abstract data type that can store distinct values, without any particular order. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set.
Some set data structures are designed for static or frozen sets that do not change after they are constructed. Static sets allow only query operations on their elements — such as checking whether a given value is in the set, or enumerating the values in some arbitrary order. Other variants, called dynamic or mutable sets, allow also the insertion and deletion of elements from the set.
A multiset is a special kind of set in which an element can appear multiple times in the set.
Type theory
In type theory, sets are generally identified with their indicator function (characteristic function): accordingly, a set of values of type may be denoted by or . (Subtypes and subsets may be modeled by refinement types, and quotient sets may be replaced by setoids.) The characteristic function of a set is defined as:
In theory, many other abstract data structures can be viewed as set structures with additional operations and/or additional axioms imposed on the standard operations. For example, an abstract heap can be viewed as a set structure with a min(S) operation that returns the element of smallest value.
Operations
Core set-theoretical operations
One may define the operations of the algebra of sets:
union(S,T): returns the union of sets S and T.intersection(S,T): returns the intersection of sets S and T.difference(S,T): returns the difference of sets S and T.subset(S,T): a predicate that tests whether the set S is a subset of set T.
Static sets
Typical operations that may be provided by a static set structure S are:
is_element_of(x,S): checks whether the value x is in the set S.is_empty(S): checks whether the set S is empty.size(S)orcardinality(S): returns the number of elements in 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 من S، لبعض العمليات الثنائية F. يجب أن تكون F تجميعية وتبديلية حتى يكون هذا مُعرّفًا جيدًا.Ai+1 := F(Ai, e)clear(S): حذف جميع عناصر S .equal(S1', S2'): يتحقق مما إذا كانت المجموعتان المعطيتان متساويتين (أي تحتويان على جميع العناصر نفسها فقط).hash(S): returns a hash value for the static set S such that ifequal(S1, S2)thenhash(S1) = hash(S2)
Other operations can be defined for sets with elements of a special type:
sum(S): returns the sum of all elements of S for some definition of "sum". For example, over integers or reals, it may be defined asfold(0, add, S).collapse(S): given a set of sets, return the union.[6] For example,collapse({{1}, {2, 3}}) == {1, 2, 3}. May be considered a kind ofsum.flatten(S): given a set consisting of sets and atomic elements (elements that are not sets), returns a set whose elements are the atomic elements of the original top-level set or elements of the sets it contains. In other words, remove a level of nesting – likecollapse,but allow atoms. This can be done a single time, or recursively flattening to obtain a set of only atomic elements.[7] For example,flatten({1, {2, 3}}) == {1, 2, 3}.nearest(S,x): returns the element of S that is closest in value to x (by some metric).min(S),max(S): returns the minimum/maximum element of S.
Implementations
Sets can be implemented using various data structures, which provide different time and space trade-offs for various operations. Some implementations are designed to improve the efficiency of very specialized operations, such as nearest or union. Implementations described as "general use" typically strive to optimize the element_of, add, and delete operations. A simple implementation is to use a list, ignoring the order of the elements and taking care to avoid repeated values. This is simple but inefficient, as operations like set membership or element deletion are O(n), as they require scanning the entire list.[b] Sets are often instead implemented using more efficient data structures, particularly various flavors of trees, tries, or hash tables.
As sets can be interpreted as a kind of map (by the indicator function), sets are commonly implemented in the same way as (partial) maps (associative arrays) – in this case in which the value of each key-value pair has the unit type or a sentinel value (like 1) – namely, a self-balancing binary search tree for sorted sets (which has O(log n) for most operations), or a hash table for unsorted sets (which has O(1) average-case, but O(n) worst-case, for most operations). A sorted linear hash table[8] may be used to provide deterministically ordered sets.
Further, in languages that support maps but not sets, sets can be implemented in terms of maps. For example, a common programming idiom in Perl that converts an array to a hash whose values are the sentinel value 1, for use as a set, is:
my%elements=map{$_=>1}@elements;Other popular methods include arrays. In particular a subset of the integers 1..n can be implemented efficiently as an n-bit bit array, which also support very efficient union and intersection operations. A Bloom map implements a set probabilistically, using a very compact representation but risking a small chance of false positives on queries.
The Boolean set operations can be implemented in terms of more elementary operations (pop, clear, and add), but specialized algorithms may yield lower asymptotic time bounds. If sets are implemented as sorted lists, for example, the naive algorithm for union(S,T) will take time proportional to the length m of S times the length n of T; whereas a variant of the list merging algorithm will do the job in time proportional to m+n. Moreover, there are specialized set data structures (such as the union-find data structure) that are optimized for one or more of these operations, at the expense of others.
Language support
One of the earliest languages to support sets was Pascal; many languages now include it, whether in the core language or in a standard library.
- In C++, the Standard Template Library (STL) provides the
settemplate class, which is typically implemented using a binary search tree (e.g. red–black tree); SGI's STL also provides thehash_settemplate class, which implements a set using a hash table. C++11 has support for theunordered_settemplate class, which is implemented using a hash table. In sets, the elements themselves are the keys, in contrast to sequenced containers, where elements are accessed using their (relative or absolute) position. Set elements must have a strict weak ordering. - The Rust standard library provides the generic
HashSetandBTreeSettypes. - توفر لغة جافا
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. - تتضمن مكتبة فئات Smalltalk
Setكلاً من `and` و`IdentitySetand`، حيث تستخدم `alquality` و`include` لاختبار التضمين على التوالي. توفر العديد من اللهجات صيغًا مختلفة للتخزين المضغوط (NumberSet``,CharacterSet``)، وللترتيب (`OrderedSet`,SortedSet``, إلخ)، أو للمراجع الضعيفة (`WeakIdentitySet`). - تتضمن المكتبة القياسية للغة روبي
setوحدة تحتوي علىSetفئاتSortedSetتقوم بتنفيذ المجموعات باستخدام جداول التجزئة، وتسمح الأخيرة بالتكرار بترتيب مُرتب. - تحتوي المكتبة القياسية لـ OCaml
Setعلى وحدة نمطية تقوم بتنفيذ بنية بيانات مجموعة وظيفية باستخدام أشجار البحث الثنائية. - يوفر تطبيق GHC للغة Haskell وحدة
Data.Setنمطية تقوم بتنفيذ المجموعات غير القابلة للتغيير باستخدام أشجار البحث الثنائية. [ 9 ] - توفر حزمة Tcl Tcllib وحدة نمطية تقوم بتنفيذ بنية بيانات مجموعة تعتمد على قوائم TCL.
- تحتوي مكتبة Swift القياسية على
Setنوع، منذ Swift 1.2. - تم تقديم JavaScript
Setككائن مدمج قياسي مع معيار ECMAScript 2015 [ 10 ] . - تحتوي المكتبة القياسية لـ Erlang
setsعلى وحدة نمطية. - تحتوي لغة Clojure على صيغة حرفية للمجموعات المجزأة، كما أنها تنفذ المجموعات المصنفة.
- يدعم برنامج LabVIEW المجموعات بشكل أصلي، بدءًا من الإصدار 2019.
- توفر آدا
Ada.Containers.Hashed_Setsالحزم والملفاتAda.Containers.Ordered_Sets.
As noted in the previous section, in languages which do not directly support sets but do support associative arrays, sets can be emulated using associative arrays, by using the elements as keys, and using a dummy value as the values, which are ignored.
Multiset
A generalization of the notion of a set is that of a multiset or bag, which is similar to a set but allows repeated ("equal") values (duplicates). This is used in two distinct senses: either equal values are considered identical, and are simply counted, or equal values are considered equivalent, and are stored as distinct items. For example, given a list of people (by name) and ages (in years), one could construct a multiset of ages, which simply counts the number of people of a given age. Alternatively, one can construct a multiset of people, where two people are considered equivalent if their ages are the same (but may be different people and have different names), in which case each pair (name, age) must be stored, and selecting on a given age gives all the people of a given age.
Formally, it is possible for objects in computer science to be considered "equal" under some equivalence relation but still distinct under another relation. Some types of multiset implementations will store distinct equal objects as separate items in the data structure; while others will collapse it down to one version (the first one encountered) and keep a positive integer count of the multiplicity of the element.
As with sets, multisets can naturally be implemented using hash table or trees, which yield different performance characteristics.
The set of all bags over type T is given by the expression bag T. If by multiset one considers equal items identical and simply counts them, then a multiset can be interpreted as a function from the input domain to the non-negative integers (natural numbers), generalizing the identification of a set with its indicator function. In some cases a multiset in this counting sense may be generalized to allow negative values, as in Python.
- C++'s Standard Template Library implements both sorted and unsorted multisets. It provides the
multisetclass for the sorted multiset, as a kind of associative container, which implements this multiset using a self-balancing binary search tree. It provides theunordered_multisetclass for the unsorted multiset, as a kind of unordered associative container, which implements this multiset using a hash table. The unsorted multiset is standard as of C++11; previously SGI's STL provides thehash_multisetclass, which was copied and eventually standardized. - For Java, third-party libraries provide multiset functionality:
- Apache Commons Collections provides the
BagandSortedBaginterfaces, with implementing classes likeHashBagandTreeBag. - Google Guava provides the
Multisetinterface, with implementing classes likeHashMultisetandTreeMultiset.
- Apache Commons Collections provides the
- Apple provides the
NSCountedSetclass as part of Cocoa, and theCFBagandCFMutableBagtypes as part of CoreFoundation. - Python's standard library includes
collections.Counter, which is similar to a multiset. - Smalltalk includes the
Bagclass, which can be instantiated to use either identity or equality as predicate for inclusion test.
Where a multiset data structure is not available, a workaround is to use a regular set, but override the equality predicate of its items to always return "not equal" on distinct objects (however, such will still not be able to store multiple occurrences of the same object) or use an associative array mapping the values to their integer multiplicities (this will not be able to distinguish between equal elements at all).
Typical operations on bags:
contains(B, x): checks whether the element x is present (at least once) in the bag Bis_sub_bag(B1, B2): checks whether each element in the bag B1 occurs in B1 no more often than it occurs in the bag B2; sometimes denoted as B1 ⊑ B2.count(B, x): returns the number of times that the element x occurs in the bag B; sometimes denoted as B # x.scaled_by(B, n): given a natural numbern, returns a bag which contains the same elements as the bag B, except that every element that occurs m times in B occurs n * m times in the resulting bag; sometimes denoted as n ⊗ B.union(B1, B2): returns a bag containing just those values that occur in either the bag B1 or the bag B2, except that the number of times a value x occurs in the resulting bag is equal to (B1 # x) + (B2 # x); sometimes denoted as B1 ⊎ B2.
Multisets in SQL
في قواعد البيانات العلائقية ، يمكن أن يكون الجدول مجموعة (رياضية) أو مجموعة متعددة، اعتمادًا على وجود قيود التفرد على بعض الأعمدة (مما يحوله إلى مفتاح مرشح ).
يسمح SQL بتحديد الصفوف من جدول علائقي: ستؤدي هذه العملية بشكل عام إلى مجموعة متعددة، ما لم DISTINCTيتم استخدام الكلمة الرئيسية لإجبار الصفوف على أن تكون جميعها مختلفة، أو يتضمن التحديد المفتاح الأساسي (أو مفتاح مرشح).
في لغة ANSI SQL، يمكن استخدام الكلمة MULTISETالمفتاحية لتحويل استعلام فرعي إلى تعبير مجموعة:
حدد التعبير 1 ، والتعبير 2 ... من اسم الجدول ...عبارة SELECT عامة يمكن استخدامها كتعبير استعلام فرعي لاستعلام آخر أكثر عمومية، بينما
MULTISET ( SELECT expression1 , expression2 ... FROM table_name ...)يحول الاستعلام الفرعي إلى تعبير مجموعة يمكن استخدامه في استعلام آخر، أو في تعيينه لعمود من نوع المجموعة المناسب.
انظر أيضاً
ملحوظات
- ↑ على سبيل المثال، في لغة بايثون،
pickيمكن تنفيذ ذلك على فئة مشتقة من الفئة المدمجةsetعلى النحو التالي:class Set ( set ): def pick ( self ): return next ( iter ( self ))
- ↑ يمكن إدخال العنصر في وقت O (1) ببساطة عن طريق الإدخال في النهاية، ولكن إذا تجنب المرء التكرارات، فإن هذا يستغرق وقتًا قدره O ( n ).
مراجع
- ↑ بايثون: pop()
- ↑ إدارة ومعالجة هياكل البيانات المعقدة: ورشة العمل الثالثة حول نظم المعلومات والذكاء الاصطناعي، هامبورغ، ألمانيا، 28 فبراير - 2 مارس 1994. وقائع المؤتمر، تحرير كاي فون لوك، هاينز ماربورغر، ص 76
- ↑ مشكلة بايثون رقم 7212 : استرجاع عنصر عشوائي من مجموعة دون حذفه؛ راجع الرسالة رقم 106593 بخصوص الاسم القياسي
- ↑ ميزة روبي: إضافة Set#pick و Set#pop
- ↑ التركيب الاستقرائي للبرامج الوظيفية: التخطيط الشامل، وطي البرامج المحدودة، وتجريد المخططات عن طريق الاستدلال القياسي، أوتي شميد ، سبرينغر، 21 أغسطس 2003، ص 240
- ↑ الاتجاهات الحديثة في تحديد أنواع البيانات: ورشة العمل العاشرة حول تحديد أنواع البيانات المجردة بالاشتراك مع ورشة عمل COMPASS الخامسة، سانتا مارغريتا، إيطاليا، 30 مايو - 3 يونيو 1994. أوراق مختارة، المجلد 10، تحرير إيجيديو أستيسيانو، جيانا ريجيو، أندريه تارليكي، ص 38
- ↑ روبي: flatten()
- ↑ وانغ، توماس (1997)، جدول التجزئة الخطي المصنف ، مؤرشف من الأصل في 12 يناير 2006
- ↑ ستيفن آدامز، " المجموعات الفعالة: عملية موازنة " ، مجلة البرمجة الوظيفية 3(4):553-562، أكتوبر 1993. تم الاطلاع عليه في 2015-03-11.
- ↑ "مواصفات لغة ECMAScript 2015 - ECMA-262 الإصدار السادس" . www.ecma-international.org . تاريخ الاطلاع: 11 يوليو 2017 .
- أنواع البيانات
- أنواع البيانات المركبة
- أنواع البيانات المجردة
