166 lines
10 KiB
Markdown
166 lines
10 KiB
Markdown
|
---
|
||
|
title: Hash Tables and Hashing Functions
|
||
|
localeTitle: جداول تجزئة ووظائف تجزئة
|
||
|
---
|
||
|
### مقدمة عن التجزئة
|
||
|
|
||
|
تم تصميم Hashing لحل مشكلة الحاجة إلى العثور على عنصر أو تخزينه بكفاءة في مجموعة.
|
||
|
على سبيل المثال ، إذا كانت لدينا قائمة تضم 10000 كلمة باللغة الإنجليزية ونريد التحقق مما إذا كانت كلمة معينة موجودة في القائمة ، فسيكون من غير المقبول مقارنة الكلمة مع جميع العناصر الـ 10000 حتى نجد تطابقًا. حتى لو تم تصنيف قائمة الكلمات معجميًا ، كما هو الحال في القاموس ، ستظل بحاجة إلى بعض الوقت للعثور على الكلمة التي تبحث عنها.
|
||
|
تجزئة هو تقنية لجعل الأشياء أكثر كفاءة من خلال تضييق نطاق البحث في البداية.
|
||
|
|
||
|
## ما هو التجزئة؟
|
||
|
|
||
|
يعني Hashing استخدام بعض الوظائف أو الخوارزمية لتعيين بيانات الكائن إلى بعض القيم العددية التمثيلية.
|
||
|
يمكن استخدام رمز التجزئة هذا (أو التجزئة ببساطة) كطريقة لتضييق نطاق البحث عند البحث عن العنصر في الخريطة.
|
||
|
بشكل عام ، تُستخدم رموز التجزئة هذه لإنشاء فهرس ، يتم فيه تخزين القيمة.
|
||
|
|
||
|
## كيف يعمل التجزئة
|
||
|
|
||
|
في جداول التجزئة ، يمكنك تخزين البيانات في نماذج أزواج المفاتيح والقيم. يتم إعطاء المفتاح ، الذي يستخدم لتحديد البيانات ، كمدخل لوظيفة التجزئة. ثم يتم تعيين رمز التجزئة ، وهو عدد صحيح ، إلى الحجم الثابت لدينا.
|
||
|
|
||
|
يجب أن تدعم جداول التجزئة 3 وظائف.
|
||
|
|
||
|
* إدراج (مفتاح ، قيمة)
|
||
|
* احصل على مفتاح)
|
||
|
* حذف (مفتاح)
|
||
|
|
||
|
بحت كمثال لمساعدتنا على فهم المفهوم ، دعونا نفترض أننا نريد تعيين قائمة بمفاتيح السلسلة لقيم السلسلة (على سبيل المثال ، خريطة قائمة البلدان إلى مدن عاصمتهم).
|
||
|
لنفترض أننا نريد تخزين البيانات في الجدول في الخريطة.
|
||
|
|
||
|
مفتاح | القيمة
|
||
|
\---------------- | -------------
|
||
|
كوبا هافانا
|
||
|
انكلترا | لندن
|
||
|
فرنسا | باريس
|
||
|
اسبانيا | مدريد
|
||
|
سويسرا | برن
|
||
|
|
||
|
ودعونا نفترض أن وظيفة هاش لدينا هي ببساطة أن تأخذ طول السلسلة.
|
||
|
|
||
|
بالنسبة إلى البساطة ، سيكون لدينا صفيفان: واحد لمفاتيحنا والآخر للقيم.
|
||
|
لذلك ، لوضع عنصر في جدول التجزئة ، نحسب رمز التجزئة الخاص به (في هذه الحالة ، ببساطة حساب عدد الأحرف) ، ثم ضع المفتاح والقيمة في المصفوفات في الفهرس المقابل.
|
||
|
على سبيل المثال ، لدى كوبا رمز هاش (طول) من 4.
|
||
|
لذلك نقوم بتخزين كوبا في المركز الرابع في صفيف المفاتيح ، وهافانا في المؤشر الرابع لصفيف القيم وما إلى ذلك ، وننتهي بما يلي:
|
||
|
|
||
|
الموقف مجموعة مفاتيح | مجموعة القيم
|
||
|
\--------------------- | ------------------ | --------- ------
|
||
|
1 | |
|
||
|
2 | |
|
||
|
3 | |
|
||
|
4 | كوبا هافانا
|
||
|
5 | اسبانيا | مدريد
|
||
|
6 | فرنسا | باريس
|
||
|
7 | انكلترا | لندن
|
||
|
8 | |
|
||
|
9 | |
|
||
|
10 | |
|
||
|
11 | سويسرا | برن
|
||
|
|
||
|
الآن ، في هذا المثال المحدد ، تعمل الأشياء بشكل جيد.
|
||
|
يجب أن تكون صفيفنا كبيرًا بما يكفي لاستيعاب أطول سلسلة ، ولكن في هذه الحالة لا يوجد سوى 11 فتحة.
|
||
|
نحن نهدر قليلاً من المساحة لأنه ، على سبيل المثال ، لا توجد مفاتيح من حرف واحد في بياناتنا ، ولا مفاتيح بين 8 و 10 أحرف. لكن في هذه الحالة ، الفضاء المهدر ليس سيئًا أيضًا. يعتبر أخذ طول السلسلة أمرًا رائعًا وسريعًا ، وكذلك عملية العثور على القيمة المرتبطة بمفتاح معين (وبالتأكيد أسرع من إجراء خمس مقارنات للأوتار).
|
||
|
|
||
|
ولكن ، ماذا نفعل إذا كانت مجموعة البيانات تحتوي على سلسلة تحتوي على أكثر من 11 حرفًا؟
|
||
|
ماذا لو كان لدينا كلمة أخرى تحتوي على 5 أحرف ، "الهند" ، وحاول تعيينها إلى فهرس باستخدام الدالة hash. بما أن المؤشر 5 مشغول بالفعل ، علينا أن نتصل على ما يجب فعله به. وهذا ما يسمى الاصطدام.
|
||
|
|
||
|
إذا كانت مجموعة البيانات الخاصة بنا تحتوي على أحرف بألف حرف ، وقمت بإنشاء مجموعة من آلاف المؤشرات لتخزين البيانات ، فسوف ينتج عنها إهدار مساحة. إذا كانت مفاتيحنا عبارة عن كلمات عشوائية من الإنجليزية ، حيث توجد العديد من الكلمات بنفس الطول ، باستخدام الطول كوظيفة تجزئة ستكون عديمة الفائدة إلى حد ما.
|
||
|
|
||
|
## التعامل مع التصادم
|
||
|
|
||
|
يتم استخدام طريقتين أساسيتين للتعامل مع الاصطدامات.
|
||
|
|
||
|
1. تسلسل منفصلة
|
||
|
2. فتح العنونة
|
||
|
|
||
|
#### تسلسل منفصلة
|
||
|
|
||
|
يستخدم التعامل مع اصطدام التجزئة بواسطة تسلسل منفصل ، بنية بيانات إضافية ، قائمة مفضلة بشكل مفضّل للتخصيص الديناميكي ، إلى دلاء. في مثالنا ، عندما نضيف الهند إلى مجموعة البيانات ، يتم إلحاقها بالقائمة المرتبطة المخزنة في الفهرس 5 ، ثم يبدو جدولنا هكذا.
|
||
|
|
||
|
الموقف رؤساء قائمة مرتبطة |
|
||
|
\--------------------- | ---------------------------- -------- |
|
||
|
1 | |
|
||
|
2 | |
|
||
|
3 | |
|
||
|
4 | [كوبا-هافانا\]
|
||
|
5 | \[اسبانيا - مدريد\] -> \[الهند - دلهي\] |
|
||
|
6 | \[فرنسا باريس\] |
|
||
|
7 | \[إنجلترا - لندن\] |
|
||
|
8 | |
|
||
|
9 | |
|
||
|
10 | |
|
||
|
11 | \[سويسرا برن\]](https://en.wikipedia.org/wiki/Linear_probing)
|
||
|
|
||
|
للعثور على عنصر ، نذهب أولاً إلى الدلو ثم نتبادل المفاتيح. هذه طريقة شائعة ، وإذا تم استخدام قائمة الارتباطات لا يتم تعبئة التجزئة. تكلفة `get(k)` هي في المتوسط `O(n)` حيث n هي عدد المفاتيح في المجموعة ، يكون العدد الإجمالي للمفاتيح هو N.
|
||
|
المشكلة مع تسلسل منفصلة هو أن بنية البيانات يمكن أن تنمو خارج الحدود.
|
||
|
|
||
|
#### فتح العنونة
|
||
|
|
||
|
لا تقدم معالجة مفتوحة أي بنية بيانات جديدة. في حالة حدوث تصادم ، فإننا نبحث عن التواجد في النقطة التالية التي تم إنشاؤها بواسطة خوارزمية. يتم استخدام Open Addressing عادة عندما تكون مساحة التخزين عبارة عن معالجات مقيدة ، أي المعالجات المضمنة. فتح العنوان ليس بالضرورة أسرع ثم فصل التسلسل.
|
||
|
|
||
|
طرق لفتح العنان
|
||
|
|
||
|
* \[تحليل خطي
|
||
|
* [تحقيقات تربيعية](https://en.wikipedia.org/wiki/Quadratic_probing)
|
||
|
* [مزدوج تجزئة](https://en.wikipedia.org/wiki/Double_hashing)
|
||
|
|
||
|
## كيفية استخدام التجزئة في التعليمات البرمجية.
|
||
|
|
||
|
#### الثعبان
|
||
|
|
||
|
` # Few languages like Python, Ruby come with an in-built hashing support.
|
||
|
# Declaration
|
||
|
my_hash_table = {}
|
||
|
my_hash_table = dict()
|
||
|
|
||
|
# Insertion
|
||
|
my_hash_table[key] = value
|
||
|
|
||
|
# Look up
|
||
|
value = my_hash_table.get(key) # returns None if the key is not present || Deferred in python 3, available in python 2
|
||
|
value = my_hash_table[key] # throws a ValueError exception if the key is not present
|
||
|
|
||
|
# Deletion
|
||
|
del my_hash_table[key] # throws a ValueError exception if the key is not present
|
||
|
|
||
|
# Getting all keys and values stored in the dictionary
|
||
|
keys = my_hash_table.keys()
|
||
|
values = my_hash_table.values()
|
||
|
`
|
||
|
|
||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":صاروخ:") [تشغيل الكود](https://repl.it/CVtK)
|
||
|
|
||
|
#### جافا
|
||
|
|
||
|
` // Java doesn't include hashing by default, you have to import it from java.util library
|
||
|
// Importing hashmaps
|
||
|
import java.util.HashMap;
|
||
|
|
||
|
// Declaration
|
||
|
HashMap<Integer, Integer> myHashTable = new HashMap<Integer, Integer>(); // declares an empty map.
|
||
|
|
||
|
// Insertion
|
||
|
myHashTable.put(key, value);
|
||
|
|
||
|
// Deletion
|
||
|
myHashtable.remove(key);
|
||
|
|
||
|
// Look up
|
||
|
myHashTable.get(key); // returns null if the key K is not present
|
||
|
myHashTable.containsKey(key); // returns a boolean value, indicating the presence of a key
|
||
|
|
||
|
// Number of key, value pairs in the hash table
|
||
|
myHashTable.size();
|
||
|
`
|
||
|
|
||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":صاروخ:") [تشغيل الكود](https://repl.it/CVt1)
|
||
|
|
||
|
## مصادر
|
||
|
|
||
|
* لمزيد من القراءة ، تريد العديد من محاولة هذا [الارتباط](http://geeksquiz.com/hashing-set-1-introduction/) ، والذي يشرح التجزئة باستخدام مثال مختلف.
|
||
|
* [تجزئة في 60 ثانية](https://www.youtube.com/watch?v=x05KubVlh_M) .
|
||
|
* [تجفيف الوقواق](https://www.youtube.com/watch?v=HRzg0SzFLQQ)
|
||
|
* [تصانيف التجزئة](https://www.youtube.com/watch?v=jznJKL0CrxM)
|
||
|
* [بلوم مرشحات](https://www.youtube.com/watch?v=-SuTGoFYjZs)
|
||
|
* [استراتيجيات تجزئة](https://www.youtube.com/watch?v=D65JQ0qQwZk)
|
||
|
* [كلمة السر](https://crackstation.net/hashing-security.htm)
|
||
|
* [الفرق بين الفرز والتشفير](http://stackoverflow.com/questions/326699/difference-between-hashing-a-password-and-encrypting-it)
|