উত্তর:
পাইথন ডিসটিক্স সম্পর্কে এখানে যা আমি একসাথে রাখতে সক্ষম হয়েছি (সম্ভবত যে কেউ জানতে চাইবে তার চেয়ে বেশি; তবে উত্তরটি বিস্তৃত)।
dict
ব্যবহার করে (নীচে ব্যাখ্যা করা হয়েছে) ( ডিক্টোবজেক্ট.২: ২৯6-২97 দেখুন )।O(1)
সূচক অনুসারে একটি অনুসন্ধান করতে পারেন )।নীচের চিত্রটি একটি পাইথন হ্যাশ টেবিলের যৌক্তিক উপস্থাপনা। নীচের চিত্রটিতে, 0, 1, ..., i, ...
বামদিকে হ্যাশ টেবিলের স্লটগুলির সূচক রয়েছে (এগুলি কেবল উদাহরণস্বরূপ উদ্দেশ্যে রয়েছে এবং টেবিলের সাথে স্পষ্টত সংরক্ষণ করা হয় না!)।
# Logical model of Python Hash table
-+-----------------+
0| <hash|key|value>|
-+-----------------+
1| ... |
-+-----------------+
.| ... |
-+-----------------+
i| ... |
-+-----------------+
.| ... |
-+-----------------+
n| ... |
-+-----------------+
নতুন ডিক শুরু হলে এটি 8 টি স্লট দিয়ে শুরু হয় । ( ডিক্টোবজেক্ট দেখুন: 49 )
i
, এটি কী এর হ্যাশের উপর ভিত্তি করে। সিপিথন প্রাথমিকভাবে ব্যবহার করে i = hash(key) & mask
(যেখানে mask = PyDictMINSIZE - 1
, তবে এটি আসলে গুরুত্বপূর্ণ নয়)। কেবলমাত্র লক্ষ্য করুন যে প্রাথমিক স্লটটি, i
এটি যাচাই করা হয়েছে কীটির হ্যাশের উপর নির্ভর করে ।<hash|key|value>
)। তবে কী যদি সেই স্লটটি দখল করা হয় !? সম্ভবত সম্ভবত অন্য এন্ট্রিতে একই হ্যাশ রয়েছে (হ্যাশ সংঘর্ষ!)==
তুলনা নয় মানে তুলনা করে is
) সন্নিবেশ করানোর জন্য বর্তমান প্রবেশের হ্যাশ এবং কীটির বিপরীতে স্লটে প্রবেশের ( ডিক্টোবজেক্ট। : যথাক্রমে 337,344-345 )। যদি উভয়ই মিলে যায়, তবে এটি মনে করে যে এন্ট্রিটি ইতিমধ্যে বিদ্যমান রয়েছে, ছেড়ে দেয় এবং entryোকানোর জন্য পরবর্তী প্রবেশপথে এগিয়ে যায়। যদি হ্যাশ বা কীটি মেলে না, এটি অনুসন্ধান শুরু করে ।i+1, i+2, ...
এবং প্রথম উপলব্ধ একটি ব্যবহার করতে পারি (এটি লিনিয়ার প্রোবিং)। তবে কারণগুলিতে মন্তব্যগুলিতে সুন্দরভাবে ব্যাখ্যা করা হয়েছে (দেখুন ডিক্টোবজেক্ট.সি: ৩৩-১২6 ), সিপিথন এলোমেলো প্রোবিং ব্যবহার করে । এলোমেলো অনুসন্ধানে, পরবর্তী স্লটটি সিউডো এলোমেলো ক্রমে বেছে নেওয়া হয়েছে। প্রথম খালি স্লটে এন্ট্রি যুক্ত করা হয়। এই আলোচনার জন্য, পরবর্তী স্লটটি বাছাইয়ের জন্য ব্যবহৃত প্রকৃত অ্যালগরিদমটি সত্যই গুরুত্বপূর্ণ নয় ( অনুসন্ধানের জন্য অ্যালগরিদমের জন্য ডিক্টোবজেক্ট.সি: ৩৩-১২6 দেখুন )। কী গুরুত্বপূর্ণ তা হল প্রথম খালি স্লট না পাওয়া পর্যন্ত স্লটগুলি তদন্ত করা হবে।dict
দুই-তৃতীয়াংশ পূর্ণ হলে পুনরায় আকার দেওয়া হবে। এটি অনুসন্ধানগুলিকে আস্তে আস্তে এড়িয়ে যায়। ( ডিক্টোবজেক্ট দেখুন: 64৪-65৫ )দ্রষ্টব্য: ডিকটিতে একাধিক এন্ট্রি কীভাবে একই হ্যাশ মান রাখতে পারে সে সম্পর্কে আমার নিজের প্রশ্নের জবাবে পাইথন ডিক্ট প্রয়োগের উপর গবেষণাটি করেছি। আমি এখানে প্রতিক্রিয়াটির একটি সামান্য সম্পাদিত সংস্করণ পোস্ট করেছি কারণ সমস্ত গবেষণাও এই প্রশ্নের জন্য খুব প্রাসঙ্গিক।
কীভাবে পাইথনের অন্তর্নির্মিত শব্দকোষ প্রয়োগ করা হয়?
এখানে সংক্ষিপ্ত কোর্স:
অর্জিত দিকটি পাইথন ৩.6 (অন্যান্য বাস্তবায়নকে অব্যাহত রাখার সুযোগ দেওয়ার মতো) হিসাবে আনুষ্ঠানিক , তবে পাইথন ৩.7-তে অফিসিয়াল ।
দীর্ঘ সময় ধরে এটি ঠিক এভাবে কাজ করেছিল। পাইথন 8 টি খালি সারি পূর্বনির্ধারিত করে এবং কী-মানটির জোড়টি কোথায় আটকে থাকবে তা নির্ধারণ করতে হ্যাশ ব্যবহার করবে। উদাহরণস্বরূপ, কীটির জন্য হ্যাশটি যদি 001 এ শেষ হয়, তবে এটি এটি 1 (অর্থাৎ ২ য়) সূচীতে আটকে থাকবে (নীচের উদাহরণের মতো))
<hash> <key> <value>
null null null
...010001 ffeb678c 633241c4 # addresses of the keys and values
null null null
... ... ...
প্রতিটি সারি একটি 64 বিট আর্কিটেকচারে 24 বাইট নেয়, 32 বিটটিতে 12 করে। (নোট করুন যে কলামের শিরোনামগুলি এখানে আমাদের উদ্দেশ্যগুলির জন্য কেবলমাত্র লেবেল - এগুলি আসলে মেমরিতে বিদ্যমান নেই))
যদি হ্যাশটি প্রিসিস্টিং কী এর হ্যাশ হিসাবে একই সমাপ্ত হয়, এটি একটি সংঘর্ষ, এবং তারপরে এটি মূল-মান জুটিটিকে অন্য কোনও স্থানে আটকে রাখবে।
5 টি মূল-মান সঞ্চিত হওয়ার পরে, অন্য কী-মান জোড় যুক্ত করার পরে, হ্যাশের সংঘর্ষের সম্ভাবনা খুব বড়, সুতরাং অভিধানটি আকারে দ্বিগুণ হয়। একটি bit৪ বিটের প্রক্রিয়াতে, আকার পরিবর্তন করার আগে, আমাদের 72 টি বাইট খালি রয়েছে এবং পরে, 10 টি খালি সারিগুলির কারণে আমরা 240 বাইট নষ্ট করছি।
এটি অনেক বেশি জায়গা নেয়, তবে দেখার সময় মোটামুটি ধ্রুবক। মূল তুলনা অ্যালগরিদম হ্যাশ গণনা করা, প্রত্যাশিত জায়গায় যান, কী এর আইডি তুলনা - যদি তারা একই বস্তু হয়, তারা সমান হয়। যদি না হয় তবে হ্যাশ মানগুলি তুলনা করুন, যদি সেগুলি না হয় তবে তারা সমান নয়। অন্যথায়, আমরা শেষ পর্যন্ত সমতার জন্য কীগুলি তুলনা করি এবং সেগুলি সমান হলে মানটি ফেরত দেয়। সাম্যের জন্য চূড়ান্ত তুলনা বেশ ধীর হতে পারে, তবে পূর্ববর্তী চেকগুলি সাধারণত চূড়ান্ত তুলনা শর্টকাট করে তোলে, যা অনুসন্ধানগুলি খুব দ্রুত করে তোলে।
সংঘর্ষগুলি জিনিসগুলিকে ধীর করে দেয় এবং কোনও আক্রমণকারী তাত্ত্বিকভাবে পরিষেবা আক্রমণকে অস্বীকার করার জন্য হ্যাশ সংঘর্ষগুলি ব্যবহার করতে পারে, তাই আমরা হ্যাশ ফাংশনটির সূচনাটি এলোমেলো করে দিয়েছিলাম যে এটি প্রতিটি নতুন পাইথন প্রক্রিয়াটির জন্য বিভিন্ন হ্যাশগুলিকে গণনা করে।
উপরে বর্ণিত নষ্ট স্থান আমাদের অভিধানের বাস্তবায়ন পরিবর্তন করতে পরিচালিত করেছে, একটি আকর্ষণীয় নতুন বৈশিষ্ট্য সহ অভিধানগুলি এখন সন্নিবেশ দ্বারা আদেশ করা হয়েছে।
পরিবর্তে, সন্নিবেশ সূচকের জন্য একটি অ্যারের পূর্বনির্ধারণ করে শুরু করি।
যেহেতু আমাদের প্রথম কী-মান জুটি দ্বিতীয় স্লটে যায় তাই আমরা এই জাতীয় সূচী:
[null, 0, null, null, null, null, null, null]
এবং আমাদের সারণী সন্নিবেশ ক্রমের দ্বারা সজ্জিত হয়ে উঠেছে:
<hash> <key> <value>
...010001 ffeb678c 633241c4
... ... ...
সুতরাং যখন আমরা কোনও কীটির জন্য অনুসন্ধান করি, তখন আমরা প্রত্যাশা করা অবস্থানটি পরীক্ষা করতে হ্যাশ ব্যবহার করি (এই ক্ষেত্রে আমরা সরাসরি অ্যারের সূচক 1 এ চলে যাই), তারপরে হ্যাশ-সারণিতে সেই সূচীতে যান (যেমন সূচক 0) ), পরীক্ষা করুন যে কীগুলি সমান (পূর্বে বর্ণিত একই অ্যালগরিদম ব্যবহার করে), এবং যদি থাকে তবে মানটি ফিরিয়ে দিন।
আমরা অবিচ্ছিন্নভাবে অনুসন্ধানের সময়টি ধরে রাখি, কিছু ক্ষেত্রে সামান্য গতির ক্ষতি এবং অন্যদের মধ্যে লাভ সহ, আমরা পূর্ব-বিদ্যমান বাস্তবায়নের চেয়ে অনেক বেশি জায়গা সঞ্চয় করি এবং আমরা সন্নিবেশ ক্রম ধরে রাখি। কেবলমাত্র স্থান নষ্ট হয় সূচি অ্যারেতে নাল বাইট।
রেমন্ড Hettinger এই চালু পাইথন-দেব ডিসেম্বর 2012. অবশেষে মধ্যে CPython পেয়েছিলাম মধ্যে পাইথন 3.6 । পাইথনের অন্যান্য বাস্তবায়নের সুযোগটি ধরার সুযোগ দেওয়ার জন্য সন্নিবেশ দ্বারা অর্ডার দেওয়া 3.6 এর জন্য একটি বাস্তবায়ন বিশদ হিসাবে বিবেচিত হয়েছিল।
স্থান বাঁচানোর জন্য আরেকটি অপ্টিমাইজেশন হ'ল একটি বাস্তবায়ন যা কীগুলি ভাগ করে। সুতরাং, সেই স্থানটি সমস্ত নিয়ে যাওয়া নিরর্থক অভিধানগুলির পরিবর্তে আমাদের কাছে অভিধান রয়েছে যা ভাগ করা কী এবং কীগুলির হ্যাশগুলি পুনরায় ব্যবহার করে। আপনি এটি এরকমভাবে ভাবতে পারেন:
hash key dict_0 dict_1 dict_2...
...010001 ffeb678c 633241c4 fffad420 ...
... ... ... ... ...
একটি 64 বিট মেশিনের জন্য, এটি অতিরিক্ত অভিধানে প্রতি কী প্রতি 16 বাইট সঞ্চয় করতে পারে।
এই ভাগ করা-কী dicts কাস্টম অবজেক্ট 'জন্য ব্যবহার করার উদ্দেশ্যে করা হয় __dict__
। এই আচরণটি পেতে, আমি বিশ্বাস করি যে আপনি __dict__
আপনার পরবর্তী বস্তুটি ইনস্ট্যান্ট করার আগে আপনার জনসংখ্যা শেষ করতে হবে ( পিইপি 412 দেখুন )। এর অর্থ আপনার __init__
বা আপনার সমস্ত বৈশিষ্ট্য বরাদ্দ করা উচিত __new__
, অন্যথায় আপনি আপনার স্থান সঞ্চয় নাও পেতে পারেন।
যাইহোক, আপনি __init__
কার্যকর হওয়ার সময় যদি আপনার সমস্ত বৈশিষ্ট্যগুলি জানেন তবে আপনি __slots__
নিজের বস্তুর জন্য এবং গ্যারান্টি সরবরাহ করতে পারেন __dict__
যা মোটেই তৈরি করা হয়নি (পিতামাতার কাছে উপলব্ধ না থাকলেও) বা এমনকি অনুমতি দেয় __dict__
তবে গ্যারান্টি দেয় যে আপনার আগত বৈশিষ্ট্যগুলি যাইহোক স্লট সঞ্চিত। আরও জন্য __slots__
, আমার উত্তর এখানে দেখুন ।
**kwargs
একটি ফাংশনে ক্রম সংরক্ষণ করা ।find_empty_slot
: github.com/python/cpython/blob/master/Objects/dictobject.c # L969 - এবং 134 লাইনে শুরু করে কিছু গদ্য রয়েছে যা এটি বর্ণনা করে।
পাইথন ডিকোচারগুলি ওপেন অ্যাড্রেসিং ( সুন্দর কোডের অভ্যন্তরে রেফারেন্স ) ব্যবহার করে
বিশেষ দ্রষ্টব্য! ওপেন অ্যাড্রেসিং , ওরফে ক্লোজড হ্যাশিং , উইকিপিডিয়ায় উল্লিখিত হিসাবে, এর বিপরীত ওপেন হ্যাশিংয়ের সাথে বিভ্রান্ত হওয়া উচিত নয় !
ওপেন অ্যাড্রেসিং এর অর্থ হ'ল ডেক অ্যারে স্লটগুলি ব্যবহার করে এবং যখন কোনও বস্তুর প্রাথমিক অবস্থান ডিকটিতে নেওয়া হয় তখন "পার্টিউথিউশন" স্কিম ব্যবহার করে বস্তুর স্পট একই অ্যারেতে আলাদা সূচীতে অনুসন্ধান করা হয়, যেখানে বস্তুর হ্যাশ মান অংশ করে plays ।