হ্যাশ টেবিলগুলি সত্যই ও (1) হতে পারে?


114

এটি সাধারণ জ্ঞান বলে মনে হয় যে হ্যাশ টেবিলগুলি ও (1) অর্জন করতে পারে তবে এটি আমার কাছে কখনই বোধগম্য হয়নি। কেউ দয়া করে এটি ব্যাখ্যা করতে পারেন? এখানে দুটি পরিস্থিতি মনে আসে:

: মান হ্যাশ টেবিলের আকারের চেয়ে ছোট একটি অন্তর্ভুক্ত। অতএব, মানটি তার নিজস্ব হ্যাশ, সুতরাং কোনও হ্যাশ টেবিল নেই। তবে যদি এটি থাকে তবে এটি ও (1) হবে এবং এখনও অদক্ষ।

বি। আপনাকে মানটির একটি হ্যাশ গণনা করতে হবে। এই পরিস্থিতিতে, ডেটা সন্ধান করা হচ্ছে তার আকারের জন্য আদেশ (ও) is আপনি ও (এন) কাজ করার পরে অনুসন্ধানটি ও (1) হতে পারে তবে এটি এখনও আমার চোখে ও (এন) এর বাইরে আসে।

এবং আপনার কাছে নিখুঁত হ্যাশ বা একটি বড় হ্যাশ টেবিল না থাকলে সম্ভবত বালতিতে বেশ কয়েকটি আইটেম রয়েছে। সুতরাং, এটি যে কোনও উপায়ে একটি ছোট রৈখিক অনুসন্ধানে রূপান্তরিত হয়।

আমি মনে করি হ্যাশ টেবিলগুলি দুর্দান্ত, তবে কেবলমাত্র তাত্ত্বিক বলে মনে করা না হলে আমি ও (1) উপাধিটি পাই না।

হ্যাশ টেবিলগুলির জন্য উইকিপিডিয়ায় নিবন্ধটি ধারাবাহিকভাবে পর্যবেক্ষণের সময়কে উল্লেখ করে এবং হ্যাশ ফাংশনের ব্যয়টিকে সম্পূর্ণ উপেক্ষা করে। সত্যিই কি এটি একটি উপযুক্ত ব্যবস্থা?


সম্পাদনা করুন: আমি যা শিখেছি তার সংক্ষিপ্তসার হিসাবে:

  • এটি প্রযুক্তিগতভাবে সত্য কারণ হ্যাশ ফাংশনটি কীতে সমস্ত তথ্য ব্যবহার করার প্রয়োজন হয় না এবং এটি ধ্রুবক সময় হতে পারে, এবং কারণ একটি বৃহত পর্যায়ে টেবিল সংঘর্ষগুলি কাছাকাছি স্থির সময়ের দিকে নামিয়ে আনতে পারে।

  • এটি বাস্তবে সত্য কারণ সময়ের সাথে সাথে এটি কেবলমাত্র কার্যকর হয় যতক্ষণ না হ্যাশ ফাংশন এবং টেবিলের আকার সংঘটন হ্রাস করতে বেছে নেওয়া হয়, যদিও এর অর্থ প্রায়শই স্থির সময় হ্যাশ ফাংশনটি ব্যবহার না করা।


31
এটি ও (1) নয়, ও (1) মোড়কবিহীন।
কেনেটিমে

মনে রাখবেন ও () প্রচুর সংখ্যক ক্রিয়াকলাপের সীমা। 'গড়' এ আপনার খুব বেশি সংঘর্ষ হবে না - এটি পৃথক ক্রিয়াকলাপের কোনও সংঘর্ষ না হওয়া প্রয়োজন।
মার্টিন বেকেট

স্ট্রিং বাস্তবায়নের উপর নির্ভর করে স্ট্রিংগুলি তাদের হ্যাশ মানটি তাদের সাথে বহন করতে পারে, সুতরাং এটি স্থির থাকবে। মুল বক্তব্যটি হ্যাশ লুকিং জটিলতার সাথে অপ্রাসঙ্গিক।
ধনী রিমার

@kennytm নিশ্চিত, লুকআপ আপনি একবার ইনপুট কুচি-কুচি করিয়া কাটা বস্তু থাকেন amortized হে (1) হয়। তবে হ্যাশ গণনার ব্যয়টি কি আসলেই নগন্য? মনে করুন আমরা একটি স্ট্রিং হ্যাশ করছি - একটি অক্ষর অ্যারে। হ্যাশ তৈরি করতে প্রতিটি অক্ষরকে পুনরাবৃত্তি করা হয়, সুতরাং একটি স্ট্রিং হ্যাশিং হল O (N) যেখানে N স্ট্রিংয়ের দৈর্ঘ্য। এটি এটি সি # এর জন্য নথিভুক্ত এবং জাভা hashCode()পদ্ধতিটি এটিকে এভাবে প্রয়োগ করা হয় Stringgrepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
spaaarky21

1
@ স্পাআরকি 21 আপনি যে এন (এন) এর সাথে কথা বলছেন তা হ'ল স্ট্রিংয়ের দৈর্ঘ্য, যা হ্যাশ টেবিলের আকার এন থেকে আলাদা। মার্ক বাইরের উত্তর ইতিমধ্যে এটি সম্বোধন করেছে।
কেনেটিএম

উত্তর:


65

আপনার এখানে দুটি ভেরিয়েবল রয়েছে, এম এবং এন, যেখানে মি ইনপুটটির দৈর্ঘ্য এবং এন হ্যাশের আইটেমের সংখ্যা।

ও (1) দেখার কর্মক্ষমতা দাবিটি কমপক্ষে দুটি অনুমান করে:

  • আপনার বস্তুগুলি ও (1) সময়ের তুলনায় সমতা হতে পারে।
  • কয়েকটি হ্যাশ সংঘর্ষ হবে।

যদি আপনার বস্তুগুলি পরিবর্তনশীল আকারের হয় এবং সমতা পরীক্ষার জন্য সমস্ত বিট দেখার প্রয়োজন হয় তবে কর্মক্ষমতা ও (এম) হয়ে যাবে। হ্যাশ ফাংশনটি তবে ও (এম) হতে হবে না - এটি ও (1) হতে পারে। কোনও ক্রিপ্টোগ্রাফিক হ্যাশের বিপরীতে, অভিধানে ব্যবহারের জন্য একটি হ্যাশ ফাংশন হ্যাশ গণনা করার জন্য ইনপুটটির প্রতিটি বিটের দিকে তাকাতে হবে না। বাস্তবায়নগুলি কেবলমাত্র একটি নির্দিষ্ট সংখ্যক বিট দেখার জন্য নিখরচায়।

পর্যাপ্ত পরিমাণ আইটেমের জন্য আইটেমের সংখ্যা সম্ভাব্য হ্যাশগুলির সংখ্যার চেয়ে বেশি হয়ে যাবে এবং তারপরে আপনি সংঘর্ষগুলি পাবেন যা পারফরম্যান্স ও (1) এর উপরে উঠবে, উদাহরণস্বরূপ একটি সাধারণ লিঙ্কযুক্ত তালিকার ট্রভারসাল (বা ও (এন) এর জন্য ও (এন) * মি) উভয় অনুমান যদি মিথ্যা হয়)।

বাস্তবে যদিও ও (1) প্রযুক্তিগতভাবে মিথ্যা হিসাবে দাবী করে, অনেকগুলি বাস্তব বিশ্বের পরিস্থিতি এবং বিশেষত সেই পরিস্থিতিতে যেখানে উপরোক্ত অনুমানগুলি ধরে আছে তা প্রায় সত্য।


4
উপরের পাশাপাশি, আপনি যদি নিজের কী হিসাবে যেমন পরিবর্তনযোগ্য অবজেক্টগুলি ব্যবহার করছেন যেমন জাভা স্ট্রিংস, একবার হ্যাশ একবার গণনা করা হয়েছে, আপনি এটি মনে রাখতে পারেন এবং এটি আবার গণনা করতে হবে না। অন্যদিকে, আপনি সঠিকভাবে বালতিটি একবার পেয়ে গেলে দুটি কী সমান হয় কিনা তা জানার জন্য আপনি সাধারণত হ্যাশের উপর নির্ভর করতে পারবেন না, সুতরাং স্ট্রিংগুলির জন্য আপনার সমান কিনা তা জানতে ও (এম) ট্র্যাভারসাল করা উচিত।
জেরেমিপ

1
@ জেরেমিপি: ও (এম) সমতা তুলনা করার পক্ষে ভাল বিষয়। আমি যে মিস - আপডেট পোস্ট। ধন্যবাদ!
মার্ক বাইয়ার্স

2
O(1)দাবি সত্য হলে তুমি হ্যাশ intগুলি বা অন্য কিছু করে একটি মেশিন শব্দ আছে। হ্যাশিংয়ের উপর এটি বেশিরভাগ তত্ত্বই ধরে নিয়েছে।
থমাস আহলে

আমি আপনার মার্কের সেই ব্যাখ্যাটি পছন্দ করি, আমি আমার নিবন্ধে এটি meshfields.de/hash-tables- এর
স্টিভ কে

3
ইন "M ইনপুটের দৈর্ঘ্য হল" - ইনপুট মাত্রাতিরিক্ত অস্পষ্ট - এটা সমস্ত কী ও মান সন্নিবেশ করা হচ্ছে মানে হতে পারে, কিন্তু এটা স্পষ্ট পরে (অন্তত যারা ইতিমধ্যে বিষয় বুঝতে) হয়ে আপনি কি এটি বলতে কী । স্বচ্ছতার জন্য উত্তরে কেবল "কী" ব্যবহার করার পরামর্শ দিচ্ছি। বিটিডাব্লু - কংক্রিট উদাহরণ - ভিজ্যুয়াল সি ++ std::hashএর পাঠ্য কীগুলি হ্যাশ মানটির সাথে পাঠ্যের সাথে সমানভাবে ফাঁকা 10 টি অক্ষর একত্রিত করে, সুতরাং এটি পাঠ্য দৈর্ঘ্য নির্বিশেষে ও (1) তবে জিসিসির চেয়ে বেশি সংঘর্ষ প্রবণ!)) পৃথকভাবে, ও (1) এর দাবির আরও একটি অনুমান রয়েছে (সাধারণত সঠিকভাবে) যে এম এন এর চেয়ে অনেক কম ।
টনি ডেলরয়

22

আপনাকে হ্যাশটি গণনা করতে হবে, সুতরাং যে ডাটাটি সন্ধান করা হচ্ছে তার জন্য অর্ডারটি হ'ল (এন)। আপনি ও (এন) কাজ করার পরে অনুসন্ধানটি ও (1) হতে পারে তবে এটি এখনও আমার চোখে ও (এন) এর বাইরে আসে।

কি? একটি একক উপাদান হ্যাশ করতে ধ্রুবক সময় লাগে। কেন অন্য কিছু হবে? যদি আপনি .োকানো হয়n উপাদানগুলি করান, তবে হ্যাঁ, আপনাকে nহ্যাশগুলি গণনা করতে হবে , এবং এটির জন্য লিনিং সময় লাগবে ... একটি উপাদান সন্ধান করতে, আপনি যা খুঁজছেন তার একক হ্যাশ গণনা করুন, তারপরে উপযুক্ত বালতিটি সন্ধান করুন । ইতিমধ্যে হ্যাশ টেবিলের মধ্যে থাকা সমস্ত কিছুর হ্যাশগুলিকে আপনি পুনরায় গণনা করবেন না।

এবং যদি না আপনি একটি নিখুঁত হ্যাশ বা একটি বড় হ্যাশ টেবিল না থাকে সম্ভবত বালতি প্রতি বেশ কয়েকটি আইটেম থাকে তাই এটি যে কোনও উপায়ে একটি ছোট রৈখিক অনুসন্ধানে রূপান্তরিত হয়।

অগত্যা। বালতিগুলি অগত্যা তালিকা বা অ্যারে হতে হবে না, এগুলি কোনও ধারক ধরণের হতে পারে, যেমন একটি ভারসাম্য বিএসটি। তার মানে O(log n)সবচেয়ে খারাপ অবস্থা। তবে এ কারণেই একটি বালতিতে অনেকগুলি উপাদান না এড়াতে একটি ভাল হ্যাশিং ফাংশন বেছে নেওয়া গুরুত্বপূর্ণ। কেনেনিটিএম যেমন উল্লেখ করেছে, গড়ে, আপনি এখনও O(1)সময় পাবেন, এমনকি মাঝে মাঝে আপনাকে বালতি দিয়ে খনন করতে হবে।

হ্যাশ টেবিলের বাণিজ্য অবশ্যই স্থান জটিলতা। আপনি সময়ের জন্য স্থান ট্রেড করছেন, যা গণনা বিজ্ঞানের ক্ষেত্রে সাধারণ ক্ষেত্রে বলে মনে হয়।


আপনি আপনার অন্য কোনও মন্তব্যে স্ট্রিংগুলি কী হিসাবে উল্লেখ করেছেন। কোনও স্ট্রিংয়ের হ্যাশ গণনা করতে আপনি যে পরিমাণ সময় নেন তা নিয়ে আপনি উদ্বিগ্ন, কারণ এতে বেশ কয়েকটি চর রয়েছে? অন্য কেউ যেমন আবার উল্লেখ করেছেন, আপনাকে হ্যাশ গণনা করার জন্য অগত্যা সমস্ত চরিত্রের দিকে নজর দেওয়ার প্রয়োজন হবে না, যদিও এটি যদি আপনি করেন তবে এটি আরও ভাল হ্যাশ তৈরি করতে পারে। সেক্ষেত্রে, যদি mআপনার কীতে গড় অক্ষর থাকে এবং আপনি আপনার হ্যাশ গণনা করার জন্য সেগুলি সবগুলি ব্যবহার করেন, তবে আমি মনে করি আপনি ঠিক বলেছেন, এই অনুসন্ধানগুলি গ্রহণ করবে O(m)। তাহলে m >> nতারপর আপনি একটি সমস্যা থাকতে পারে। সেক্ষেত্রে আপনি সম্ভবত একটি বিএসটি দিয়ে ভাল হতে চাই। অথবা একটি সস্তা হ্যাশিং ফাংশন চয়ন করুন।


হ্যাশ টেবিলগুলি বিএসটি ব্যবহার করে না। বিএসটিগুলিতে হ্যাশ মানগুলির প্রয়োজন হয় না। মানচিত্র এবং সেটগুলি যদিও বিএসটি হিসাবে প্রয়োগ করা যেতে পারে।
নিক দানডৌলাকিস

3
@ নিক: এহ? না ... বিএসটিগুলিতে হ্যাশ মানগুলির প্রয়োজন নেই ... এটাই কথা। আমরা ধরে নিচ্ছি যে এই মুহুর্তে আমাদের ইতিমধ্যে একটি সংঘর্ষ হয়েছে (একই হ্যাশ ... বা কমপক্ষে একই বালতি), সুতরাং সঠিক উপাদানটি, অর্থাৎ আসল মানটি খুঁজে পেতে আমাদের অন্য কিছু দেখার প্রয়োজন।
এমপিএন

ওহ, আমি আপনার বক্তব্য দেখতে পাচ্ছি তবে আমি নিশ্চিত নই যে বিএসটি এবং হ্যাশগুলি মিশ্রিত করা সমস্যার জন্য উপযুক্ত। শুধু বিএসটি ব্যবহার করবেন না কেন?
নিক ডানডৌলাকিস

2
আমি শুধু আপনি যে বলছি পারে যে পরিত্রাণ পেতে O(n)দুর্ঘটনায় জন্য। আপনি যদি করছে দুর্ঘটনায় প্রচুর আশা, তাহলে আপনি সম্ভবত ভাল প্রথম স্থানে একটি বিএসটি সাথে যাচ্ছেন বন্ধ ঠিক।
এমপিএন

1
@ spaaarky21 ডান, তবে Nসেক্ষেত্রে স্ট্রিংয়ের দৈর্ঘ্য। আমাদের কোন 'বালতি' প্রবেশ করতে হবে তা নির্ধারণ করতে আমাদের কেবল একটি স্ট্রিং হ্যাশ করতে হবে - এটি হ্যাশম্যাপের দৈর্ঘ্যের সাথে বৃদ্ধি পায় না।
এমপেন

5

হ্যাশ স্থির আকার - উপযুক্ত হ্যাশ বালতি সন্ধান করা একটি নির্দিষ্ট ব্যয় ক্রিয়াকলাপ। এর অর্থ এটি ও (1) 1

হ্যাশ গণনা করা বিশেষ ব্যয়বহুল অপারেশন হওয়ার দরকার নেই - আমরা এখানে ক্রিপ্টোগ্রাফিক হ্যাশ ফাংশন বলছি না। তবে তা বাই। হ্যাশ ফাংশন গণনা নিজেই সংখ্যার উপর নির্ভর করে না এন উপাদানের; যদিও এটি কোনও উপাদানের ডেটার আকারের উপর নির্ভর করতে পারে, এটি এন উল্লেখ করে না। সুতরাং হ্যাশের গণনা n এর উপর নির্ভর করে না এবং এটি ও (1)।


3
হ্যাশ বালতিটি অনুসন্ধান করা হল ও (1)। তবে ডান কীটি সনাক্ত করা একটি ও (এন) পদ্ধতি, যেখানে এন হ্যাশের সংঘর্ষের সংখ্যার উপর নির্ভর করে।
নিক ডানডোলাকিস

1
3 টি পদক্ষেপের মধ্যে, হ্যাশ গণনা করুন, বালতিটি সন্ধান করুন, বালতিটি অনুসন্ধান করুন, মাঝের ধাপটি ধ্রুবক? বালতি অনুসন্ধান করা সাধারণত ধ্রুবক হয়। হ্যাশ গণনা করা সাধারণত বালতিটি আবিষ্কারের অন্যান্য উপায়ের চেয়ে কম মাত্রার কয়েকটি অর্ডার। কিন্তু এটি কি সত্যিকারের ধ্রুবক সময় যুক্ত করে? একটি নিষ্পাপ সাবস্ট্রিং অনুসন্ধানে, আপনি দুটি দৈর্ঘ্যের জন্য ও (এন * মি) বলবেন, তবে কীটির দৈর্ঘ্যটি এখানে অবহেলা করা হবে কেন?
ড্রোনওয়ার্ড

নির্দিষ্ট দৈর্ঘ্যের কী সন্ধান করা কেবলমাত্র ও (এন) এর তালিকার ব্যাক হলে কেবলমাত্র ভারসাম্যযুক্ত গাছ ব্যাকযুক্ত হ্যাশ টেবিলটি ও (লগ (এন))
জে কে হবে।

@Jk ভাল হ্যাশ কাজগুলির জন্য সবচেয়ে খারাপ ক্ষেত্রে সর্বদা logn, আমার উত্তর এ দেখতে stackoverflow.com/questions/4553624/hashmap-get-put-complexity/...
টমাস আহলে

সংঘর্ষের ক্ষেত্রে সবচেয়ে খারাপ ক্ষেত্রে ও (এন) হবে
সৌরভ চন্দ্র প্যাটেল

3

হ্যাশিং কেবলমাত্র (1) কেবলমাত্র যদি টেবিলটিতে কেবল ধ্রুব সংখ্যক কী থাকে এবং কিছু অন্যান্য অনুমান করা হয়। তবে এ জাতীয় ক্ষেত্রে এর সুবিধা রয়েছে।

আপনার কীতে যদি এন-বিট উপস্থাপনা থাকে তবে আপনার হ্যাশ ফাংশনটি এই বিটগুলির মধ্যে 1, 2, ... n ব্যবহার করতে পারে। 1 টি বিট ব্যবহার করে এমন একটি হ্যাশ ফাংশন সম্পর্কে ভাবনা। মূল্যায়ন নিশ্চিতভাবে ও (1)। তবে আপনি কেবল কী স্পেসটি ২ তে বিভক্ত করছেন So সুতরাং আপনি একই বিনে প্রায় ২ ^ (এন -১) কী ম্যাপিং করছেন। বিএসটি অনুসন্ধান ব্যবহার করে এটি প্রায় পূর্ণ হলে নির্দিষ্ট কী সনাক্ত করতে এন -1 পদক্ষেপ নিতে পারে।

আপনি এটি দেখতে প্রসারিত করতে পারেন যে যদি আপনার হ্যাশ ফাংশনটি কে বি বিট ব্যবহার করে তবে আপনার বিনের আকার 2 ^ (এন কে) হয়।

সুতরাং কে-বিট হ্যাশ ফাংশন ==> 2 ^ K কার্যকরী বিনগুলি ==> 2 বিন্যাসের বেশি (এনকে) এন-বিট কীগুলি প্রতি বিন ==> (এনকে) পদক্ষেপ (বিএসটি) সংঘর্ষগুলি সমাধান করার জন্য। আসলে বেশিরভাগ হ্যাশ ফাংশনগুলি খুব কম "কার্যকর" হয় এবং 2 ^ কে বিইন তৈরি করতে কে বিটসের চেয়ে বেশি / প্রয়োজন হয়। এমনকি এটি আশাবাদী।

আপনি এটিকে এটি দেখতে পারেন - সবচেয়ে খারাপ ক্ষেত্রে এন বিটের কীগুলির একজোড়া আলাদাভাবে আলাদা করতে আপনার ~ n পদক্ষেপের প্রয়োজন হবে। এই তথ্যের তত্ত্বের সীমা, হ্যাশ টেবিলটি বা না পাওয়ার সত্যিকারের কোনও উপায় নেই।

তবে, আপনি হ্যাশ টেবিলটি কীভাবে / কখন ব্যবহার করবেন তা নয়!

জটিলতা বিশ্লেষণ ধরে নেওয়া হয়েছে যে এন-বিট কীগুলির জন্য আপনার টেবিলে ও (2 ^ n) কী থাকতে পারে (যেমন সমস্ত সম্ভাব্য কীগুলির 1/4)। তবে বেশিরভাগ ক্ষেত্রে যদি আমরা হ্যাশ টেবিল ব্যবহার করি না, তবে আমাদের কেবল টেবিলের এন-বিট কীগুলির একটি ধ্রুবক সংখ্যা রয়েছে। আপনি যদি কেবল টেবিলের ধ্রুবক সংখ্যক কীগুলি চান তবে সি আপনার সর্বাধিক সংখ্যা বলুন, তবে আপনি হে (সি) বিনের একটি হ্যাশ টেবিল গঠন করতে পারেন, এটি প্রত্যাশিত ধ্রুবক সংঘর্ষের নিশ্চয়তা দেয় (একটি ভাল হ্যাশ ফাংশন সহ); এবং কীতে এন বিটের ~ লগসি ব্যবহার করে একটি হ্যাশ ফাংশন। তারপরে প্রতিটি ক্যোয়ারি হল ও (লগসি) = ও (1)। এইভাবে লোকেরা দাবি করে যে "হ্যাশ টেবিল অ্যাক্সেস ও ও (1)" /

এখানে বেশ কয়েকটি ক্যাচ রয়েছে - প্রথমে আপনাকে বলার দরকার নেই যে সমস্ত বিট দরকার নেই কেবলমাত্র বিলিংয়ের কৌশল। প্রথমে আপনি হ্যাশ ফাংশনের মূল মানটি সত্যিই পাস করতে পারবেন না, কারণ এটি মেমরিতে এন বিটগুলি চলবে যা হে (এন)। সুতরাং আপনার প্রয়োজন যেমন একটি রেফারেন্স পাসিং। তবে আপনাকে এখনও এটি অন্য কোথাও সংরক্ষণ করতে হবে যা একটি ও (এন) অপারেশন ছিল; আপনি কেবল এটি হ্যাশিংয়ের সাথে বিল করবেন না; আপনি সামগ্রিক গণনার কাজ এড়াতে পারবেন না। দ্বিতীয়ত, আপনি হ্যাশিং করছেন, বিনটি খুঁজে পেয়েছেন এবং 1 টিরও বেশি চাবি খুঁজে পেয়েছেন; আপনার ব্যয়টি আপনার রেজোলিউশন পদ্ধতির উপর নির্ভর করে - যদি আপনি তুলনা ভিত্তিক (বিএসটি বা তালিকা) করেন তবে আপনার ও (এন) অপারেশন হবে (রিকাল কীটি এন-বিট); যদি আপনি ২ য় হ্যাশ করেন তবে ভাল, ২ য় হ্যাশের সংঘর্ষ হলে আপনার একই সমস্যা রয়েছে।

এক্ষেত্রে বিকল্প হিসাবে যেমন বিএসটি বিবেচনা করুন। সি কী রয়েছে, সুতরাং ভারসাম্যপূর্ণ বিএসটি গভীরতার সাথে ও (লগসি) হবে, সুতরাং একটি অনুসন্ধান ও (লগসি) পদক্ষেপ নেয়। তবে এই ক্ষেত্রে তুলনা করা একটি ও (এন) অপারেশন হবে ... সুতরাং দেখা যাচ্ছে হ্যাশিং এই ক্ষেত্রে একটি ভাল পছন্দ।


1

টিএল; ডিআর: O(1)হ্যাশ ফাংশনগুলির একটি সার্বজনীন পরিবার থেকে এলোমেলোভাবে যদি আপনি আপনার হ্যাশ ফাংশনটি বেছে নেন তবে হ্যাশ টেবিলগুলি প্রত্যাশিত খারাপ পরিস্থিতি সময়ের নিশ্চয়তা দেয় । প্রত্যাশিত নিকৃষ্টতম পরিস্থিতি গড়ের ক্ষেত্রে একই নয়।

দাবি অস্বীকার: আমি হ্যাশ টেবিলগুলি আনুষ্ঠানিকভাবে প্রমাণ করি না O(1), তার জন্য অবশ্যই এই ভিডিওটি দেখে নেওয়া উচিত [ 1 ]। আমি amorised সম্পর্কে আলোচনা না হ্যাশ টেবিলগুলির দিকগুলি । এটি হ্যাশিং এবং সংঘর্ষ সম্পর্কে আলোচনার অর্থেগোনাল।

আমি অন্যান্য উত্তর এবং মন্তব্যে এই বিষয়টিকে ঘিরে একটি আশ্চর্যজনকরকম বিভ্রান্তি দেখছি, এবং এই দীর্ঘ উত্তরে তাদের কয়েকটি সংশোধন করার চেষ্টা করব।

সবচেয়ে খারাপ পরিস্থিতি নিয়ে যুক্তি

বিভিন্ন ধরণের নিকৃষ্ট মামলার বিশ্লেষণ রয়েছে। বিশ্লেষণ যে অধিকাংশ উত্তর এখানে এতদূর করেছি নয় সবচেয়ে খারাপ ক্ষেত্রে, বরং গড় কেস [ 2 ]। গড় ক্ষেত্রে বিশ্লেষণ আরো ব্যবহারিক হতে থাকে। হতে পারে আপনার অ্যালগরিদমের একটি খারাপ খারাপ কেস ইনপুট রয়েছে তবে অন্য সমস্ত সম্ভাব্য ইনপুটগুলির পক্ষে আসলে ভাল কাজ করে। বটমলাইন হ'ল আপনার রানটাইমটি আপনি যে ডেটাसेट চালাচ্ছেন তার উপর নির্ভর করে।

getহ্যাশ টেবিলের পদ্ধতির নীচের সিউডোকোডটি বিবেচনা করুন । এখানে আমি ধরে নিচ্ছি যে শৃঙ্খলাবদ্ধ হয়ে আমরা সংঘর্ষটি পরিচালনা করি, সুতরাং সারণির প্রতিটি প্রবেশই (key,value)জোড়াগুলির লিঙ্কযুক্ত তালিকা । আমরা ধরে নিই যে বালতিগুলির সংখ্যা mস্থির রয়েছে তবে তা হল O(n), nইনপুটে উপাদানগুলির সংখ্যা কোথায় ।

function get(a: Table with m buckets, k: Key being looked up)
  bucket <- compute hash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

অন্যান্য উত্তরগুলি যেমন উল্লেখ করেছে যে এটি গড় O(1)এবং সবচেয়ে খারাপ ক্ষেত্রে চলেO(n) । আমরা এখানে চ্যালেঞ্জ করে একটি প্রমাণের একটু স্কেচ তৈরি করতে পারি। চ্যালেঞ্জটি নিম্নরূপ:

(1) আপনি আপনার হ্যাশ টেবিল অ্যালগরিদমকে প্রতিপক্ষকে দেন।

(২) শত্রুরা এটি অধ্যয়ন করতে পারে এবং যতক্ষণ ইচ্ছা সে ​​প্রস্তুত করতে পারে।

(3) শেষ পর্যন্ত বিরোধী আপনাকে nনিজের টেবিলে .োকানোর জন্য আকারের একটি ইনপুট দেয় ।

প্রশ্নটি হল: প্রতিপক্ষের ইনপুটটিতে আপনার হ্যাশ টেবিলটি কত গতিযুক্ত?

পদক্ষেপ (1) থেকে শত্রুরা আপনার হ্যাশ ফাংশনটি জানে; পদক্ষেপের সময় (২) শত্রুরা nউপাদানগুলির সাথে তালিকার একটি তালিকা তৈরি করতে পারে hash modulo m, উদাহরণস্বরূপ, এলোমেলোভাবে একটি গুচ্ছ উপাদানগুলির হ্যাশ গণনা করা; এবং তারপরে (3) তারা আপনাকে সেই তালিকা দিতে পারে। তবে দেখুন এবং দেখুন যেহেতু সমস্ত nউপাদান একই বালতিতে হ্যাশ করে, আপনার অ্যালগরিদম সেই বালতিটির O(n)লিঙ্কযুক্ত তালিকাকে অতিক্রম করতে সময় নেবে take আমরা যতবার চ্যালেঞ্জটি আবার চেষ্টা করি না কেন, বিরোধীরা সর্বদা জয়ী হয় এবং এটিই আপনার অ্যালগরিদমটি কতটা খারাপ, সবচেয়ে খারাপ পরিস্থিতি O(n)

কীভাবে হ্যাশিং আসে ও (1)?

পূর্ববর্তী চ্যালেঞ্জের মধ্যে যে বিষয়টি আমাদের ফেলেছিল তা হ'ল শত্রুরা আমাদের হ্যাশ ফাংশনটি খুব ভাল করে জানত এবং সেই জ্ঞানটিকে সবচেয়ে খারাপতম ইনপুট কারুকাজ করতে ব্যবহার করতে পারে। তবে যদি সর্বদা একটি স্থির হ্যাশ ফাংশন ব্যবহার না করে আমাদের আসলে হ্যাশ ফাংশনগুলির একটি সেট থাকে H, যেটি অ্যালগরিদম এলোমেলোভাবে রানটাইম থেকে বেছে নিতে পারে? আপনি যদি কৌতূহলী হন Hতবে তাকে হ্যাশ ফাংশনগুলির একটি সার্বজনীন পরিবার বলা হয় [ 3 ]। ঠিক আছে, এর সাথে কিছু এলোমেলোতা যুক্ত করার চেষ্টা করি ।

প্রথম ধরুন আমাদের হ্যাশ টেবিলটিতে একটি বীজও রয়েছে r, এবং rনির্মাণের সময় এলোমেলো সংখ্যায় নির্ধারিত হয়। আমরা এটি একবার বরাদ্দ করি এবং তারপরে এটি হ্যাশ টেবিলের দৃষ্টান্তের জন্য ঠিক করা হয়। এখন আসুন আমাদের সিউডোকোডটি ঘুরে দেখি।

function get(a: Table with m buckets and seed r, k: Key being looked up)
  rHash <- H[r]
  bucket <- compute rHash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

আমরা যদি আরও একবার চ্যালেঞ্জটি চেষ্টা করি: পদক্ষেপ (1) থেকে শত্রুরা আমাদের থাকা সমস্ত হ্যাশ ফাংশন জানতে পারে H, তবে এখন আমরা নির্দিষ্ট নির্দিষ্ট হ্যাশ ফাংশনটি নির্ভর করি r। এর মানটি rআমাদের কাঠামোর কাছে ব্যক্তিগত, শত্রুরা রানটাইমে এটি পরীক্ষা করতে পারে না বা সময়ের পূর্বে ভবিষ্যদ্বাণী করতে পারে না, তাই তিনি আমাদের পক্ষে সর্বদা খারাপ এমন একটি তালিকা তৈরি করতে পারেন না। এর অনুমান করা ধাপে (2) প্রতিদ্বন্দ্বী এক ফাংশন বেছে করা যাক যে hashমধ্যে Hএলোমেলোভাবে, তারপর তিনি একটি তালিকা নৈপুণ্য করে nঅধীনে দুর্ঘটনায় hash modulo m, এবং পাঠায় পদক্ষেপ (3) আঙ্গুলের যে রানটাইম এ পার H[r]একই হবে hashতারা বেছে নেওয়া হয়েছে।

এটি বিরোধীদের পক্ষে মারাত্মক বাজি, তিনি তৈরি করেছিলেন এমন তালিকাটি সংঘর্ষে পড়েছে hashতবে এটি অন্য কোনও হ্যাশ ফাংশনের অধীনে একটি এলোমেলো ইনপুট হবে H। যদি তিনি এই বাজিটি জিতেন তবে আমাদের রান সময়টি O(n)আগের মতো খারাপ পরিস্থিতি হয়ে উঠবে , তবে যদি সে হেরে যায় তবে আমাদের কেবল একটি এলোমেলো ইনপুট দেওয়া হচ্ছে যা গড় O(1)সময় নেয় । এবং প্রকৃতপক্ষে শত্রুরা সবচেয়ে বেশিবার হারাবে, তিনি প্রতি |H|চ্যালেঞ্জের মধ্যে একবারই জয়ী হন এবং আমরা |H|খুব বড় হতে পারি ।

পূর্ববর্তী অ্যালগরিদমের সাথে এই ফলাফলটির তুলনা করুন যেখানে প্রতিপক্ষরা সর্বদা চ্যালেঞ্জকে জয়ী করে। এখানে একটু Handwaving, কিন্তু যেহেতু সবচেয়ে বার প্রতিদ্বন্দ্বী ব্যর্থ হবে, এবং এই সব সম্ভব কৌশল প্রতিদ্বন্দ্বী চেষ্টা করতে পারেন জন্য সত্য বোঝা যায় যে, যদিও খারাপ ক্ষেত্রে দেখা যায় O(n), প্রত্যাশিত সবচেয়ে খারাপ ক্ষেত্রে আসলে O(1)


আবার এটি কোনও আনুষ্ঠানিক প্রমাণ নয়। এই প্রত্যাশিত খারাপ ক্ষেত্রে বিশ্লেষণ থেকে আমরা যে গ্যারান্টি পেয়েছি তা হ'ল আমাদের রান সময়টি এখন কোনও নির্দিষ্ট ইনপুট থেকে স্বতন্ত্র । এটি সত্যিকারের এলোমেলো গ্যারান্টি, যেখানে গড় কেস বিশ্লেষণের বিপরীতে যেখানে আমরা দেখিয়েছি যে প্রেরণিত প্রতিপক্ষ খুব সহজেই খারাপ ইনপুট কারুকাজ করতে পারে।


0

দুটি সেটিংস রয়েছে যার অধীনে আপনি ও (1) খারাপ পরিস্থিতি বার পেতে পারেন ।

  1. যদি আপনার সেটআপ স্থিতিশীল হয়, তবে এফকেএস হ্যাশিং আপনাকে সবচেয়ে খারাপ ক্ষেত্রে (O) গ্যারান্টি দেবে। আপনি যেমন ইঙ্গিত করেছেন, আপনার সেটিংস স্থির নয়।
  2. আপনি যদি কোকিল হ্যাশিং ব্যবহার করেন, তবে অনুসন্ধানগুলি এবং মুছে ফেলা হ'ল ও (1) সবচেয়ে খারাপ পরিস্থিতি, তবে সন্নিবেশ কেবলমাত্র ও (1) প্রত্যাশিত। মোট serোকানোর সংখ্যার উপর যদি আপনার উপরের আবদ্ধ থাকে এবং টেবিলের আকারটি প্রায় 25% বড় হতে পারে তবে কোকিল হ্যাশিং বেশ ভাল কাজ করে।

এখান থেকে অনুলিপি করা হয়েছে


0

এখানে আলোচনার ভিত্তিতে মনে হয়, এক্স যদি সারণি হয় (টেবিলের / # বিনের # উপাদানগুলির সিলিং), তবে এর চেয়ে আরও ভাল উত্তর হ'ল ল (লগ (এক্স)) বিন লুকের একটি কার্যকর বাস্তবায়ন ধরে।


0

উ: মান হ্যাশ টেবিলের আকারের চেয়ে ছোট একটি অন্তর্ভুক্ত। অতএব, মানটি তার নিজস্ব হ্যাশ, সুতরাং কোনও হ্যাশ টেবিল নেই। তবে যদি এটি থাকে তবে এটি ও (1) হবে এবং এখনও অদক্ষ।

এটি এমন একটি ক্ষেত্রে যেখানে আপনি তুচ্ছভাবে স্বতন্ত্র বালতির কীগুলি ম্যাপ করতে পারতেন, সুতরাং একটি অ্যারে হ্যাশ টেবিলের চেয়ে ডেটা কাঠামোর চেয়ে ভাল পছন্দ বলে মনে হয়। তবুও, অদক্ষতাগুলি টেবিলের আকারের সাথে বৃদ্ধি পায় না।

(আপনি এখনও একটি হ্যাশ টেবিল ব্যবহার করতে পারেন কারণ প্রোগ্রামটি বিকশিত হওয়ার সাথে সাথে আপনি টেবিলের আকারের চেয়ে ছোট থাকার জন্য অন্তর্নিহিতদের বিশ্বাস করেন না, আপনি যখন সম্পর্কটি ধরে না রাখেন তখন আপনি কোডটি সম্ভাব্য পুনরায় ব্যবহারযোগ্য করে তুলতে চান, বা আপনি কেবল এটি করেন না কোড পড়তে / বজায় রাখা লোকেরা মানসিক প্রচেষ্টা বোঝার এবং সম্পর্ক বজায় রাখতে নষ্ট করতে চায়)।

বি। আপনাকে মানটির একটি হ্যাশ গণনা করতে হবে। এই পরিস্থিতিতে, ডেটা সন্ধান করা হচ্ছে তার আকারের জন্য আদেশ (ও) is আপনি ও (এন) কাজ করার পরে অনুসন্ধানটি ও (1) হতে পারে তবে এটি এখনও আমার চোখে ও (এন) এর বাইরে আসে।

আমাদের কী (যেমন বাইটে) এর আকার এবং হ্যাশ টেবিলের মধ্যে কী কী সংখ্যক সংরক্ষণ করা হচ্ছে তার মাপের মধ্যে পার্থক্য করতে হবে। হ্যাশ টেবিলগুলি ও (1) ক্রিয়াকলাপ সরবরাহ করে এমন দাবিগুলির অর্থ কীগুলি সংখ্যা বাড়ার সাথে সাথে অপারেশনগুলি (সন্নিবেশ / মুছা / সন্ধান) আরও ধীর করে না কয়েকশ থেকে হাজারে লক্ষ লক্ষ হয়ে যায় (কমপক্ষে সমস্ত ডেটা না থাকলে না সমান দ্রুত স্টোরেজে অ্যাক্সেস করা / আপডেট করা হয়, র‌্যাম বা ডিস্ক থাকুক - ক্যাশে প্রভাবগুলি কার্যকর হতে পারে তবে সবচেয়ে খারাপ ক্ষেত্রে ক্যাশে মিসের ব্যয়টি বেস্ট-কেস হিটের কয়েকটি ধ্রুবক হতে পারে)।

একটি টেলিফোন বইয়ের কথা বিবেচনা করুন: আপনার নাম থাকতে পারে যা বেশ দীর্ঘ are

যে কারও দ্বারা ব্যবহৃত সবচেয়ে দীর্ঘ নামের গিনেসের বিশ্ব রেকর্ডটি সেট করেছিলেন অ্যাডলফ ব্লেইন চার্লস ডেভিড আর্ল ফ্রেডেরিক জেরাল্ড হুবার্ট ইরভিন জন কেনেথ লয়েড মার্টিন নেরো অলিভার পল কুইন্সি র্যান্ডলফ শেরম্যান টমাস উনকাস ভিক্টর উইলিয়াম জেরেক্সেস ইয়েন্সি ওল্ফেসচ্লেজস্টেইনহাউসেনবার্গারডর্ফ,

... wcআমাকে বলে যে 215 টি অক্ষর - যে না একটি কঠিন কী দৈর্ঘ্য উপরের-বাউন্ড, কিন্তু আমরা হচ্ছে সেখানে সম্পর্কে চিন্তা করতে প্রয়োজন হবে না ব্যাপক আরও অনেক কিছু।

এটি বেশিরভাগ বাস্তব ওয়ার্ল্ড হ্যাশ টেবিলের জন্য ধারণ করে: গড় কী দৈর্ঘ্যের ব্যবহারের কীগুলির সংখ্যা বাড়ার ঝোঁক থাকে না। ব্যতিক্রম রয়েছে, উদাহরণস্বরূপ একটি মূল তৈরি রুটিনটি বাড়ানো পূর্ণসংখ্যার এম্বেড করে স্ট্রিংগুলি ফিরে আসতে পারে তবে তারপরেও প্রতিবার আপনি মাত্রার অর্ডার দিয়ে কীগুলির সংখ্যা বাড়িয়েছেন কেবলমাত্র 1 টি অক্ষর দ্বারা মূল দৈর্ঘ্য বৃদ্ধি করবেন: এটি তাত্পর্যপূর্ণ নয়।

স্থির আকারের কী ডেটা থেকে একটি হ্যাশ তৈরি করাও সম্ভব। উদাহরণস্বরূপ, স্ট্যান্ডার্ড লাইব্রেরি প্রয়োগের সাথে মাইক্রোসফ্টের ভিজ্যুয়াল সি ++ জাহাজ std::hash<std::string>স্ট্রিংয়ের সাথে একইভাবে স্থানিত দশটি বাইট সমেত একটি হ্যাশ তৈরি করে, তাই যদি অন্য সূচকগুলিতে কেবল স্ট্রিংগুলি পরিবর্তিত হয় তবে আপনি সংঘর্ষ পেতে পারেন (এবং তাই অনুশীলনে নন ও (1) আচরণে সংঘর্ষের পরে অনুসন্ধানের দিকে), তবে হ্যাশ তৈরির সময়টির উপরের বাঁধাই শক্ত।

এবং আপনার কাছে নিখুঁত হ্যাশ বা একটি বড় হ্যাশ টেবিল না থাকলে সম্ভবত বালতিতে বেশ কয়েকটি আইটেম রয়েছে। সুতরাং, এটি যে কোনও উপায়ে একটি ছোট রৈখিক অনুসন্ধানে রূপান্তরিত হয়।

সাধারণত সত্য, তবে হ্যাশ টেবিলগুলির সম্পর্কে দুর্দান্ত বিষয়টি হ'ল যে "ছোট ছোট রৈখিক অনুসন্ধানগুলি" চলাকালীন পরিদর্শন করা কীগুলির সংখ্যা হ'ল সংঘর্ষগুলির জন্য পৃথক শৃঙ্খলা পদ্ধতির জন্য - হ্যাশ টেবিল লোড ফ্যাক্টরের একটি কার্য (বালতির কীগুলির অনুপাত)।

উদাহরণস্বরূপ, ০.০ এর লোড ফ্যাক্টরের সাথে কীগুলির সংখ্যা নির্বিশেষে line 1.58 ডলার লিনিয়ার অনুসন্ধানগুলির দৈর্ঘ্য পর্যন্ত রয়েছে ( আমার উত্তর এখানে দেখুন )। জন্য বদ্ধ হ্যাশ এটি একটি বিট আরো জটিল, কিন্তু অনেক না খারাপ যখন লোড ফ্যাক্টর খুব বেশী নয় আছে।

এটি প্রযুক্তিগতভাবে সত্য কারণ হ্যাশ ফাংশনটি কীতে সমস্ত তথ্য ব্যবহার করার প্রয়োজন হয় না এবং এটি ধ্রুবক সময় হতে পারে, এবং কারণ একটি বৃহত পর্যায়ে টেবিল সংঘর্ষগুলি কাছাকাছি স্থির সময়ের দিকে নামিয়ে আনতে পারে।

এই জাতীয় বিন্দু মিস করে। যে কোনও ধরনের সহযোগী ডেটা কাঠামো শেষ পর্যন্ত কীটির প্রতিটি অংশ জুড়ে অপারেশন করতে হয় (বৈষম্য কখনও কখনও কীগুলির কেবলমাত্র একটি অংশ থেকে নির্ধারিত হতে পারে, তবে সাম্যকে সাধারণত প্রতিটি বিট বিবেচনা করা প্রয়োজন)। সর্বনিম্ন, এটি একবার কীটি হ্যাশ করতে পারে এবং হ্যাশটির মানটি সংরক্ষণ করতে পারে এবং যদি এটি যথেষ্ট শক্তিশালী হ্যাশ ফাংশন ব্যবহার করে - যেমন 64৪-বিট এমডি 5 - এটি একই মানে দুটি কী হ্যাশ করার সম্ভাবনাটিকে কার্যত উপেক্ষা করতে পারে (একটি সংস্থা আমি বিতরণকৃত ডাটাবেসের জন্য ঠিক সেভাবে কাজ করেছি: ডাব্লুএইচএন-ওয়াইড নেটওয়ার্ক সংক্রমণের তুলনায় হ্যাশ-প্রজন্মের সময় এখনও তুচ্ছ ছিল)) সুতরাং, কীটি প্রসেস করার জন্য ব্যয় সম্পর্কে খুব বেশি অবকাশ করার দরকার নেই: এটি ডেটা কাঠামো নির্বিশেষে কীগুলি সংরক্ষণ করার অন্তর্নিহিত, এবং উপরে যেমন বলা হয়েছে - '

যথেষ্ট পরিমাণে হ্যাশ টেবিলগুলি সংঘর্ষগুলি নামিয়ে আনছে, এটিও বিন্দুটি অনুপস্থিত। পৃথক শৃঙ্খলার জন্য, আপনার দেওয়া যে কোনও লোড ফ্যাক্টরের কাছে এখনও ধ্রুবক গড় সংঘর্ষ শৃঙ্খলার দৈর্ঘ্য রয়েছে - লোড ফ্যাক্টর বেশি হলে এটি কেবল উচ্চতর হয় এবং সেই সম্পর্কটি অ-রৈখিক হয়। আমার উত্তর সম্পর্কে এসও ব্যবহারকারী হান্স মন্তব্যগুলির উপরেও লিঙ্ক করেছেন:

মজাদার বালতিতে শর্তযুক্ত গড় বালতির দৈর্ঘ্য দক্ষতার একটি আরও ভাল পরিমাপ। এটি একটি / (1-e ^ {- a}) [যেখানে a লোড ফ্যাক্টর, e হল 2.71828 ...]

সুতরাং, একা লোড ফ্যাক্টর সন্নিবেশ / মুছা / সন্ধানের ক্রিয়াকলাপগুলির মধ্যে আপনাকে যে সংঘর্ষের কীগুলি অনুসন্ধান করতে হবে তার গড় সংখ্যা নির্ধারণ করে। পৃথক শৃঙ্খলার জন্য, লোড ফ্যাক্টর কম হলে এটি কেবল ধ্রুবক হওয়ার কাছে যায় না - এটি সর্বদা স্থির থাকে। আপনার দাবির কিছু বৈধতা থাকলেও খোলা সম্বোধনের জন্য: কিছু সংঘর্ষকারী উপাদানগুলি বিকল্প বালতিতে পুনর্নির্দেশ করা হয় এবং তারপরে অন্যান্য কীগুলিতে ক্রিয়াকলাপে হস্তক্ষেপ করতে পারে, তাই উচ্চতর লোডের কারণগুলিতে (বিশেষত> .8 বা .9) সংঘর্ষ শৃঙ্খলার দৈর্ঘ্য আরও নাটকীয়ভাবে খারাপ হয়ে যায়।

এটি বাস্তবে সত্য কারণ সময়ের সাথে সাথে এটি কেবলমাত্র কার্যকর হয় যতক্ষণ না হ্যাশ ফাংশন এবং টেবিলের আকার সংঘটন হ্রাস করতে বেছে নেওয়া হয়, যদিও এর অর্থ প্রায়শই স্থির সময় হ্যাশ ফাংশনটি ব্যবহার না করা।

ঠিক আছে, টেবিলের আকারটি হ্যাশিং বা পৃথক চেইনিংয়ের পছন্দ অনুসারে একটি বুদ্ধিমান লোড ফ্যাক্টরের ফলস্বরূপ হওয়া উচিত, তবে হ্যাশ ফাংশনটি যদি কিছুটা দুর্বল হয় এবং কীগুলি খুব এলোমেলো না হয় তবে প্রাথমিক স্তরের বালতিগুলি প্রায়শ হ্রাস করতে সহায়তা করে সংঘর্ষগুলিও ( hash-value % table-sizeতারপরে এমনভাবে আবৃত হয় যা হ্যাশ-মানটিতে কেবলমাত্র একটি উচ্চ অর্ডার বিট বা দুটিতে পরিবর্তিত হয় যা এখনও হ্যাশ টেবিলের বিভিন্ন অংশে ছদ্ম-এলোমেলোভাবে ছড়িয়ে বালতিগুলিতে সংশোধন করে)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.