কিভাবে একটি জাভা হ্যাশম্যাপ একই হ্যাশ কোড সহ বিভিন্ন বস্তু পরিচালনা করে?


223

আমার বোধ অনুযায়ী আমি মনে করি:

  1. দুটি অবজেক্টের জন্য একই হ্যাশকোড থাকা পুরোপুরি আইনী।
  2. যদি দুটি বস্তু সমান হয় (সমান () পদ্ধতিটি ব্যবহার করে) তবে তাদের একই হ্যাশকোড রয়েছে।
  3. দুটি বস্তু যদি সমান না হয় তবে তাদের একই হ্যাশকোড থাকতে পারে না

আমি কি সঠিক?

এখন যদি সঠিক হয় তবে আমার কাছে নিম্নলিখিত প্রশ্ন রয়েছে: HashMapঅভ্যন্তরীণভাবে অবজেক্টটির হ্যাশকোড ব্যবহার করা হয়। সুতরাং যদি দুটি বস্তুর একই হ্যাশকোড থাকতে পারে, তবে HashMapএটি কোন কীটি ব্যবহার করবে তা ট্র্যাক কিভাবে করতে পারে?

HashMapঅভ্যন্তরীণভাবে কীভাবে অবজেক্টটির হ্যাশকোড ব্যবহার করা যায় তা কেউ ব্যাখ্যা করতে পারেন ?


29
রেকর্ডের জন্য: # 1 এবং # 2 সঠিক, # 3 টি ভুল: দুটি বস্তু যা সমান নয় তাদের একই হ্যাশ কোড থাকতে পারে।
জোচিম সৌর 15

6
# 1 এবং # 3 এমনকি
বিরোধী

প্রকৃতপক্ষে, যদি # 2 অনুসরণ না করা হয় তবে সমান () বাস্তবায়ন (বা যুক্তিযুক্তভাবে হ্যাশকোড ()) ভুল।
জোছিম সউর

উত্তর:


346

একটি হ্যাশম্যাপ এটির মতো কাজ করে (এটি সামান্য সরল, তবে এটি মৌলিক প্রক্রিয়াটি চিত্রিত করে):

এটিতে বেশ কয়েকটি "বালতি" রয়েছে যা এটি কী-মান জোড়গুলিকে সঞ্চয় করতে ব্যবহার করে Each প্রতিটি বালতিটির একটি স্বতন্ত্র সংখ্যা রয়েছে - যা বালতিটি চিহ্নিত করে। আপনি যখন মানচিত্রে একটি মূল-মান জুড়ি রাখবেন, হ্যাশম্যাপ কীটির হ্যাশ কোডটি দেখবে এবং সেই জুটিটি বালতিতে সংরক্ষণ করবে যার শনাক্তকারী কীটির হ্যাশ কোড। উদাহরণস্বরূপ: কীটির হ্যাশ কোডটি 235 -> জোড়াটি বালতি নম্বর 235-এ সঞ্চিত থাকে ((নোট করুন যে একটি বালতি আরও একটি কী-মান জুড়ি সংরক্ষণ করতে পারে)।

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

এখন আপনি দেখতে পাচ্ছেন যে কীভাবে মানচিত্রে কী-মান জোড়ার সন্ধানের জন্য এটি অত্যন্ত দক্ষ: কীটির হ্যাশ কোড দ্বারা হ্যাশম্যাপটি তাত্ক্ষণিকভাবে জানে যে কোন বালতিটি দেখতে হবে, যাতে কেবল সেই বালতিতে কী আছে তার বিরুদ্ধে পরীক্ষা করতে হয়।

উপরের প্রক্রিয়াটি দেখে আপনি কীগুলির পদ্ধতি hashCode()এবং equals()পদ্ধতিগুলির জন্য প্রয়োজনীয় প্রয়োজনীয়তাগুলিও দেখতে পাবেন :

  • যদি দুটি কী একই হয় ( আপনি যখন তাদের তুলনা করবেন তখন equals()ফিরে আসবেন true), তাদের hashCode()পদ্ধতিতে একই নম্বরটি অবশ্যই ফিরে আসতে হবে। কীগুলি যদি এটি লঙ্ঘন করে, তবে সমান চাবিগুলি বিভিন্ন বালতিতে সঞ্চিত থাকতে পারে এবং হ্যাশম্যাপ কী-মান যুক্তগুলি খুঁজে পেতে সক্ষম হবে না (কারণ এটি একই বালতিতে দেখা যাচ্ছে)।

  • যদি দুটি কী পৃথক হয় তবে তাদের হ্যাশ কোডগুলি একই কিনা তা বিবেচনা করে না। যদি তাদের হ্যাশ কোডগুলি একই হয় তবে এগুলি একই বালতিতে সংরক্ষণ করা হবে এবং এই ক্ষেত্রে, হ্যাশম্যাপটি equals()তাদের আলাদা করে বলার জন্য ব্যবহার করবে ।


4
আপনি লিখেছেন "এবং হ্যাশম্যাপ কী-মানযুক্ত জোড়গুলি খুঁজে পেতে সক্ষম হবে না (কারণ এটি একই বালতিতে সন্ধান করা যাচ্ছে)"। আপনি কি এটি একই বালতিতে দেখতে যাচ্ছেন তা বলতে পারবেন যে দুটি সমান বস্তু টি 1 এবং টি 2 এবং এগুলি সমান এবং টি 1 এবং টি 2 এর যথাক্রমে হ্যাশকোড এইচ 1 এবং এইচ 2 রয়েছে। সুতরাং t1.equals (t2) = সত্য এবং এইচ 1! = এইচ 2 সুতরাং যখন হ্যাশম্যাপটি টি 1 খুঁজবে, তখন এটি বালতি এইচ 1 এ এবং বালতি টি 2 তে টি 2 জন্য সন্ধান করবে?
গীক

19
যদি দুটি কী সমান হয় তবে তাদের hashCode()পদ্ধতিতে বিভিন্ন হ্যাশ কোডগুলি ফেরত আসে, তবে কী শ্রেণীর পদ্ধতি equals()এবং hashCode()পদ্ধতিগুলি চুক্তি লঙ্ঘন করে এবং একটিতে এই কীগুলি ব্যবহার করার সময় আপনি অদ্ভুত ফলাফল পাবেন HashMap
জেস্পার

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

1
@ অঙ্কিতশর্মা যদি আপনি সমস্ত বিবরণটি সত্যই জানতে চান তবে উত্স কোডটি অনুসন্ধান করুন HashMap, যা আপনি src.zipআপনার জেডিকে ইনস্টলেশন ডিরেক্টরিতে ফাইলটিতে খুঁজে পেতে পারেন ।
জেস্পার

1
@ 1290 একই বালতিতে কীগুলির মধ্যে একমাত্র সম্পর্ক হ'ল তাদের একই হ্যাশ কোড রয়েছে।
জেস্পার

88

আপনার তৃতীয় দাবিটি ভুল।

দুটি অসম বস্তুর জন্য একই হ্যাশ কোড থাকা সম্পূর্ণ বৈধ। এটি HashMapএকটি "প্রথম পাস ফিল্টার" হিসাবে ব্যবহার করা হয়েছে যাতে মানচিত্রটি নির্দিষ্ট কী সহ সম্ভাব্য এন্ট্রিগুলি দ্রুত খুঁজে পেতে পারে । একই হ্যাশ কোড সহ কীগুলি নির্দিষ্ট কীগুলির সাথে সমতার জন্য পরীক্ষা করা হয়।

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


6
আপনি কীভাবে 2 ^ 32 সম্ভাব্য বস্তুতে পৌঁছেছেন?
গীক

5
আমি দেরি করে ফেলেছি, তবে যারা এখনও ভাবছেন তাদের জন্য: জাভাতে একটি হ্যাশকোড একটি অন্তর্নিহিত, এবং একটি অন্তর্গতের 2 ^ 32 সম্ভাব্য মান রয়েছে
জেরুস

69

হ্যাশম্যাপ স্ট্রাকচার ডায়াগ্রাম

HashMapEntryবস্তুর একটি অ্যারে ।

HashMapকেবলমাত্র বস্তুর অ্যারে হিসাবে বিবেচনা করুন ।

এটি কী তা একবার দেখুন Object:

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
 
}

প্রতিটি Entryবস্তু একটি মূল-মান জুড়ি উপস্থাপন করে। যদি বালতিতে একের বেশি থাকে তবে ক্ষেত্রটি nextঅন্য একটি Entryবস্তুকে বোঝায় Entry

কখনও কখনও এটি ঘটতে পারে যে 2 বিভিন্ন বস্তুর জন্য হ্যাশ কোডগুলি একই। এই ক্ষেত্রে, দুটি বালতি একটি বালতিতে সংরক্ষণ করা হবে এবং একটি লিঙ্কযুক্ত তালিকা হিসাবে উপস্থাপিত হবে। এন্ট্রি পয়েন্ট হ'ল সম্প্রতি যুক্ত হওয়া বস্তু object এই বস্তুটি এর সাথে অন্য একটি বস্তুকে বোঝায়next ক্ষেত্রের । শেষ এন্ট্রি বোঝায়null

আপনি যখন HashMapডিফল্ট কনস্ট্রাক্টর দিয়ে একটি তৈরি করেন

HashMap hashMap = new HashMap();

অ্যারেটি 16 মাপ এবং ডিফল্ট 0.75 লোড ব্যালেন্স দিয়ে তৈরি করা হয়েছে।

একটি নতুন কী-মান জুড়ি

  1. কীটির জন্য হ্যাশকোড গণনা করুন
  2. hash % (arrayLength-1)উপাদানটি স্থাপন করতে হবে এমন অবস্থানের গণনা করুন (বালতি নম্বর)
  3. আপনি যদি ইতিমধ্যে সংরক্ষিত এমন একটি কী দিয়ে কোনও মান যুক্ত করার চেষ্টা করেন HashMapতবে মানটি ওভাররাইট হয়ে যায়।
  4. অন্যথায় বালতিতে উপাদান যুক্ত করা হয়।

বালতিতে ইতিমধ্যে কমপক্ষে একটি উপাদান থাকলে, একটি নতুন যুক্ত হয় এবং বালতির প্রথম অবস্থানে স্থাপন করা হয়। এর nextক্ষেত্রটি পুরানো উপাদানকে বোঝায়।

মুছিয়াতা

  1. প্রদত্ত কীটির জন্য হ্যাশকোড গণনা করুন
  2. বালতি নম্বর গণনা করুন hash % (arrayLength-1)
  3. বালতিতে প্রথম এন্ট্রি অবজেক্টের একটি রেফারেন্স পান এবং প্রদত্ত বালতিতে সমস্ত প্রবেশপথের সমান পদ্ধতির মাধ্যমে পুনরাবৃত্তি করুন। শেষ পর্যন্ত আমরা সঠিক খুঁজে পেতে হবে Entry। যদি কোনও কাঙ্ক্ষিত উপাদান না পাওয়া যায় তবে ফিরে আসুনnull

2
এটি ভুল hash % (arrayLength-1)হবে hash % arrayLength। তবে এটি আসলে hash & (arrayLength-1) । এটি হ'ল, কারণ এটি 2^nঅ্যারের দৈর্ঘ্যের জন্য দুটি ( ) এর শক্তি ব্যবহার করে , nকমপক্ষে উল্লেখযোগ্য বিট গ্রহণ করে।
ওয়েস্টন

আমি মনে করি এটি লিঙ্কডলিস্ট / গাছের অ্যারের পরিবর্তে সত্তা সামগ্রীর অ্যারে নয়। এবং প্রতিটি গাছের অভ্যন্তরীণভাবে সত্তা অবজেক্ট থাকে।
মুদিত ভৈন্টওয়াল

@ শেভচাইক কেন আমরা কী এবং হ্যাশ সঞ্চয় করি? তাদের ব্যবহার কি? আমরা কি এখানে স্মৃতি নষ্ট করছি না?
রুট ট্র্যাভেলার

হ্যাশসেট অভ্যন্তরীণভাবে হ্যাশম্যাপ ব্যবহার করে। হ্যাশম্যাপের সংযোজন এবং মোছার নিয়মগুলি কি হ্যাশসেটের পক্ষে ভাল?
অপরাহ্ন

2
@ ওয়েস্টন কেবল এটিই নয়, হ্যাশকোড intযা অবশ্যই নেতিবাচক হতে পারে, একটি নেতিবাচক সংখ্যায় মডুলো করা আপনাকে একটি নেতিবাচক সংখ্যা দেবে
ইউজিন

35

আপনি http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html এ চমৎকার তথ্য খুঁজে পেতে পারেন

সংক্ষেপ:

হ্যাশম্যাপ হ্যাশিংয়ের নীতিতে কাজ করে

পুট (কী, মান): হ্যাশম্যাপ মানচিত্রের হিসাবে কী এবং মান উভয় বস্তু সংরক্ষণ করে nt বালতি পেতে হ্যাশম্যাপ হ্যাশকোড (কী) প্রয়োগ করে। যদি সংঘর্ষ হয় তবে হ্যাশম্যাপ অবজেক্ট স্টোর করতে লিংকডলিস্ট ব্যবহার করে।

get (কী): হ্যাশম্যাপ বাল্টির অবস্থানটি জানতে কী অবজেক্টের হ্যাশকোড ব্যবহার করে লিঙ্কডলিস্টে সঠিক নোড সনাক্ত করতে কীস.সেকুয়ালস () পদ্ধতিটি কল করুন এবং জাভা হ্যাশম্যাপে সেই কীটির জন্য সম্পর্কিত মান অবজেক্টটি ফিরিয়ে আনুন।


3
আমি জ্যাস্পারের দেওয়া উত্তরটি আরও ভালভাবে পেয়েছি, অনুভব করেছি যে ব্লগটি ধারণাটি বোঝার চেয়ে ইন্টারভিউ পরিচালনা করার দিকে বেশি
নরেন্দ্র এন

@ নরেন্দ্রএন আমি তোমার সাথে একমত
অভিজিৎ গায়কওয়াদ

22

সংস্করণের HashMapজন্য এর মেকানিজম সম্পর্কে মোটামুটি বর্ণনা এখানে দেওয়া হয়েছে (এটি জাভা 6 থেকে কিছুটা আলাদা হতে পারে)Java 8


ডাটা স্ট্রাকচার

  • হ্যাশ টেবিল
    হ্যাশ মান hash()অন ​​কী দ্বারা গণনা করা হয়, এবং এটি সিদ্ধান্ত নিয়েছে যে প্রদত্ত কীটির জন্য হ্যাশটেবলের কোন বালতিটি ব্যবহার করতে হবে।
  • লিঙ্কযুক্ত তালিকা (এককভাবে)
    যখন বালতিতে উপাদানগুলির সংখ্যা ছোট হয়, তখন এককভাবে সংযুক্ত তালিকা ব্যবহৃত হয়।
  • লাল-কালো গাছ
    যখন বালতিতে উপাদানের গণনা বড় হয়, তখন একটি লাল-কালো গাছ ব্যবহার করা হয়।

ক্লাস (অভ্যন্তরীণ)

  • Map.Entry
    মানচিত্রে একটি একক সত্তা, কী / মান সত্তাকে উপস্থাপন করুন।
  • HashMap.Node
    নোডের লিঙ্কযুক্ত তালিকার সংস্করণ।

    এটি উপস্থাপন করতে পারে:

    • একটি হ্যাশ বালতি
      কারণ এটির একটি হ্যাশ সম্পত্তি রয়েছে।
    • একক সংযুক্ত তালিকার একটি নোড, (এটি লিঙ্কযুক্ত তালিকার শীর্ষস্থানীয়ও)
  • HashMap.TreeNode
    নোডের গাছের সংস্করণ।

ক্ষেত্রগুলি (অভ্যন্তরীণ)

  • Node[] table
    বালতি টেবিল, (সংযুক্ত তালিকার শীর্ষস্থানীয়)।
    যদি কোনও বালতিতে উপাদান থাকে না, তবে এটি নাল হয়, সুতরাং কেবলমাত্র একটি রেফারেন্সের স্থান নিয়ে যায়।
  • Set<Map.Entry> entrySet সত্তা সেট।
  • int size
    সত্ত্বার সংখ্যা।
  • float loadFactor
    আকার দেওয়ার আগে হ্যাশ টেবিলটি কতটা অনুমোদিত তা নির্দেশ করুন।
  • int threshold
    পরের আকারটি যার আকার পরিবর্তন করতে হবে।
    সূত্র:threshold = capacity * loadFactor

পদ্ধতি (অভ্যন্তরীণ)

  • int hash(key)
    কী দ্বারা হ্যাশ গণনা করুন।
  • কিভাবে বালতি থেকে হ্যাশ মানচিত্র?
    নিম্নলিখিত যুক্তি ব্যবহার করুন:

    static int hashToBucket(int tableSize, int hash) {
        return (tableSize - 1) & hash;
    }

ক্ষমতা সম্পর্কে

হ্যাশ টেবিলে, ক্ষমতা মানে বালতি গণনা, এটি থেকে পাওয়া যেতে পারে table.length
এছাড়াও thresholdএবং মাধ্যমে গণনা করা যেতে পারেloadFactor এইভাবে শ্রেণিক ক্ষেত্র হিসাবে সংজ্ঞায়িত করার দরকার নেই।

এর মাধ্যমে কার্যকর ক্ষমতা পেতে পারে: capacity()


অপারেশনস

  • কী দ্বারা সত্তা সন্ধান করুন।
    প্রথমে হ্যাশ মান দ্বারা বালতিটি সন্ধান করুন, তারপরে লুপযুক্ত লিঙ্কযুক্ত তালিকা বা সাজানো গাছ অনুসন্ধান করুন।
  • কী সহ সত্তা যুক্ত করুন।
    প্রথমে কী এর হ্যাশ মান অনুযায়ী বালতিটি সন্ধান করুন।
    তারপরে মানটি খোঁজার চেষ্টা করুন:
    • যদি পাওয়া যায় তবে মানটি প্রতিস্থাপন করুন।
    • অন্যথায়, লিঙ্কযুক্ত তালিকার শুরুতে একটি নতুন নোড যুক্ত করুন বা সাজানো গাছটিতে inোকান।
  • আকারে পৌঁছে
    গেলে হ্যাশটেবলের thresholdক্ষমতা দ্বিগুণ হবে ( table.length), তারপরে সারণীটি পুনর্নির্মাণের জন্য সমস্ত উপাদানগুলিতে পুনরায় হ্যাশ সঞ্চালন করুন।
    এটি একটি ব্যয়বহুল অপারেশন হতে পারে।

কর্মক্ষমতা


  • সময় জটিলতা পান এবং রাখুন O(1)কারণ:
    • ব্যাকেট অ্যারে সূচক মাধ্যমে অ্যাক্সেস করা হয়, এইভাবে O(1)
    • প্রতিটি বালতি লিঙ্কযুক্ত তালিকা ছোট দৈর্ঘ্যের হয়, সুতরাং হিসাবে দেখতে পারে O(1)
    • গাছের আকারও সীমাবদ্ধ, কারণ উপাদান সংখ্যা বাড়লে ক্ষমতা এবং পুনরায় হ্যাশ প্রসারিত হবে, তাই এটিকে দেখতে পেত O(1), না হিসাবে দেখতে পেল O(log N)

আপনি কী দয়া করে উদাহরণ দিতে পারেন কীভাবে সময়ের জটিলতা রয়েছে (1)
জিতেন্দ্র

@ জস্রিয়াল এটি জটিলতা আরও স্পষ্টভাবে ব্যাখ্যা করতে পারে: en.wikedia.org/wiki/Hash_table । তবে সংক্ষেপে: লক্ষ্য বালতিটি অনুসন্ধান করা ও (1), কারণ আপনি এটি অ্যারে সূচক অনুসারে খুঁজে পেয়েছেন; তারপরে একটি বালতির মধ্যে পরিমাণগুলি সামান্য এবং পুরো হ্যাশটেবলের মোট উপাদানগুলির সত্ত্বেও গড়ে একটি ধ্রুবক সংখ্যা থাকে, তাই বালতির মধ্যে লক্ষ্য উপাদানটির সন্ধান করা ও (1); সুতরাং, ও (1) + ও (1) = ও (1)।
এরিক ওয়াং

14

হ্যাশকোড হ্যাশম্যাপের জন্য কোন বালতি চেক করবে তা নির্ধারণ করে। বালতিতে যদি একাধিক অবজেক্ট থাকে তবে বালতিতে কোন আইটেমটি পছন্দসই আইটেমটির (সমান ব্যবহার করে equals()) পদ্ধতির সমান হয় তা সন্ধান করার জন্য একটি রৈখিক অনুসন্ধান করা হয় ।

অন্য কথায়, যদি আপনার একটি নিখুঁত হ্যাশকোড থাকে তবে হ্যাশম্যাপ অ্যাক্সেস অবিচ্ছিন্ন থাকে, আপনাকে কখনই একটি বালতি দিয়ে পুনরাবৃত্তি করতে হবে না (প্রযুক্তিগতভাবে আপনারও MAX)T বালতি থাকতে হবে, জাভা বাস্তবায়ন একই বালতিতে কয়েকটি হ্যাশ কোড ভাগ করতে পারে স্থানের প্রয়োজনীয়তাগুলি হ্রাস করুন)। যদি আপনার নিকৃষ্টতম হ্যাশকোড থাকে (সর্বদা একই নম্বরটি ফেরত দেয়) তবে আপনার হ্যাশম্যাপ অ্যাক্সেস লিনিয়ার হয়ে যায় যেহেতু আপনি যা চান তা পেতে ম্যাপের প্রতিটি আইটেমের (তারা সবাই একই বালতিতে রয়েছে) অনুসন্ধান করতে হবে।

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


11

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

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


6
import java.util.HashMap;

public class Students  {
    String name;
    int age;

    Students(String name, int age ){
        this.name = name;
        this.age=age;
    }

    @Override
    public int hashCode() {
        System.out.println("__hash__");
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("__eq__");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Students other = (Students) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    public static void main(String[] args) {

        Students S1 = new Students("taj",22);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Output:

__ hash __

116232

__ hash __

116201

__ hash __

__ hash __

2

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

    public static void main(String[] args) {

        Students S1 = new Students("taj",21);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Now lets change out main method a little bit. Output after this change is 

__ hash __

116201

__ hash __

116201

__ hash __

__ hash __

__ eq __

1
We can clearly see that equal method is called. Here is print statement __eq__, since we have same hashcode, then content of objects MAY or MAY not be similar. So program internally  calls Equal method to verify this. 


Conclusion 
If hashcode is different , equal method will not get called. 
if hashcode is same, equal method will get called.

Thanks , hope it helps. 

3

দুটি বস্তু সমান, বোঝায় যে তাদের একই হ্যাশকোড রয়েছে তবে বিপরীতে নয়।

2 সমান বস্তু ------> তাদের একই হ্যাশকোড রয়েছে

2 টি বস্তুর একই হ্যাশকোড রয়েছে ---- xxxxx -> তারা সমান নয়

হাশম্যাপে জাভা 8 আপডেট

আপনি আপনার কোডে এই অপারেশনটি করেন -

myHashmap.put("old","old-value");
myHashMap.put("very-old","very-old-value");

সুতরাং, ধরুন আপনার হ্যাশকোড উভয় কীগুলির জন্য ফিরে এসেছে "old"এবং "very-old"এটি একই। তাহলে কি হবে।

myHashMapএটি একটি হ্যাশম্যাপ, এবং ধরুন যে প্রাথমিকভাবে আপনি এর ক্ষমতাটি নির্দিষ্ট করেন নি। সুতরাং জাভা অনুযায়ী ডিফল্ট ক্ষমতা 16 হয় So সুতরাং এখনই আপনি নতুন কীওয়ার্ডটি ব্যবহার করে হ্যাশম্যাপ শুরু করার সাথে সাথে এটি 16 বালতি তৈরি করেছে। এখন যখন আপনি প্রথম বিবৃতি কার্যকর করেছেন-

myHashmap.put("old","old-value");

তারপরে হ্যাশকোড "old"গণনা করা হয়, এবং কারণ হ্যাশকোডটি খুব বড় পূর্ণসংখ্যার হতে পারে, সুতরাং জাভা অভ্যন্তরীণভাবে এটি করেছিল - (হ্যাশ এখানে হ্যাশকোড এবং >>> ডান শিফট)

hash XOR hash >>> 16

একটি বড় ছবি হিসাবে দিতে, এটি কিছু সূচক ফেরত দেবে, যা 0 থেকে 15 এর মধ্যে হবে। এখন আপনার মূল মান জুটি "old"এবং "old-value"এন্ট্রি অবজেক্টের কী এবং মান উদাহরণ ভেরিয়েবলে রূপান্তর হবে। এবং তারপরে এই এন্ট্রি অবজেক্টটি বালতিতে সংরক্ষণ করা হবে, বা আপনি বলতে পারেন যে কোনও নির্দিষ্ট সূচীতে এই এন্ট্রি অবজেক্টটি সংরক্ষণ করা হবে।

এফওয়াইআই- এন্ট্রি মানচিত্র ইন্টারফেসের একটি শ্রেণি- মানচিত্র.এন্ট্রি, এই স্বাক্ষর / সংজ্ঞা সহ

class Entry{
          final Key k;
          value v;
          final int hash;
          Entry next;
}

এখন আপনি যখন পরবর্তী বিবৃতি কার্যকর করবেন -

myHashmap.put("very-old","very-old-value");

এবং "very-old"একই হ্যাশকোড দেয় "old", সুতরাং এই নতুন কী মান জোড়া আবার একই সূচক বা একই বালতিতে প্রেরণ করা হয়। তবে যেহেতু এই বালতিটি খালি নয়, তারপরে nextএন্ট্রি অবজেক্টের ভেরিয়েবলটি এই নতুন কী মান জুড়ি রাখার জন্য ব্যবহৃত হয়।

এবং এটি হ্যাশকোডযুক্ত প্রতিটি বস্তুর জন্য লিঙ্কযুক্ত তালিকা হিসাবে সংরক্ষণ করা হবে, তবে একটি ট্রাইফাই_এইচটিআরশোল্ড 6 মান সহ সুনির্দিষ্ট করা হয়েছে, সুতরাং এটি পৌঁছানোর পরে, লিঙ্কযুক্ত তালিকাটি প্রথম উপাদান হিসাবে ভারসাম্য গাছ (লাল-কালো গাছ) এ রূপান্তরিত হয় রুট।


দুর্দান্ত উত্তর (y)
সুধাংশু গৌড়

2

প্রতিটি এন্ট্রি অবজেক্ট কী-মান জোড় উপস্থাপন করে। যদি বালতিতে 1 টির বেশি প্রবেশ থাকে তবে ক্ষেত্রটি পরবর্তী এন্ট্রি অবজেক্টকে বোঝায় to

কখনও কখনও এটি ঘটতে পারে যে 2 বিভিন্ন বস্তুর জন্য হ্যাশকডগুলি একই are এক্ষেত্রে 2 টি বস্তু একটি বালতিতে সংরক্ষণ করা হবে এবং লিংকডলিস্ট হিসাবে উপস্থাপিত হবে। এন্ট্রি পয়েন্টটি আরও সম্প্রতি যুক্ত হওয়া বস্তু। এই অবজেক্টটি অন্য ক্ষেত্রের সাথে অন্য ক্ষেত্রের সাথে বোঝায় so শেষ এন্ট্রি নাল বোঝায়। আপনি যখন ডিফল্ট কনস্ট্রাক্টর দিয়ে হ্যাশম্যাপ তৈরি করেন

অ্যারে 16 মাপ এবং ডিফল্ট 0.75 লোড ব্যালেন্স দিয়ে তৈরি হয়।

এখানে চিত্র বর্ণনা লিখুন

(উৎস)


1

হ্যাশ মানচিত্র হ্যাশিংয়ের নীতিতে কাজ করে

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

  • যখনই আমরা হ্যাশম্যাপ অবজেক্টে get (কী কে) পদ্ধতিটি কল করি। প্রথমে এটি পরীক্ষা করে দেখুন যে কীটি নাল কিনা। মনে রাখবেন যে হ্যাশম্যাপে কেবল একটি নাল কী থাকতে পারে।

যদি কীটি নাল হয় তবে নুল কীগুলি সর্বদা হ্যাশ 0 তে ম্যাপ করে, সুতরাং 0 সূচী।

যদি কীটি নাল না থাকে তবে কী-এর অবজেক্টে এটি হ্যাশফংশনকে কল করবে, উপরের পদ্ধতিতে লাইন 4 দেখতে হবে অর্থাৎ কী.হ্যাশকোড (), সুতরাং কী.হ্যাশকোড () পরে হ্যাশভ্যালু ফিরিয়ে দেওয়ার পরে লাইন 4 এর মত দেখাচ্ছে

            int hash = hash(hashValue)

এবং এখন, এটি তার নিজের হ্যাশিং ফাংশনে ফেরত হ্যাশভ্যালু প্রয়োগ করে।

আমরা ভাবতে পারি যে কেন আমরা আবার হ্যাশ (হ্যাশভ্যালু) ব্যবহার করে হ্যাশভ্যালু গণনা করছি। উত্তরটি হ'ল এটি নিম্ন মানের হ্যাশ ফাংশন থেকে রক্ষা করে।

এখন চূড়ান্ত হ্যাশভ্যালুটি বালতি অবস্থানটি অনুসন্ধান করতে ব্যবহৃত হয় যেখানে এন্ট্রি অবজেক্টটি সংরক্ষণ করা হয়। বালতিতে এন্ট্রি অবজেক্ট স্টোরগুলি (হ্যাশ, কী, মান, বালতিলিডেক্স)


1

আমি হাশম্যাপ কীভাবে কাজ করে তার বিবরণে যাব না, তবে একটি উদাহরণ দেব যাতে আমরা মনে করতে পারি যে হ্যাশম্যাপ বাস্তবতার সাথে সম্পর্কিত হয়ে কীভাবে কাজ করে।

আমাদের কাছে কী, মান, হ্যাশকোড এবং বালতি রয়েছে।

কিছু সময়ের জন্য, আমরা তাদের প্রত্যেককে নিম্নলিখিতগুলির সাথে সম্পর্কিত করব:

  • বালতি -> একটি সোসাইটি
  • হ্যাশকোড -> সোসাইটির ঠিকানা (সর্বদা অনন্য)
  • মান -> সোসাইটিতে একটি বাড়ি
  • কী -> বাড়ির ঠিকানা।

মানচিত্রের ব্যবহার (কী):

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

  • এসএসএন সোসাইটির নাম
  • 92313 (জোসে'স) - জাভালোভার্স
  • 13214 - AngularJSLovers
  • 98080 - জাভালোভার্স
  • 53808 - জীববিজ্ঞানপ্রেমী

  1. এই এসএসএন (কী) প্রথমে আমাদের একটি হ্যাশকোড দেয় (সূচী সারণী থেকে) যা সোসাইটির নাম ছাড়া কিছুই নয়।
  2. এখন, বহু সমাজগুলি একই সমাজে থাকতে পারে, সুতরাং হ্যাশকোড সাধারণ হতে পারে।
  3. ধরা যাক, সোসাইটি দুটি বাড়ির জন্য সাধারণ, আমরা কীভাবে আমরা যাব যাচ্ছি তা সনাক্ত করতে যাব, হ্যাঁ, (এসএসএন) কী ব্যবহার করে যা বাড়ির ঠিকানা ছাড়া কিছুই নয়

মান.পুট (কী, মান) ব্যবহার করা হচ্ছে

এটি হ্যাশকোড সন্ধান করে এই মানটির জন্য একটি উপযুক্ত সমাজের সন্ধান করে এবং তখন মানটি সংরক্ষণ করা হয়।

আমি আশা করি এটি সাহায্য করে এবং এটি পরিবর্তনগুলির জন্য উন্মুক্ত।


0

এটি দীর্ঘ উত্তর হতে পারে, একটি পানীয় পান এবং পড়ুন…

হ্যাশিং মেমরির একটি মূল-মান জুড়ি সংরক্ষণ করার জন্য যা দ্রুত পড়া এবং আরও দ্রুত লেখা যায়। এটি একটি অ্যারেতে কীগুলি সংরক্ষণ করে এবং একটি লিঙ্কলিস্টে মানগুলি।

আসুন বলুন আমি 4 টি মূল মান জোড়া সংরক্ষণ করতে চাই -

{
girl => ahhan , 
misused => Manmohan Singh , 
horsemints => guess what”, 
no => way
}

সুতরাং কীগুলি সঞ্চয় করতে আমাদের 4 টি উপাদানটির অ্যারে প্রয়োজন। এখন আমি কীভাবে এই 4 টির মধ্যে 4 টি অ্যারে সূচকগুলিতে (0,1,2,3) মানচিত্র করব?

সুতরাং জাভা পৃথক কীগুলির হ্যাশকোড খুঁজে পায় এবং এটিকে একটি নির্দিষ্ট অ্যারে সূচীতে ম্যাপ করে। হ্যাশকোড সূত্রগুলি হ'ল -

1) reverse the string.

2) keep on multiplying ascii of each character with increasing power of 31 . then add the components .

3) So hashCode() of girl would be –(ascii values of  l,r,i,g are 108, 114, 105 and 103) . 

e.g. girl =  108 * 31^0  + 114 * 31^1  + 105 * 31^2 + 103 * 31^3  = 3173020

হ্যাশ আর মেয়ে !! আমি জানি তুমি কি ভাবছ। সেই বুনো দ্বৈত সম্পর্কে আপনার আকর্ষণ আপনাকে একটি গুরুত্বপূর্ণ জিনিস মিস করতে পারে miss

জাভা কেন এটি 31 দিয়ে গুণ করে?

এটি কারণ, 31 2 ^ 5 - 1 ফর্মের মধ্যে একটি বিজোড় প্রধান। এবং বিজোড় প্রাইম হ্যাশ সংঘর্ষের সম্ভাবনা হ্রাস করে

এখন এই হ্যাশ কোডটি কীভাবে অ্যারে সূচকে ম্যাপ করা হবে?

উত্তর হল Hash Code % (Array length -1) ,। সুতরাং “girl”ম্যাপ করা হয় (3173020 % 3) = 1আমাদের ক্ষেত্রে। যা অ্যারের দ্বিতীয় উপাদান।

এবং মান "অহান" অ্যারে সূচক 1 এর সাথে যুক্ত একটি লিঙ্কযুক্ত তালিকায় সংরক্ষণ করা হয়।

হ্যাশকোলিশন - উপরে বর্ণিত সূত্রগুলি hasHCodeকীগুলি সন্ধান করার “misused”এবং “horsemints”ব্যবহার করার চেষ্টা করলে আপনি উভয়ই আমাদের একই রকম দেখতে পাবেন 1069518484। হুয়াও !! পাঠ শিখেছি -

2 টি সমান অবজেক্টের অবশ্যই একই হ্যাশকোড থাকতে হবে তবে হ্যাশকোডের সাথে মেলে যদি বস্তু সমান হয় তবে কোনও গ্যারান্টি নেই। সুতরাং এটি বালতি 1 (1069518484% 3) এর "অপব্যবহার" এবং "ঘোড়াগুলি" এর সাথে সম্পর্কিত উভয় মান সংরক্ষণ করতে হবে।

এখন হ্যাশ মানচিত্রটি দেখতে দেখতে -

Array Index 0 
Array Index 1 - LinkedIst (“ahhan , Manmohan Singh , guess what”)
Array Index 2  LinkedList (“way”)
Array Index 3  

এখন যদি কিছু শরীর চাবির জন্য মানটি খুঁজতে চেষ্টা করে “horsemints”, জাভা দ্রুত এটির হ্যাশকোড খুঁজে পেতে পারে, এটি মডিউল করে এবং লিংকডলিস্টের সাথে সম্পর্কিত এটির মান অনুসন্ধান করতে শুরু করে index 1। সুতরাং এইভাবে আমাদের 4 টি অ্যারে সূচকগুলি অনুসন্ধান করার দরকার নেই যাতে এইভাবে ডেটা অ্যাক্সেস দ্রুত হয়।

তবে, অপেক্ষা করুন, এক সেকেন্ড লিঙ্কযুক্ত তালিকার সাথে সম্পর্কিত অ্যারে সূচি 1-তে 3 টি মান রয়েছে, কীভাবে এটি আবিষ্কার করবে যে কী "ঘোড়াগুলি" এর মান ছিল কোনটি?

আসলে আমি মিথ্যা বললাম, যখন আমি বললাম হাশম্যাপ লিংকডলিস্টে কেবলমাত্র মান সংরক্ষণ করে।

এটি মানচিত্রের প্রবেশের হিসাবে উভয় মূল মান জোড়া সংরক্ষণ করে। সুতরাং প্রকৃতপক্ষে মানচিত্রটি এর মতো দেখাচ্ছে।

Array Index 0 
Array Index 1 - LinkedIst (<”girl => ahhan”> , <” misused => Manmohan Singh”> , <”horsemints => guess what”>)
Array Index 2  LinkedList (<”no => way”>)
Array Index 3  

এখন আপনি দেখতে পাচ্ছেন অ্যারেআইন্ডেক্স 1 এর সাথে সম্পর্কিত লিঙ্কলিস্টের মধ্য দিয়ে ট্র্যাভার করার সময় এটি আসলে সেই লিংকডলিস্টের প্রতিটি প্রবেশের কীটিকে "ঘোড়াগুলির সাথে" তুলনা করে এবং এটি যখন খুঁজে পায় তখন এটি কেবল তার মান ফেরত দেয়।

আশা করি আপনি এটি পড়ার সময় মজা পেয়েছিলেন :)


আমি মনে করি এটি ভুল: "এটি একটি অ্যারেতে কীগুলি সংরক্ষণ করে এবং একটি লিঙ্কলিস্টে মান দেয়।"
এসিভি

প্রতিটি বালতির তালিকার প্রতিটি উপাদানটিতে কী এবং মান এবং পরবর্তী নোডের রেফারেন্স রয়েছে।
এসিভি

0

যেমনটি বলা হয়, একটি চিত্রের মূল্য 1000 শব্দ। আমি বলি: কিছু কোড 1000 শব্দের চেয়ে ভাল। এখানে হ্যাশম্যাপের উত্স কোড। পদ্ধতি পান:

/**
     * Implements Map.get and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

সুতরাং এটি স্পষ্ট হয়ে যায় যে হ্যাশটি "বালতি" সন্ধান করতে ব্যবহৃত হয় এবং সর্বদা প্রথম উপাদানটি সেই বালতিতে পরীক্ষা করা হয়। যদি তা না equalsহয় তবে লিঙ্কযুক্ত তালিকার আসল উপাদানটি খুঁজতে চাবিটি ব্যবহৃত হয়।

আসুন put()পদ্ধতিটি দেখুন:

  /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

এটি কিছুটা জটিল, তবে এটি স্পষ্ট হয়ে যায় যে নতুন উপাদানটি হ্যাশের উপর ভিত্তি করে গণনা করা অবস্থানে ট্যাবটিতে রাখা হয়েছে:

i = (n - 1) & hashএখানে iসূচিটি যেখানে নতুন উপাদানটি স্থাপন করা হবে (বা এটি "বালতি")। অ্যারের nআকার tab("বালতি" এর অ্যারে)।

প্রথমত, এটি "বালতি" এর প্রথম উপাদান হিসাবে স্থাপন করার চেষ্টা করা হয়। যদি ইতিমধ্যে কোনও উপাদান থাকে তবে তালিকায় একটি নতুন নোড যুক্ত করুন।

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