مقارنة عدة طرق للحكم على نفس عناصر hashmap و hashset و treemap و treeset في جافا
1.1 هاشماب
دعونا أولاً نلقي نظرة على كيفية تخزين العناصر في HashMap. كل عنصر مخزّن في الخريطة عبارة عن زوج من القيمة الرئيسية مثل القيمة الرئيسية ، ويتم إضافته من خلال طريقة PUT. بالإضافة إلى ذلك ، لن يكون للمفتاح نفسه سوى قيمة مرتبطة بها في الخريطة. يتم تعريف طريقة وضع في الخريطة على النحو التالي.
v put (k key ، v value) ؛
يتم استخدامه لتخزين زوج القيمة الرئيسية مثل القيمة الرئيسية. قيمة الإرجاع هي القيمة القديمة المخزنة في الخريطة بواسطة المفتاح. إذا لم يكن موجودًا من قبل ، فسوف يعود فارغًا. هذه هي الطريقة التي يتم بها تنفيذ طريقة وضع hashmap.
public v put (k key ، v value) {if (key == null) return putfornullkey (value) ؛ int hash = hash (مفتاح) ؛ int i = indexfor (hash ، table.length) ؛ لـ (الإدخال <k ، v> e = table [i] ؛ e! = null ؛ e = e.next) {object k ؛ if ( e.value = القيمة ؛ eRecordAccess (هذا) ؛ إرجاع Oldvalue ؛ }} modcount ++ ؛ addentry (التجزئة ، المفتاح ، القيمة ، i) ؛ العودة لاغية. }مما سبق يمكننا أن نرى أنه عند إضافة مجموعة قيمة المفاتيح المقابلة ، إذا كان المفتاح المقابل موجودًا بالفعل ، فسيتم تغيير القيمة المقابلة مباشرةً وسيتم إرجاع القيمة القديمة. عند الحكم على ما إذا كان المفتاح موجودًا ، تتم مقارنة رمز الهاوية للمفتاح أولاً ، ثم تتم مقارنة ترميز المفتاح مع متساوٍ أو متساوٍ. قد لا نتمكن من رؤيته هنا. من الكود أعلاه ، نقارن hashcode من map.entry و hashcode من المفتاح. في الواقع ، يمكننا أن نرى أن map.entry hashcode هو في الواقع hashcode لمفتاحه. إذا لم يكن المفتاح المقابل موجودًا في الأصل ، فسيتم استدعاء Addentry لإضافة قيمة المفتاح المقابلة إلى الخريطة. تجزئة المعلمة التي تم تمريرها بواسطة Addentry هي hashcode المقابلة للمفتاح. بعد ذلك ، دعونا نلقي نظرة على تعريف طريقة الإضافات.
addentry void (int hash ، k key ، v value ، int bucketIndex) {if ((size> = threshold) && (null! = table [bucketIndex])) {تغيير حجم (2 * table.length) ؛ hash = (null! = مفتاح)؟ التجزئة (مفتاح): 0 ؛ bucketIndex = indexfor (hash ، table.length) ؛ } createentry (hash ، key ، value ، bucketIndex) ؛ } void createentry (int hash ، k key ، v value ، int bucketIndex) {entry <k ، v> e = table [bucketIndex] ؛ الجدول [bucketIndex] = إدخال جديد <> (التجزئة ، المفتاح ، القيمة ، E) ؛ حجم ++ ؛ }جوهر الإضافات هو استدعاء Createentry لإنشاء خريطة. كائن entry الذي يمثل قيمة المفاتيح المقابلة وتخزينها. من الواضح أن الجدول أعلاه عبارة عن مجموعة من الخريطة. map.entry يستخدم تجزئة خاصية لحفظ رمز hashcode للمفتاح المقابل. دعنا نلقي نظرة على مُنشئ الخريطة.
إدخال (int h ، k k ، v v ، entry <k ، v> n) {value = v ؛ التالي = ن ؛ المفتاح = k ؛ التجزئة = ح ؛ }من الواضح أنه يحفظ رمز التجزئة المقابل للمفتاح والقيمة والمفتاح المقابل.
بعد فهم كيفية تخزين HashMap عناصر ، من الأسهل معرفة كيف يخزن HashMap عناصر. هناك طريقتان رئيسيتان في hashmap لتحديد ما إذا كانت العناصر هي نفسها. أحدهما هو تحديد ما إذا كان المفتاح هو نفسه ، والآخر هو تحديد ما إذا كانت القيمة هي نفسها. في الواقع ، عند تقديم عناصر HashMap ، قدمنا كيف يحدد HashMap ما إذا كان مفتاح العنصر هو نفسه. وهذا هو ، أولاً وقبل كل شيء ، هو رمز الهاش هو نفسه ، وثانياً ، المفاتيح متساوية أو متساوية. إن تحديد ما إذا كان المفتاح هو نفسه في الخريطة يتم من خلال طريقة contekekey () ، وتنفيذها في hashmap كما يلي.
يحتوي Boolean العام على KEYKEY (مفتاح الكائن) {return getentry (key)! = null ؛ } الإدخال النهائي <k ، v> getentry (مفتاح الكائن) {int hash = (key == null)؟ 0: التجزئة (المفتاح) ؛ لـ (الإدخال <k ، v> e = table [indexfor (hash ، table.length)] ؛ e! = null ؛ e = e.next) {object k ؛ if ( } إرجاع فارغ ؛ }من الواضح أنه يحدد أولاً ما إذا كان رمز hashcode للمفتاح هو نفسه ، ثم يحدد ما إذا كان المفتاح متساويًا أو يساويًا.
يتم الحكم على القيمة المستخدمة في الخريطة بواسطة طريقة ContainSvalue ، وتنفيذها في HashMap كما يلي.
يحتوي Boolean العام على Value (قيمة الكائن) {if (value == null) الإرجاع يحتوي على قيمة () ؛ إدخال [] علامة التبويب = جدول ؛ لـ (int i = 0 ؛ i <tab.length ؛ i ++) لـ (الإدخال e = tab [i] ؛ e! = null ؛ e = e.next) if (value.equals (e.value)) return true ؛ العودة كاذبة }من الواضح أن قيمة النموذج غير الفني يتم الحكم عليها من خلال المساواة بين القيمة ، والنموذج الفارغ هو طالما كان متساوي ، أي أن القيمة في العنصر المحفوظ لاغري.
1.2 HASHSET
بعد معرفة كيفية تخزين HashMap عناصر وتحديد ما إذا كانت العناصر متماثلة ، من الأسهل معرفة كيف تحدد Hashset ما إذا كانت العناصر هي نفسها.
يتم حفظ العناصر الموجودة في Hashset من خلال hashmap. يحمل كل كائن Hashset مرجعًا إلى كائن HashMap المقابل. عند إضافة وحذف عناصر إلى hassset ، يتم تنفيذها من خلال hashmap التي يحتفظ بها. عند حفظ عنصر ما ، سيوفر العنصر المقابل كمفتاح HashMap المعقد. القيمة المقابلة هي كائن ثابت ، لذلك عند حفظه ، فإنها تستخدم منطق تحديد ما إذا كانت العناصر هي نفسها. عند تحديد ما إذا كان يتم تضمين عنصر ما ، فإنه يطلق أيضًا على طريقة Contekey من HashMap الذي تم وضعه لإصدار الأحكام.
يحتوي Boolean العام على (كائن O) {returnmap.containskey (O) ؛ }يمكن للأصدقاء المهتمين الاطلاع على رمز المصدر لشركة Hashset.
1.3 تريماب
يتم طلب العناصر المخزنة في Treemap وفرزها وفقًا للمفتاح. تريماب لديه طريقتان لفرز العناصر المخزنة. أحدهما هو الفرز من خلال المقارنة التي يحتفظ بها ، والآخر هو الفرز من خلال المفتاح الذي ينفذ الواجهة المماثلة. الطريقة الأولى مفضلة. عندما يكون المقارن المعقد (الافتراضي هو فارغ) ، يتم استخدام الطريقة الثانية. يحتوي Treemap على العديد من المنشآت ، يمكن من خلالها تهيئة المقارنة التي يحملها. دعونا نلقي نظرة أولاً على كيفية حفظ Treemap عناصر. يتم تنفيذ طريقة وضع على النحو التالي.
public v put (k key ، v value) {entry <k ، v> t = root ؛ if (t == null) {compare (key ، key) ؛ // type (و null null) check root = new entry <> (المفتاح ، القيمة ، فارغة) ؛ الحجم = 1 ؛ modcount ++ ؛ العودة لاغية. } int cmp ؛ الدخول <K ، V> Parent ؛ // المقارنة المقارنة والمسارات المماثلة المقارنة <؟ Super K> cpr = المقارنة ؛ if (cpr! = null) {do {parent = t ؛ cmp = cpr.compare (مفتاح ، t.key) ؛ if (cmp <0) t = t.left ؛ elseif (cmp> 0) t = t.right ؛ عودة أخرى T.SetValue (القيمة) ؛ } بينما (t! = null) ؛ } آخر {if (key == null) remrownew nullpointerxception () ؛ قابلة للمقارنة <؟ Super K> k = (قابلة للمقارنة <؟ super k>) مفتاح ؛ do {parent = t ؛ cmp = k.compareto (t.key) ؛ if (cmp <0) t = t.left ؛ elseif (cmp> 0) t = t.right ؛ عودة أخرى T.SetValue (القيمة) ؛ } بينما (t! = null) ؛ } الإدخال <k ، v> e = إدخال جديد <> (المفتاح ، القيمة ، الأصل) ؛ if (cmp <0) parent.left = e ؛ else parent.right = e ؛ fixafterinsertion (e) ؛ حجم ++ ؛ modcount ++ ؛ العودة لاغية. }من التنفيذ أعلاه ، يمكننا أن نرى أنه سيتم تخزين العنصر الأول مباشرة. تنقسم العناصر التالية إلى حالتين ، إحداها هي الحالة التي لا يكون فيها المقارن غير فارغ ، والآخر هو الحالة التي يكون فيها المقارنة فارغة. عندما لا يكون المقارن فارغًا ، سيحدد المقارنة موقع العنصر المخزن. أحد الأشياء المهمة هو أنه عندما تكون نتيجة مقارنة مفتاح العنصر الحالي بمفتاح العنصر المخزن الحالي 0 ، سيتم اعتبار أن مفتاح العنصر المخزن حاليًا موجود بالفعل في الخريطة الأصلية ، ثم يتم تغيير القيمة المقابلة للمفتاح الأصلي إلى القيمة الجديدة ، ثم يتم إرجاع القيمة القديمة مباشرة. عندما يكون المقارن المعقد فارغًا ، سيتم تحديد موقع العنصر بواسطة طريقة المقارنة للمفتاح الذي ينفذ الواجهة المماثلة. شيء واحد مشابه لاستخدام المقارنة هو أنه عند مقارنة المفتاح الأصلي بالمفتاح المخزن حديثًا 0 ، سيتم اعتبار أن المفتاح المخزّن حديثًا موجود بالفعل في الخريطة الأصلية ، ولن يتم تغيير قيمة المفتاح الأصلي المقابل مباشرة ، ولن يتم تخزين زوج القيمة المفتاح. في الواقع ، فإن منطق التنفيذ الرئيسي لطريقة ConteKey التي تحدد ما إذا كان العنصر موجودًا متشابهًا ، والتنفيذ المحدد كما يلي.
يحتوي Boolean العام على KEYKEY (مفتاح الكائن) {return getentry (key)! = null ؛ } الإدخال النهائي <k ، v> getentry (مفتاح الكائن) {// إلغاء التحميل ، الإصدار المستند إلى المقارنة من أجل الأداء إذا كانت (المقارنة! = null) return getentryusingComparator (key) ؛ if (key == null) remrownew nullpointerxception () ؛ قابلة للمقارنة <؟ Super K> k = (قابلة للمقارنة <؟ super k>) مفتاح ؛ الدخول <k ، v> p = root ؛ بينما (p! = null) {int cmp = k.compareto (p.key) ؛ if (cmp <0) p = p.left ؛ elseif (cmp> 0) p = p.right ؛ عودة أخرى P ؛ } إرجاع فارغ ؛ }نظرًا لأن منطق Treemap لتحديد ما إذا كان هناك عنصر ما هو تحديد ما إذا كانت النتيجة بعد المقارنة أو المقارنة هي 0 ، يجب أن نكون حذرين بشكل خاص عند استخدام Treemap لتنفيذ بعض المنطق المشابه للعنصر المساواة.
يحتوي منطق Treemap على القياس هو تحديد ما إذا كانت القيمة المقابلة متساوية؟ على غرار hashmap. يمكن للأصدقاء المهتمين التحقق من الكود المصدري لـ Treemap.
1.4 Treeset
Treeset هو أيضا تنفيذ مجموعة. لا تتكرر العناصر المخزنة ويتم طلبها. بشكل افتراضي ، يجب أن تنفذ العناصر المخزنة الواجهة المماثلة ، لأنه بشكل افتراضي ، سيتم مقارنة العناصر ككائنات قابلة للمقارنة. يمكن أيضًا استخدام Treeset لمقارنة العناصر المخزنة من خلال المقارنة. يمكن تحقيق ذلك عن طريق تمرير كائن مقارن أو treemap يحمل كائن المقارنة عند بناء مجموعة من الأشجار. يشبه تنفيذ Treeset لتطبيق Hashset. كما أنه يحمل إشارة إلى خريطة ، لكنه لا يشير إلى hashmap ، ولكن Treemap. يتم تنفيذ إضافة وحذف العناصر في Treeset بواسطة Treemap الذي يحملونه. لذلك ، على غرار hashset ، فإن طريقة تحديد ما إذا كانت العناصر في Treeset هي نفسها تتوافق مع Treemap ، ويتم تحديدها أيضًا من خلال المقارنة أو قابلة للمقارنة ، بدلاً من طريقة متساوية التقليدية. يمكن للأصدقاء المهتمين التحقق من رمز المصدر لشركة Treeset.
شكرا لك على القراءة ، آمل أن تساعدك. شكرا لك على دعمك لهذا الموقع!