स्ट्रिंग्स के लिए अच्छा हैश फंक्शन


160

मैं तार के लिए एक अच्छा हैश फ़ंक्शन सोचने की कोशिश कर रहा हूं। और मैं सोच रहा था कि स्ट्रिंग में पहले पांच पात्रों के लिए यूनिकोड मूल्यों को योग करना एक अच्छा विचार हो सकता है (यह मानते हुए कि इसमें पाँच हैं, अन्यथा जहां यह समाप्त होता है) रोक दें। क्या यह एक अच्छा विचार है, या यह एक बुरा है?

मैं जावा में ऐसा कर रहा हूं, लेकिन मैं कल्पना नहीं करूंगा कि इससे बहुत फर्क पड़ेगा।


4
अच्छा हैश फ़ंक्शन हैश के इनपुट पर बहुत अधिक निर्भर करता है, और एल्गोरिथ्म की आवश्यकताएं। उदाहरण के लिए, यदि आपके सभी तार एक ही पाँच अक्षरों से शुरू होते हैं, तो ऐसा हैश बहुत अच्छा नहीं होगा। इसका परिणाम सामान्य वितरण में भी होगा।
व्हर्लविंड


14
आप Stringस्वयं का उपयोग क्यों नहीं कर सकते hashCode()?
बार्ट कीर्स

@HirlWind, सच है, मुझे यकीन नहीं है कि तार क्या होगा, इसके अलावा यह शायद अंग्रेजी पाठ होगा।
लीफ एंडरसन

@ बर्ल, मुख्य रूप से क्योंकि मेरे प्रोफेसर ने हमें अपने खुद के हैश फ़ंक्टर को लागू करने के लिए कहा था ... और जिस कारण से मैं जावा का उपयोग नहीं करना चाहता था, वह इसलिए था क्योंकि यह सामान्य था, और मुझे लगता है कि एक अधिक विशिष्ट हैश फ़ेक्टर बेहतर होगा।
लीफ एंडरसन

जवाबों:


161

आमतौर पर हैश रकम नहीं करते, अन्यथा stopऔर potsएक ही हैश होगा।

और आप इसे पहले n वर्णों तक सीमित नहीं रखेंगे क्योंकि अन्यथा घर और घरों में समान हैश होगा।

आम तौर पर हैश मान लेते हैं और इसे एक अभाज्य संख्या से गुणा करते हैं (यह अद्वितीय हैश उत्पन्न करने की अधिक संभावना बनाता है) इसलिए आप कुछ ऐसा कर सकते हैं:

int hash = 7;
for (int i = 0; i < strlen; i++) {
    hash = hash*31 + charAt(i);
}

@jonathanasdf आप कैसे कह सकते हैं कि यह आपको हमेशा एक अद्वितीय हैश कुंजी देता है। क्या कोई गणितीय प्रमाण है? मुझे लगता है कि हमें एक और बड़ी प्राइम संख्या के साथ हैश का मॉड लेना होगा, अन्यथा ओवरफ्लो की समस्या होती है।
देवसेना

17
@ महादेव ने हमेशा अद्वितीय नहीं कहा, उन्होंने कहा कि अद्वितीय होने की अधिक संभावना है। क्यों, Google पर त्वरित खोज से इस लेख का पता चलता है: कंप्यूटिंगलाइफ़ .wordpress.com/2008/11/20/… यह बताते हुए कि जावा स्ट्रिंग हैशिंग के लिए 31 का उपयोग क्यों किया गया था। कोई गणितीय प्रमाण नहीं दिया गया है, लेकिन यह सामान्य अवधारणा की व्याख्या करता है कि क्यों primes बेहतर काम करते हैं।
फराप

2
बेहतर हैशिंग करने के विचार को स्पष्ट करने के लिए बहुत धन्यवाद। बस दोहरी जांच करने के लिए - हैशकोड () रिटर्न वैल्यू का उपयोग जावा द्वारा ऑब्जेक्ट को स्टोर करने से पहले कुछ टेबल इंडेक्स में मैप करने के लिए किया जाएगा। इसलिए, यदि हैशकोड () मी लौटाता है, तो यह आकार की तालिका के सूचकांक को प्राप्त करने के लिए (एम मॉड के) जैसा कुछ करता है। क्या वह सही है?
श्वेतघाट

1
"हैश = हैश * 31 + charAt (i);" स्पॉट, टॉप, स्टॉप, ऑप्स और पॉट्स के लिए समान हैश का उत्पादन करता है।
जैक स्ट्रब

1
@ ओम मुझे विश्वास है कि आप सही हैं। पता नहीं मैं क्या सोच रहा था।
जैक स्ट्रब

139

यदि यह सुरक्षा की बात है, तो आप जावा क्रिप्टो का उपयोग कर सकते हैं:

import java.security.MessageDigest;

MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(stringToEncrypt.getBytes());
String encryptedString = new String(messageDigest.digest());

93
अच्छा लगा। मेरे पास मशीन-लर्निंग एप्लिकेशन है, जो एक बड़े कॉर्पस पर सांख्यिकीय एनएलपी कर रहा है। पाठ में मूल शब्दों पर रूपात्मक सामान्यीकरण के कुछ प्रारंभिक पास के बाद, मैं स्ट्रिंग मानों को हटा देता हूं और इसके बजाय हैश कोड का उपयोग करता हूं। मेरे पूरे कॉर्पस में, लगभग 600,000 अद्वितीय शब्द हैं, और डिफ़ॉल्ट जावा हैशकोड फ़ंक्शन का उपयोग करके, मुझे लगभग 3.5% टक्कर मिल रही थी। लेकिन अगर मैं स्ट्रिंग मान SHA-256 और फिर पचा स्ट्रिंग से एक हैशकोड उत्पन्न करता हूं, तो टक्कर अनुपात 0.0001% से कम है। धन्यवाद!
बेंजिस्मिथ

3
टकराव और शब्दों की संख्या के बारे में जानकारी प्रदान करने के लिए धन्यवाद। बहुत मददगार।
दीक्षा

19
@benjismith एक मिलियन में एक बहुत दूर है ... "0.0001% से कम" "ठीक 0" कहने का एक तिरछा तरीका है? मुझे वास्तव में संदेह है कि आपने SHA-256 टकराव देखा, क्योंकि यह कभी भी, कहीं भी, कभी भी नहीं देखा गया है; 160-बिट SHA-1 के लिए भी नहीं। यदि आपके पास दो तार हैं जो समान SHA-256 का उत्पादन करते हैं, तो सुरक्षा समुदाय उन्हें देखना पसंद करेगा; आप विश्व-प्रसिद्ध होंगे ... बहुत अस्पष्ट तरीके से। SHA फ़ंक्शंस की तुलना
टिम सिल्वेस्टर

7
@TimSylvester, आपने गलत समझा। मुझे SHA-256 टक्कर नहीं मिली। मैंने SHA-256 की गणना की और फिर परिणामी बाइट अनुक्रमों को एक विशिष्ट जावा "हैशकोड" फ़ंक्शन में खिलाया, क्योंकि मुझे 32-बिट हैश की आवश्यकता थी। यहीं से मुझे टक्कर मिली। उल्लेखनीय कुछ भी नहीं है
बेंजिस्मिथ

1
क्या 'हैशिंग' और 'एनक्रिप्टिंग' में कोई अंतर नहीं है? मैं समझता हूं कि मैसेजडिजेस्ट एक तरह से हैशिंग फ़ंक्शन है, है ना? इसके अलावा, जब मैंने फ़ंक्शन का उपयोग किया, तो मुझे लिबरऑफिस में फ़ाइल खोलने पर ढेर सारे कबाड़ वाले यूटीएफ पात्रों के रूप में हैशेड स्ट्रिंग मिला। क्या कबाड़ को UTF वर्णों के बजाय अल्फ़ान्यूमेरिक वर्णों के यादृच्छिक गुच्छा के रूप में हैशेड स्ट्रिंग प्राप्त करना संभव है?
नव

38

आपको शायद String.hashCode () का उपयोग करना चाहिए ।

यदि आप वास्तव में खुद को हैशकोड लागू करना चाहते हैं:

प्रदर्शन में सुधार के लिए हैश कोड संगणना से किसी वस्तु के महत्वपूर्ण भागों को बाहर करने का प्रलोभन न दें - जोशुआ बलोच, प्रभावी जावा

केवल पहले पांच पात्रों का उपयोग करना एक बुरा विचार है । पदानुक्रमित नामों के बारे में सोचें, जैसे कि URL: उनके पास सभी समान हैश कोड होंगे (क्योंकि वे सभी "http: //" से शुरू करते हैं, जिसका अर्थ है कि वे एक हैश मैप में उसी बाल्टी के नीचे संग्रहीत हैं, जो भयानक प्रदर्शन प्रदर्शित करता है।

यहां " प्रभावी जावा " से स्ट्रिंग हैशकोड पर एक युद्ध कहानी लिखी गई है :

सबसे अधिक सोलह वर्णों में 1.2 से पहले की गई सभी रिलीज़ों में स्ट्रिंग हैश फ़ंक्शन को लागू किया गया, समान रूप से पहले वर्ण से शुरू होकर, पूरे स्ट्रिंग में स्थान दिया गया। URL जैसे पदानुक्रमित नामों के बड़े संग्रह के लिए, इस हैश फ़ंक्शन ने भयानक व्यवहार प्रदर्शित किया।


1
यदि कोई डबल-हैशेड संग्रह का उपयोग कर रहा है, तो यह संभव है कि पहला हैश वास्तव में त्वरित और गंदा हो। यदि किसी के पास एक हजार लंबे तार हैं, जिनमें से आधे को एक विशेष मान के लिए एक क्रमी फ़ंक्शन द्वारा मैप किया जाता है, और जिनमें से आधे को अलग-अलग मानों में मैप किया जाता है, तो एकल-हैशेड तालिका में प्रदर्शन खराब होगा, लेकिन एक डबल में प्रदर्शन हैशेड टेबल, जहां दूसरे हैश ने पूरे स्ट्रिंग की जांच की, लगभग एक-हैशेड टेबल के लगभग दो बार हो सकता है (क्योंकि आधे तार पूरी तरह से हैशेड नहीं होंगे)। मानक जावा संग्रह में से कोई भी डबल हैशिंग नहीं करता है, हालांकि।
सुपरकैट

प्रभावी जावा लिंक टूट गया है @Frederik
KGs

17

यदि आप जावा में ऐसा कर रहे हैं तो आप ऐसा क्यों कर रहे हैं? बस .hashCode()स्ट्रिंग पर कॉल करें


2
मैं इसे कक्षा के हिस्से के रूप में कर रहा हूं, और असाइनमेंट का हिस्सा कई अलग-अलग हैश फ़ंक्शन को लिखना है। प्रोफेसर ने हमें 'बेहतर' लोगों के लिए बाहर की मदद लेने के लिए कहा।
लीफ एंडरसन

20
यदि आपको अपनी जेवीएम संस्करणों और कार्यान्वयन के अनुरूप होना चाहिए, तो आपको भरोसा नहीं करना चाहिए .hashCode()। बल्कि, कुछ ज्ञात एल्गोरिदम का उपयोग करें।
स्टीफन ओस्टरमिलर

7
के लिए एल्गोरिथ्म String::hashCodeJDK में निर्दिष्ट है, इसलिए यह वर्ग के अस्तित्व के रूप में पोर्टेबल है java.lang.String
यशस्वी


8

निक द्वारा प्रदान किया गया यह कार्य अच्छा है लेकिन यदि आप स्ट्रिंग में परिवर्तन करने के लिए नई स्ट्रिंग (बाइट [] बाइट्स) का उपयोग करते हैं, तो यह विफल रहा। आप ऐसा करने के लिए इस फ़ंक्शन का उपयोग कर सकते हैं।

private static final char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

public static String byteArray2Hex(byte[] bytes) {
    StringBuffer sb = new StringBuffer(bytes.length * 2);
    for(final byte b : bytes) {
        sb.append(hex[(b & 0xF0) >> 4]);
        sb.append(hex[b & 0x0F]);
    }
    return sb.toString();
}

public static String getStringFromSHA256(String stringToEncrypt) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(stringToEncrypt.getBytes());
    return byteArray2Hex(messageDigest.digest());
}

यह किसी की मदद कर सकता है


आप बस बाइट सरणी पास कर सकते हैं messageDigest.update () में।
szgal 13

byteArray2Hex () - यह पूरी तरह से मैं क्या देख रहा था! बहुत बहुत धन्यवाद :)
Krzysiek

5
// djb2 hash function
unsigned long hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

स्रोत djb2 ​​हैश फ़ंक्शन के पीछे तर्क - एसओ


1
मुझे लगता है कि इसे शुरू करने के लिए सिर्फ एक प्रमुख संख्या है, ताकि हमारे पास कम टकराव हो।
कॉर्नस्मिथ

5

FNV-1 स्ट्रिंग्स के लिए एक अच्छा हैश फंक्शन होने की अफवाह है।

लंबे स्ट्रिंग्स (लंबे समय तक, कहते हैं, लगभग 200 अक्षर) के लिए, आप एमडी 4 हैश फ़ंक्शन से अच्छा प्रदर्शन प्राप्त कर सकते हैं । एक क्रिप्टोग्राफ़िक फ़ंक्शन के रूप में, यह लगभग 15 साल पहले टूट गया था, लेकिन गैर क्रिप्टोग्राफ़िक प्रयोजनों के लिए, यह अभी भी बहुत अच्छा है, और आश्चर्यजनक रूप से तेज़ है। जावा के संदर्भ में, आपको 16-बिट charमानों को 32-बिट शब्दों में बदलना होगा , जैसे कि ऐसे मूल्यों को जोड़े में समूहित करके। जावा में एमडी 4 का तेजी से कार्यान्वयन स्फालिब में पाया जा सकता है । संभवतः कक्षा असाइनमेंट के संदर्भ में ओवरक्लिल करें, लेकिन अन्यथा एक कोशिश के लायक है।


यह हैश फ़ंक्शन इतना बेहतर है कि फिर जावा के साथ आता है।
clankill3r

3

यदि आप उद्योग मानक कार्यान्वयन देखना चाहते हैं, तो मैं java.security.MessageDigest देखूंगा

"संदेश डाइजेस्ट एक-तरफ़ा हैश फ़ंक्शंस हैं जो मनमाने आकार के डेटा लेते हैं और एक निश्चित-लंबाई हैश मान आउटपुट करते हैं।"


1

यहाँ एक लिंक है जो कई अलग-अलग हैश कार्यों की व्याख्या करता है, अब मैं आपकी विशेष समस्या के लिए ईएलएफ हैश फ़ंक्शन पसंद करता हूं। यह इनपुट के रूप में मनमानी लंबाई की एक स्ट्रिंग लेता है।


1

sdbm: यह एल्गोरिथ्म sdbm (ndbm के सार्वजनिक डोमेन के कार्यान्वयन) डेटाबेस लाइब्रेरी के लिए बनाया गया था

static unsigned long sdbm(unsigned char *str)
{   
    unsigned long hash = 0;
    int c;
    while (c = *str++)
            hash = c + (hash << 6) + (hash << 16) - hash;

    return hash;
}

0
         public String hashString(String s) throws NoSuchAlgorithmException {
    byte[] hash = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        hash = md.digest(s.getBytes());

    } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hash.length; ++i) {
        String hex = Integer.toHexString(hash[i]);
        if (hex.length() == 1) {
            sb.append(0);
            sb.append(hex.charAt(hex.length() - 1));
        } else {
            sb.append(hex.substring(hex.length() - 2));
        }
    }
    return sb.toString();
}

-1

स्ट्रिंग के लिए एक अच्छा जल्दबाजी समारोह विकसित करने की कोशिश करते समय विषम संख्या के साथ काम करने का यह एक अच्छा विचार है। यह फ़ंक्शन एक स्ट्रिंग लेता है और एक इंडेक्स वैल्यू लौटाता है, अब तक इसका काम बहुत अच्छा है। और कम टक्कर है। सूचकांक 0 से लेकर - 300 तक शायद इससे भी अधिक है, लेकिन मैंने अब तक "इलेक्ट्रोकेनिकल इंजीनियरिंग" जैसे लंबे शब्दों के साथ कोई भी उच्च अंक प्राप्त नहीं किया है।

int keyHash(string key)
{
    unsigned int k = (int)key.length();
    unsigned int u = 0,n = 0;

    for (Uint i=0; i<k; i++)
    {
        n = (int)key[i];
        u += 7*n%31;
    }
    return u%139;
}

एक और चीज जो आप कर सकते हैं वह प्रत्येक वर्ण int parse को अनुक्रमणिका से गुणा कर रहा है क्योंकि यह "भालू" (0 * b) + (1 * e) + (2 * a) + (3 * r) जैसे शब्द बढ़ाता है जो आपको देगा। एक अंतर मूल्य के साथ खेलने के लिए। ऊपर दिया गया पहला हैश फ़ंक्शन "यहाँ" और "सुनना" पर टकराता है लेकिन फिर भी कुछ अच्छे अनूठे मूल्य देता है। नीचे वाला "यहाँ" और "सुन" से नहीं टकराता क्योंकि मैं प्रत्येक वर्ण को सूचकांक के साथ गुणा करता हूँ क्योंकि यह बढ़ता है।

int keyHash(string key)
{
    unsigned int k = (int)key.length();
    unsigned int u = 0,n = 0;

    for (Uint i=0; i<k; i++)
    {
        n = (int)key[i];
        u += i*n%31;
    }
    return u%139;
}

-1

यहाँ एक साधारण हैश फ़ंक्शन है जिसका उपयोग मैं अपने द्वारा बनाई गई हैश तालिका के लिए करता हूँ। मूल रूप से एक टेक्स्ट फ़ाइल लेने के लिए और प्रत्येक शब्द को एक सूचकांक में संग्रहीत करता है जो वर्णमाला के क्रम का प्रतिनिधित्व करता है।

int generatehashkey(const char *name)
{
        int x = tolower(name[0])- 97;
        if (x < 0 || x > 25)
           x = 26;
        return x;
}

यह मूल रूप से क्या करता है शब्द उनके पहले अक्षर के अनुसार हैशेड हैं। तो, 'a' से शुरू होने वाले शब्द को 0 की हैश कुंजी मिलेगी, 'b' को 1 और इसी तरह 'z' मिलेगा और 'z' 25 होगा। संख्या और प्रतीकों में 26 की हैश कुंजी होगी। यह एक ऐसा लाभ है जो प्रदान करता है। ; आप आसानी से और जल्दी से गणना कर सकते हैं कि किसी दिए गए शब्द को हैश तालिका में अनुक्रमित किया जाएगा क्योंकि सभी वर्णमाला के क्रम में कुछ इस तरह हैं: कोड यहां पाया जा सकता है: https://github.com/abhijitcpatil/general

निम्नलिखित पाठ को इनपुट के रूप में देते हुए: एटिकस ने एक दिन जेम से कहा, "मैं आपको पिछवाड़े में टिन के डिब्बे में गोली मारना चाहता हूं, लेकिन मुझे पता है कि आप पक्षियों के बाद जाएंगे। अगर आप उन्हें मार सकते हैं, तो सभी नीले रंग की किरणों को गोली मार दें, लेकिन याद रखें कि मॉकिंगबर्ड को मारना एक पाप है। ” केवल यही समय था जब मैंने कभी अटारीस को यह कहते सुना कि यह कुछ करना पाप है, और मैंने मिस मौडी से इसके बारे में पूछा। "आपके पिता का अधिकार," उसने कहा। “मॉकिंगबर्ड्स हमें आनंद लेने के लिए संगीत बनाने के अलावा एक काम नहीं करते हैं। वे लोगों के बगीचों को नहीं खाते, मकई के दानों में घोंसला नहीं बनाते, वे एक काम नहीं करते, लेकिन हमारे लिए अपना दिल खोलकर गाते हैं। इसलिए मॉकिंगबर्ड को मारना पाप है।

यह आउटपुट होगा:

0 --> a a about asked and a Atticus a a all after at Atticus
1 --> but but blue birds. but backyard
2 --> cribs corn can cans
3 --> do dont dont dont do dont do day
4 --> eat enjoy. except ever
5 --> for for fathers
6 --> gardens go
7 --> hearts heard hit
8 --> its in it. I it I its if I in
9 --> jays Jem
10 --> kill kill know
11 --> 
12 --> mockingbird. music make Maudie Miss mockingbird.”
13 --> nest
14 --> out one one only one
15 --> peoples
16 --> 17 --> right remember rather
18 --> sin sing said. she something sin say sin Shoot shot said
19 --> to Thats their thing they They to thing to time the That to the the tin to
20 --> us. up us
21 --> 
22 --> why was was want
23 --> 
24 --> you you youll you
25 --> 
26 --> Mockingbirds  Your em Id

2
एक अच्छा हैश फंक्शन बकेट्स में समान रूप से मान वितरित करता है।
जोनाथन पीटरसन

-1

यह किसी भी टकराव से बच जाएगा और यह तब तक तेज होगा जब तक हम गणना में बदलाव का उपयोग नहीं करते।

 int k = key.length();
    int sum = 0;
    for(int i = 0 ; i < k-1 ; i++){
        sum += key.charAt(i)<<(5*i);
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.