Treeification और प्रदर्शन
Java 8+ टकरावों को कैसे संभालता है
Treeification और प्रदर्शन, CoddyKit पर Java Academy का एक निःशुल्क पाठ है। यह 4 में से 4वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Java Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
टकराव की समस्या
Java 8 से पहले, बहुत अधिक टकरावों वाला बकेट एक लंबी श्रृंखलाबद्ध सूची बन जाता था। उस बकेट में खोज की गति घटकर O(n) हो जाती थी।
एक हमलावर ऐसा करने के लिए विशेष रूप से बनाए गए कुंजियों का उपयोग कर सकता था, जिससे सभी कुंजियों का hash एक ही बकेट में जाकर सेवा-अस्वीकार समस्या पैदा करता।
public class Main {
public static void main(String[] args) {
// All these strings can be made to collide in one bucket
System.out.println("FB".hashCode() == "Ea".hashCode());
}
}Java 8 में वृक्षीकरण
Java 8 में वृक्षीकरण जोड़ा गया। जब किसी एक बकेट में बहुत अधिक प्रविष्टियाँ होती हैं, तो श्रृंखलाबद्ध सूची एक संतुलित लाल-काले वृक्ष में बदल जाती है।
इसके बाद उस बकेट में खोज O(n) के बजाय O(log n) हो जाती है।
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, Integer> m = new HashMap<>();
for (int i = 0; i < 1000; i++) m.put(i, i);
System.out.println("Lookups stay fast: " + m.get(742));
}
}सीमा: TREEIFY_THRESHOLD
TREEIFY_THRESHOLD स्थिरांक का मान 8 है। किसी बकेट में 8 प्रविष्टियाँ होने पर वह वृक्ष में बदल जाता है।
लेकिन दूसरी शर्त भी है: तालिका का आकार कम-से-कम MIN_TREEIFY_CAPACITY (64) होना चाहिए, अन्यथा मानचित्र का आकार बदल दिया जाता है।
public class Main {
public static void main(String[] args) {
int TREEIFY_THRESHOLD = 8;
int MIN_TREEIFY_CAPACITY = 64;
System.out.println("Treeify when bucket size >= " + TREEIFY_THRESHOLD);
System.out.println("...and table capacity >= " + MIN_TREEIFY_CAPACITY);
}
}पहले आकार बदलें, बाद में वृक्षीकरण करें
यदि कोई बकेट भरकर सीमा से बाहर चला जाए, लेकिन तालिका अभी छोटी हो (64 से कम), तो HashMap पहले तालिका का आकार बदलता है।
आकार बदलने से आम तौर पर प्रविष्टियाँ फिर से वितरित हो जाती हैं और समस्या वाला स्थान समाप्त हो जाता है, इसलिए वृक्षीकरण वास्तव में खराब hash वितरण के लिए अंतिम उपाय है।
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, Integer> m = new HashMap<>(16);
for (int i = 0; i < 50; i++) m.put(i, i);
// Many resizes happened before any treeify would
System.out.println("size = " + m.size());
}
}वृक्षीकरण हटाना
वृक्ष स्थायी नहीं होते। यदि हटाने की प्रक्रिया से कोई बकेट UNTREEIFY_THRESHOLD (6) से नीचे चला जाता है, तो वृक्ष फिर से श्रृंखलाबद्ध सूची में बदल जाता है।
8 (वृक्षीकरण) और 6 (वृक्षीकरण हटाना) के बीच का अंतर सीमा पर बार-बार होने वाले बदलावों से बचाता है।
public class Main {
public static void main(String[] args) {
System.out.println("TREEIFY_THRESHOLD = 8");
System.out.println("UNTREEIFY_THRESHOLD = 6");
System.out.println("Gap prevents flip-flopping at the edge");
}
}वृक्षों को तुलनीय या पहचान-आधारित क्रम चाहिए
लाल-काले वृक्ष को अपनी प्रविष्टियों का क्रम तय करना होता है। HashMap पहले hash कोड की तुलना करता है; समानता होने पर, यदि कुंजियाँ इसे लागू करती हैं, तो Comparable से क्रम तय किया जाता है। अन्यथा वर्ग के नामों और पहचान के आधार पर एक स्थिर बराबरी-निर्णायक का उपयोग होता है।
Comparable कुंजियाँ (जैसे String या पूर्णांक) सबसे साफ़ वृक्ष-क्रम प्रदान करती हैं।
public class Main {
public static void main(String[] args) {
System.out.println("String is Comparable: " + ("a" instanceof Comparable));
System.out.println("Integer is Comparable: " + (Integer.valueOf(1) instanceof Comparable));
}
}व्यावहारिक प्रभाव
अच्छे hash कोड वाले अधिकांश वास्तविक प्रोग्रामों में आपको कभी नहीं वृक्षीकरण दिखाई देगा। बकेट छोटे ही रहते हैं।
वृक्षीकरण एक सुरक्षा-जाल है, जो hash खराब या हमलावर तरीके से बनाए गए होने पर भी सबसे खराब स्थिति में खोज की गति को O(log n) तक सीमित रखता है।
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<>();
m.put("alpha", 1);
m.put("beta", 2);
m.put("gamma", 3);
// Tiny buckets, plain linked lists, no trees needed
System.out.println(m.get("beta"));
}
}एक स्थिर hashCode वृक्षों को बाध्य करता है
यदि आप जानबूझकर स्थिर hashCode लौटाते हैं, तो हर कुंजी एक ही बकेट में जाएगी। 64 या उससे अधिक की क्षमता होने पर वह बकेट वृक्षीकृत हो जाएगा।
यह सुरक्षा-जाल को प्रदर्शित करता है, लेकिन यह डिज़ाइन में एक खामी का संकेत है। इसके बजाय hashCode को ठीक करें।
import java.util.HashMap;
import java.util.Map;
public class Main {
static class Bad implements Comparable<Bad> {
final int v;
Bad(int v) { this.v = v; }
@Override public int hashCode() { return 1; } // forces collisions
@Override public boolean equals(Object o) { return o instanceof Bad b && b.v == v; }
@Override public int compareTo(Bad o) { return Integer.compare(v, o.v); }
}
public static void main(String[] args) {
Map<Bad, Integer> m = new HashMap<>();
for (int i = 0; i < 100; i++) m.put(new Bad(i), i);
System.out.println("All in one bucket, still works: " + m.get(new Bad(50)));
}
}वृक्षों की स्मृति लागत
वृक्ष के नोड सामान्य श्रृंखलाबद्ध-सूची नोड से बड़े होते हैं, क्योंकि वे अभिभावक, बाएँ, दाएँ और रंग के संदर्भ संग्रहीत करते हैं।
यह एक और कारण है कि वृक्षीकरण डिफ़ॉल्ट तरीका नहीं, बल्कि एक वैकल्पिक उपाय है: वृक्ष सबसे खराब स्थिति की गति के बदले अधिक स्मृति लेते हैं।
public class Main {
public static void main(String[] args) {
System.out.println("Node: hash, key, value, next");
System.out.println("TreeNode: + parent, left, right, prev, red flag");
System.out.println("=> trees cost more memory per entry");
}
}वृक्षीकरण से कैसे बचें
आप लगभग कभी भी वृक्षीकरण पर निर्भर नहीं रहना चाहेंगे। इससे बचने के लिए:
- अच्छी तरह वितरित
hashCode()लिखें। - कुंजियों के रूप में अंतर्निर्मित प्रकारों या रिकॉर्ड का उपयोग करें।
- टकराव कम करने के लिए मानचित्र का आकार पहले से तय करें।
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class Main {
record Key(int a, int b) {}
public static void main(String[] args) {
Map<Key, Integer> m = new HashMap<>(256);
for (int i = 0; i < 200; i++) m.put(new Key(i, i * 31), i);
System.out.println("Even distribution, fast lookups: " + m.get(new Key(10, 310)));
}
}प्रदर्शन का सारांश
HashMap के संचालन की लागत:
- अच्छा hash: औसतन O(1)।
- श्रृंखलाबद्ध बकेट: सबसे खराब स्थिति में प्रत्येक बकेट के लिए O(n)।
- वृक्षीकृत बकेट: प्रत्येक बकेट के लिए O(log n)।
वृक्षीकरण सबसे खराब स्थिति को सीमित करता है, लेकिन अच्छा hashCode आपको O(1) की स्थिति में बनाए रखता है।
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, Integer> m = new HashMap<>(1 << 14);
for (int i = 0; i < 10000; i++) m.put(i, i);
System.out.println("10k entries, O(1) get: " + m.get(9999));
}
}त्वरित जाँच
वृक्षीकरण के बारे में अपनी जानकारी जाँचें।
पुनरावलोकन
आपने सीखा कि आधुनिक HashMap टकरावों को कैसे संभालता है:
- जब क्षमता कम-से-कम 64 हो, तो 8 प्रविष्टियों पर बकेट वृक्षीकृत हो जाते हैं।
- वृक्ष सबसे खराब स्थिति में खोज को O(log n) तक ले आते हैं।
- 6 से कम प्रविष्टियाँ होने पर बकेट वृक्षीकरण हटाते हैं।
- अच्छे hashCode का अर्थ है कि आप इस सुरक्षा-जाल को बहुत कम सक्रिय करेंगे।
आपने HashMap की आंतरिक कार्यप्रणाली का पाठ्यक्रम पूरा कर लिया है।
public class Main {
public static void main(String[] args) {
System.out.println("Treeification course complete");
}
}एआई शिक्षक के साथ Java सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 104
- पाठ
- 374
अक्सर पूछे जाने वाले प्रश्न
क्या “Treeification और प्रदर्शन” पाठ निःशुल्क है?
हाँ—“Treeification और प्रदर्शन” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Java Academy पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“Treeification और प्रदर्शन” में मैं क्या सीखूँगा?
Java 8+ टकरावों को कैसे संभालता है आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Java Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Java Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Java Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 4वाँ पाठ है।
“Treeification और प्रदर्शन” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Java Academy पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Java Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- HashMap कैसे काम करता है
- equals/hashCode अनुबंध
- hashCode लागू करना
- Treeification और प्रदर्शन