لفترة طويلة ، تكون قائمة البيانات التي يتم استخدامها بشكل متكرر في الكود قائمة بشكل أساسي ، وكلها ArrayList. يبدو أن هذا الشيء يكفي. ArrayList عبارة عن فئة أدوات Wrapper تستخدم لتنفيذ المصفوفات الديناميكية ، بحيث يمكنك عند كتابة رمز ، التكرار والتجارة ، وهو مريح للغاية.
لا أعرف متى بدأت في بدء فصول الأدوات ببطء مثل HashMap و Hashset غالبًا ما تظهر في الكود. يجب أن يقال إن HashMap أكثر شيوعًا ، وهو أيضًا سؤال مقابلة كلاسيكي ، لذلك سأقرأ المزيد منه في الحياة اليومية. عندما بدأت استخدامه لأول مرة ، فهمت ببساطة كجدول مقابل القيمة الرئيسية ، وهو أكثر ملاءمة لاستخدام المفاتيح للعثور على البيانات. بعد مزيد من التحقيق ، اكتشفت ذلك
يحتوي هذا الشيء على بعض الأسرار ، خاصة بعد أن يغير الإصدار الجديد من JDK hashmap إلى شجرة ، والرمز معقد بعض الشيء.
بدأت في استخدام SET أقل ، لكنني وجدت بطريق الخطأ عبارة عن Treeset في رمز. لقد وجدت أن هذا الفصل يمكن أن يأتي بسلاسة. لقد شعرت مثيرًا للاهتمام. اكتشفت تدريجياً أن هذه أداة جيدة أيضًا.
إذا كتبت الكثير من التعليمات البرمجية ، فستشعر بأهمية الأساسيات ، لذلك هنا أكتب مقالة قصيرة لتنظيم بعض المعرفة بإيجاز حول المجموعة.
حسنًا ، دعنا نفرزها لفترة وجيزة:
• القائمة: أي قائمة ، تدعم وظائف المصفوفات والقوائم المرتبطة ، وهي خطي بشكل عام.
• الخريطة: إنه جدول رسم الخرائط ، والذي يخزن العلاقة المقابلة بين المفاتيح والقيم.
• المجموعة: تعني مجموعة ، تستخدم بشكل رئيسي لفرز البيانات والفرز
لنلقي نظرة على القائمة أولاً
القائمة هي نافذة لتخزين البيانات الخطية ، مثل: ArrayList للصفائف و LinkedList للحصول على قوائم مرتبطة.
ArrayList
هذه قائمة صفيف ، لكنها توفر وظيفة التوسع التلقائي لتحقيق واجهة القائمة. يتم الوصول إلى العمليات الخارجية من خلال طريقة إعلان الواجهة ، وهي آمنة ومريحة.
مفتاح ArrayList هو توسيع السعة التلقائي. يمكن تعيين السعة الأولية عند تهيئة الكائن أو يمكن قياس السعة الافتراضية. إذا لم يكن حجم الصفيف واضحًا بشكل خاص ، فلا يمكن تحديد الحجم الأولي. إذا كان الأمر واضحًا ، فيمكن تحديد الحجم ، مما يقلل من التأخر الناجم عن التوسع الديناميكي. الحديث عن هذا ، نحن بحاجة إلى التحدث عن كيفية تنفيذ التوسع. انظر إلى الكود التالي:
Private void Grow (int mincapacity) {// overflow-concious code int oldcapacity = elementData.Length ؛ int newCapacity = OldCapacity + (OldCapacity >> 1) ؛ if (newCapacity - minicapacity <0) newCapacity = mincapacity ؛ if (newCapacity - max_array_size> 0) newCapacity = hugecapacity (mincapacity) ؛ // عادة ما تكون Mincapacity قريبة من الحجم ، لذلك هذا هو الفوز: elementData = Arrays.copyof (ElementData ، NewCapacity) ؛ }Grow هي طريقة تؤدي إلى تشغيل قائمة ArrayList عند إضافة عناصر أو بعض عمليات الفحص السهلة. العملية الرئيسية:
1. احصل على طول الصفيف وحركه بشكل صحيح ، وهو ما يعادل OldCapacity/2 ، واحصل على الطول الجديد
2. إذا كان هذا الطول أقل من الحد الأدنى للسعة ، فمن السهل استخدامه مباشرة.
3. إذا كان أكبر من الحد الأقصى ، خذ أقصى قيمة. سيتم استدعاء طريقة HugeCapacity هنا ، وذلك أساسًا لمقارنة طاقة mincapity مع max_array_size. إذا كانت MinCapacity أكبر من max_array_size ، خذ integer.max_value ، وإلا خذ max_array_size. ومن المثير للاهتمام ، max_array_size يأخذ integer.max_value - 8 ؛ لا أعرف ما هو معنى القيام بذلك
4. أخيرًا ، اتصل بأسلوب النسخ لنسخ الرقم الحالي إلى صفيف جديد.
بسبب عملية النسخ هذه ، إذا كان الصفيف كبيرًا نسبيًا ، فسيتسبب التوسع بالتأكيد في تأخر. لذا ، إذا كنت تعرف الحد الأقصى لقيمة من البداية وكان من السهل النمو إلى هذه القيمة ، فإن تحديد الحجم عند بدء التهيئة سيكون له تأثير معين.
LinkedList
هذه فئة أدوات للقوائم المرتبطة. تتمثل مزايا القوائم المرتبطة في إضافة وحذف الأشياء بشكل أسرع ، لكنهم سيجدونها أبطأ.
بالنسبة للرمز ، يبدو أنه لا يوجد شيء مميز هو أنه مرتبط معًا بسلسلة من المؤشرات. بالطبع ، تستخدم Java الكائنات بدلاً من ذلك لإنشاء كائن عقدة. تشير العقدة نفسها إلى العقدة السابقة والعقدة التالية. هذا هو بنية القائمة المرتبطة:
عقدة الفئة الثابتة الخاصة <e> {e item ؛ العقدة <e> التالية ؛ العقدة <e> prev ؛ العقدة (العقدة <e> prev ، e element ، node <e> next) {this.item = element ؛ this.next = التالي ؛ this.prev = prev ؛ }}ثم استخدم عقدين للإشارة إلى الرأس والذيل ويتم ذلك. الرمز التالي:
/*** مؤشر إلى العقدة الأولى. * ثابت: (أولاً == null && last == null) || * (first.prev == null && first.item! = null) */ node transient <e> first ؛ /*** مؤشر إلى آخر عقدة. * ثابت: (أولاً == null && last == null) || * (last.next == null && last.item! = null) */ node transient <e> last ؛
انظر عملية إضافة:
/*** الروابط E كعنصر آخر. */ void linklast (e e) {final node <e> l = last ؛ العقدة النهائية <e> newNode = new node <> (l ، e ، null) ؛ الأخير = newNode ؛ إذا (l == null) أولاً = newNode ؛ آخر l.next = newNode ؛ حجم ++ ؛ modcount ++ ؛ }الماضي هو:
1. احصل على آخر عقدة ووضعها في L.
2. قم بإنشاء عقدة جديدة وجلب البيانات إلى هذه العقدة. ستشير عملية الإنشاء إلى العقدة الجديدة إلى L ، بحيث تكون متصلة بالسلسلة.
3. ثم تدوم إلى هذه العقدة الجديدة
4. ثم تحديد ما إذا كان l هو لاغ. إذا كان Null Null ، فهذا يعني أنها قائمة مرتبطة فارغة. العقدة الجديدة هي العنصر الأول. وبهذه الطريقة ، يجب أن يشير الأول أيضًا إلى NewNode
5. إذا لم يكن فارغًا ، فقم بإشارة إلى N newNode
6. عداد التراكم
عملية الحذف هي أيضًا العقدة الأمامية والخلفية التي تشير إلى تحريك هذه العقدة.
لنلقي نظرة على الخريطة
الخريطة هي تطبيق لجدول رسم الخرائط للمفاتيح والقيم. فئات التنفيذ الرئيسية: hashmap ، hashtable ، treemap
hashmap و hashtable
HashMap هو الذي يستخدم خوارزمية التجزئة لرسم خرائط القيمة الرئيسية. Hashtable هو فئة آمنة مؤشرات الترابط مع التزامن. هذا هو الفرق الرئيسي بينهما. المبدأ مشابه ، ويتم تحقيقه جميعًا من خلال مجموعة سلسلة دلو +. يتم استخدام الدلو لتخزين المفاتيح ، ويجب تخزين القيمة في قائمة مرتبطة بسبب تصادم التجزئة.
• تكمن أهمية الجرافة في الكفاءة ، ويمكن وضعها في خطوة واحدة من خلال حسابات التجزئة.
• معنى القوائم المرتبطة هو الوصول إلى بيانات التجزئة المتكررة
المبدأ المحدد الذي كتبت "ملاحظات الدراسة: Hashtable و Hashmap" من قبل
لكنني رأيت للتو أن HashMap من JDK1.8 قد غير بنية التخزين الخاصة به واعتماد بنية شجرة حمراء وسوداء. هذا قد يحل كفاءة البحث في القائمة المرتبطة؟ لم تجري دراسة مفصلة.
تريماب
بعد قراءة رمز 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 ؛ آخر إذا (cmp> 0) t = t.right ؛ عودة أخرى T.SetValue (القيمة) ؛ } بينما (t! = null) ؛ } آخر {if (key == null) رمي nullpointerxception () جديدة ؛ suppressWarnings ("غير محدد") قابلة للمقارنة <؟ Super K> k = (قابلة للمقارنة <؟ super k>) مفتاح ؛ do {parent = t ؛ cmp = k.compareto (t.key) ؛ if (cmp <0) t = t.left ؛ آخر إذا (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 ++ ؛ العودة لاغية. }1. تحقق أولا ما إذا كانت عقدة الجذر موجودة. إذا لم يكن موجودًا ، فهذا يعني أنه الجزء الأول من البيانات ويتم استخدامه مباشرة كجذر الشجرة.
2. تحديد ما إذا كان هناك مقارنة. إذا كان هناك ، استخدم المقارنة للعثور على موقع تخزين البيانات. إذا كانت نتيجة إرجاع المقارنة أقل من 0 ، خذ اليسار ، واتخذ اليمين ، وإلا استبدل قيمة العقدة الحالية مباشرة.
3. إذا لم يكن هناك مقارنة ، تتم مقارنة المفتاح مباشرة بمفتاح العقدة. المقارنة هي نفس الطريقة السابقة.
4. الخطوة التالية هي إنشاء عقدة طفل على الوالد الموجود ووضعها في العقد الطفل اليسرى أو اليمنى.
5.
6. معالجة تراكم
سيكون أيضًا مزعجًا بعض الشيء عند إزالة البيانات. بالإضافة إلى حذف البيانات ، تحتاج أيضًا إلى إعادة توازن الأشجار الحمراء والأسود.
بالإضافة إلى ذلك ، يقوم Treemap بتنفيذ واجهة NavigableMap <K ، V> ، لذلك يوفر أيضًا بعض عمليات الإرجاع على مجموعة البيانات.
أخيرًا ، ألق نظرة على المجموعة
يحتوي Set بشكل أساسي على نوعين من التطبيقات: Hashset و Treeset.
Hashset
المعنى الحرفي واضح للغاية ، باستخدام مجموعة من التجزئة. تتمثل سمة هذه المجموعة في استخدام خوارزمية التجزئة لتخزين البيانات ، وبالتالي لا يتم تكرار البيانات والوصول سريع نسبيًا. كيف تم القيام به؟
Boolean Public Add (e e) {return map.put (e ، present) == null ؛ }اتضح أن هناك كائن خريطة. دعونا نلقي نظرة على ما هي الخريطة؟
خريطة hashmap عابرة خاصة <ه ، كائن> ؛
إنه هاشماب. أولئك الذين يعرفون hashmap سوف يفهمون أن مثل هذه البيانات لن تتكرر. نظرًا لأن الكائن نفسه يتم تخزينه كمفتاح عند إيداعه ، فلن توجد نسخة واحدة فقط في HashMap.
بعد فهم هذا وأشياء أخرى ، سوف تفهم جيدًا.
Treeset
يتم استخدام هذه المجموعة لفرز المجموعة ، مما يعني أنه بالإضافة إلى القدرة على فرز الثقيلة ، يمكن أن يكون لها أيضًا وظيفة الفرز الخاصة بها. ولكن بعد النظر إلى مدونة Treeset ، وجدت أنه تم تنفيذه في أساسيات Treemap. بتعبير أدق ، يجب أن تكون فئة مشتقة من NavigableMap. تعتمد Treeset على Treemap دون تحديد الخريطة بشكل افتراضي.
Treeset () {this (tremap new treemap <e ، object> ()) ؛ }لذا ، ما الذي قد نولي المزيد من الاهتمام إليه هنا هو كيف أن Treeset هي الشاقة؟ لنلقي نظرة على طريقة الإضافة:
Boolean Public Add (e e) {return m.put (e ، present) == null ؛ }إنه يشبه إلى حد ما hashset ، وكلاهما يعتمد على ميزات الخريطة لتحقيق التحميل الثقيل. انها حقا بسيطة وفعالة.
ما سبق هو التفسير التفصيلي للمجموعة والقائمة والخريطة في جافا التي يقدمها لك المحرر. آمل أن تتمكن من دعم wulin.com أكثر ~