हजार टेलीफोन नंबर स्टोर करने का सबसे कारगर तरीका


94

यह एक Google साक्षात्कार प्रश्न है:

10 अंकों वाले प्रत्येक को संग्रहीत करने के लिए लगभग हजार फोन नंबर हैं। आप मान सकते हैं कि प्रत्येक के पहले 5 अंक हजार संख्याओं में समान होंगे। आपको निम्न कार्य करने होंगे: a। यदि दी गई संख्या मौजूद है तो खोजें। ख। सभी नंबर प्रिंट कर लें

ऐसा करने के लिए सबसे कुशल अंतरिक्ष बचत तरीका क्या है?

मैंने हैश टेबल और बाद में हफ़मैन कोडिंग का जवाब दिया लेकिन मेरे साक्षात्कारकर्ता ने कहा कि मैं सही दिशा में नहीं जा रहा था। कृपया यहाँ मेरी मदद करें।

एक प्रत्यय trie मदद का उपयोग कर सकता है?

आदर्श रूप से 1000 नंबरों के भंडारण में प्रति नंबर 4 बाइट्स लगते हैं इसलिए सभी में 1000 नंबरों को स्टोर करने के लिए 4000 बाइट्स लगेंगे। मात्रात्मक रूप से, मैं स्टोरेज को कम करके <4000 बाइट्स करना चाहता हूं, यह मेरे साक्षात्कारकर्ता ने मुझे समझाया है।


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

1
@AndreasBonini: मैं शायद वह जवाब दूंगा, जब तक कि मैं Google या फेसबुक जैसी किसी कंपनी में इंटरव्यू नहीं दे रहा था, मैं बॉक्स सॉल्यूशंस से बाहर था, बस उसे काटे नहीं। हालांकि उदाहरण के लिए पोस्टग्रैज ने कोशिशें की हैं, मुझे भी यकीन नहीं होगा कि इन डेटा के माध्यम से google को लेने की जरूरत है।
LiKao

1
@ लिकाओ: ध्यान रखें कि ओपी ने विशेष रूप से "एक हजार संख्या के आसपास" कहा
थॉमस बोनीनी

@AndreasBonini: सच है, यह भी एक परीक्षा हो सकती है, कि साक्षात्कारकर्ता इस तरह की बाधाओं को सही ढंग से व्याख्या करना जानता है और इसके अनुसार सबसे अच्छा समाधान चुनता है।
लीकाओ

4
इस प्रश्न में "कुशल" को वास्तव में परिभाषित करने की आवश्यकता है - किन तरीकों से कुशल? अंतरिक्ष, समय, दोनों?
मैट बी

जवाबों:


36

यहाँ aix के उत्तर में सुधार है । डेटा संरचना के लिए तीन "परतों" का उपयोग करने पर विचार करें: पहला पहले पांच अंकों (17 बिट्स) के लिए एक स्थिर है; इसलिए यहां से, प्रत्येक फोन नंबर में केवल पांच अंक शेष हैं। 17-बिट बाइनरी पूर्णांकों और दुकान के रूप में हम इन शेष पाँच अंक देखने कश्मीर - एक विधि और 17 का उपयोग करते हुए उन बिट्स के कश्मीर = मीटर एक अलग विधि के साथ, निर्धारित करने कश्मीर अंत में आवश्यक स्थान कम करने के लिए।

हम पहले फ़ोन नंबर (सभी घटाए गए 5 दशमलव अंकों) को क्रमबद्ध करते हैं। फिर हम गिनते हैं कि कितने फ़ोन नंबर हैं जिनके लिए पहले m बिट्स से युक्त बाइनरी नंबर सभी 0 हैं, कितने फ़ोन नंबर के लिए पहला m बिट्स सबसे अधिक 0 ... 01 हैं, कितने फ़ोन नंबर पहले m हैं बिट्स अधिकतम 0 ... 10, वगैरह, फोन नंबरों की गिनती तक जिसके लिए पहले मी बिट्स 1 ... 11 हैं - यह अंतिम गिनती 1000 (दशमलव) है। इस तरह के काउंट्स 2 ^ मी होते हैं और प्रत्येक काउंट अधिकतम 1000 पर होता है। यदि हम पिछले एक को छोड़ देते हैं (क्योंकि हम जानते हैं कि यह वैसे भी 1000 है), हम इन सभी नंबरों को (2 ^ m - 1) के सन्निहित ब्लॉक में स्टोर कर सकते हैं। * 10 बिट्स। (10 बिट्स 1024 से कम संख्या के भंडारण के लिए पर्याप्त हैं।)

सभी (कम) फोन नंबरों के अंतिम k बिट्स को स्मृति में संचित रूप से संग्रहीत किया जाता है; इसलिए यदि k , 7 है, तो मेमोरी के इस ब्लॉक के पहले 7 बिट्स (बिट्स 0 थ्रू 6) पहले (कम) फोन नंबर के अंतिम 7 बिट्स के बराबर हैं, बिट्स 7 थ्रू 13 पिछले 7 बिट्स के अनुरूप हैं दूसरा (कम) फोन नंबर, वगैरह। इसके लिए कुल 17 + (2 ^ (17 - k ) - 1) * 10 + 1000 * k के लिए 1000 * k बिट्स की आवश्यकता होती है , जो k = 10. के लिए अपने न्यूनतम 11287 अंक प्राप्त करता है। इसलिए हम सभी फोन नंबरों को Ceil () में स्टोर कर सकते हैं 11287/8) = 1411 बाइट्स।

अतिरिक्त स्थान को यह देखते हुए बचाया जा सकता है कि हमारी कोई भी संख्या उदाहरण के लिए 1111111 (बाइनरी) से शुरू नहीं हो सकती है, क्योंकि सबसे कम संख्या जो कि 130048 से शुरू होती है और हमारे पास केवल पांच दशमलव अंक हैं। यह हमें मेमोरी के पहले ब्लॉक से कुछ प्रविष्टियों को शेव करने की अनुमति देता है: 2 ^ m - 1 काउंट के बजाय , हमें केवल छत (99999/2 ^ k ) की आवश्यकता है। अर्थात सूत्र बन जाता है

17 + छत (99999/2 ^ k ) * 10 + 1000 * k

जो आश्चर्यजनक रूप से k = 9 और k = 10, या छत (10997/8) = 1375 बाइट्स दोनों के लिए अपने न्यूनतम 10997 प्राप्त करता है ।

यदि हम यह जानना चाहते हैं कि क्या एक निश्चित फ़ोन नंबर हमारे सेट में है, तो हम पहले जाँचते हैं कि पहले पाँच बाइनरी अंक हमारे द्वारा संग्रहित पाँच अंकों से मेल खाते हैं या नहीं। फिर हम शेष पाँच अंकों को उसके शीर्ष m = 7 बिट्स में विभाजित करते हैं (जो है, कहते हैं, m -bit संख्या M ) और इसके निचले k = 10 बिट्स (संख्या K )। अब हम नंबर मिल एक कम फोन नंबर है जिसके लिए पहले की [एम -1] मीटर अंक अधिक से अधिक कर रहे हैं एम 1, और संख्या - एक [एम] कम फोन नंबर है जिसके लिए पहले से मीटर अंक अधिक से अधिक कर रहे हैं एम , दोनों बिट्स के पहले ब्लॉक से। अब हम एक के बीच की जाँच करते हैं[एम -1] वें और एक [एम] वें बिट्स में k बिट्स का अनुक्रम, यह देखने के लिए कि क्या हम के ; सबसे खराब स्थिति में 1000 ऐसे क्रम होते हैं, इसलिए यदि हम द्विआधारी खोज का उपयोग करते हैं तो हम ओ (लॉग 1000) संचालन में समाप्त हो सकते हैं।

सभी 1000 नंबर मुद्रण के लिए स्यूडोकोड, इस प्रकार मैं कहाँ तक पहुँच कश्मीर 'वें कश्मीर -बिट के रूप में स्मृति के पहले खंड के प्रवेश एक [K] और एम ' वें मीटर के रूप में स्मृति के दूसरे खंड के -बिट प्रविष्टि [एम] (इन दोनों को कुछ बिट संचालन की आवश्यकता होगी जो बाहर लिखने के लिए थकाऊ हैं)। पहले पांच अंक संख्या सी में हैं

i := 0;
for K from 0 to ceil(99999 / 2^k) do
  while i < a[K] do
    print(c * 10^5 + K * 2^k + b[i]);
    i := i + 1;
  end do;
end do;

हो सकता है कि K = Ceil (99999/2 ^ k ) के लिए सीमा मामले में कुछ गलत हो , लेकिन इसे ठीक करना काफी आसान है।

अंत में, एक एन्ट्रापी दृष्टिकोण से, यह संभव नहीं है कि 10 ^ 3 पॉजिटिव पूर्णांकों का एक सबसेट स्टोर करें जो सभी 10 से कम ^ 5 से कम छत (लॉग [2] (द्विपद (10 ^ 5, 10 ^ 3)) से कम हो। ) = The० 17३। पहले ५ अंकों के लिए हमें जो १ Includ चाहिए, उसमें १० ९९ - bits० ९ ० = २ ९ ० 80 बिट्स का अंतर अभी भी है। यह देखना एक दिलचस्प चुनौती है कि क्या बेहतर समाधान हैं जहां आप अभी भी अपेक्षाकृत कुशलता से संख्याओं तक पहुंच सकते हैं!


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

हाय एरिक, जब से आपने कहा था कि आप अन्य विकल्पों को देखने के लिए इच्छुक होंगे, मेरा समाधान देखें। यह इसे 8,580 बिट्स में हल करता है, जो कि सैद्धांतिक न्यूनतम से सिर्फ 490 बिट्स है। यह अलग-अलग संख्याओं को देखने के लिए थोड़ा अक्षम है, लेकिन भंडारण बहुत कॉम्पैक्ट है।
Briguy37

1
मुझे लगता है कि एक समझदार साक्षात्कारकर्ता "एक जटिल कस्टम मेड डेटाबेस" के बजाय "एक ट्राई" जवाब पसंद करेंगे। यदि आप अपने 133 वें हैकिंग कौशल का प्रदर्शन करना चाहते हैं, तो आप जोड़ सकते हैं - "इस विशेष मामले के लिए एक विशिष्ट ट्री एल्गोरिदम बनाना संभव होगा, यदि नेकसेरी।"
कार्ल 14

नमस्ते, क्या आप कृपया बता सकते हैं कि कैसे 5 अंकों को संग्रहीत करने में 17 बिट्स लगते हैं?
तुषार बान

@ तुषार पाँच अंक 00000 और 99999 के बीच एक संख्या को सम्मिलित करते हैं। बाइनरी में उस संख्या का प्रतिनिधित्व करते हैं। 2 ^ 17 = 131072, तो 17 बिट उसके लिए पर्याप्त हैं, लेकिन 16 नहीं।
एरिक पी।

43

इस प्रकार, मैं संख्याओं को पूर्णांक चर के रूप में मानता हूं (जैसा कि स्ट्रिंग्स के विपरीत):

  1. संख्या को क्रमबद्ध करें।
  2. प्रत्येक संख्या को पहले पाँच अंकों और अंतिम पाँच अंकों में विभाजित करें।
  3. पहले पाँच अंक संख्याओं में समान हैं, इसलिए उन्हें केवल एक बार संग्रहीत करें। इसके लिए 17 बिट्स स्टोरेज की आवश्यकता होगी।
  4. प्रत्येक नंबर के अंतिम पांच अंकों को व्यक्तिगत रूप से संग्रहीत करें। इसके लिए प्रति नंबर 17 बिट्स की आवश्यकता होगी।

पुनरावृत्ति करने के लिए: पहले 17 बिट्स सामान्य उपसर्ग हैं, 17 बिट्स के बाद के 1000 समूह आरोही क्रम में संग्रहीत प्रत्येक संख्या के अंतिम पांच अंक हैं।

कुल में हम 1000 संख्याओं के लिए 2128 बाइट्स या 10-अंकीय टेलीफोन नंबर प्रति 17.017 बिट्स देख रहे हैं।

खोज O(log n)(बाइनरी सर्च) है और पूर्ण गणना है O(n)


उह, अंतरिक्ष की जटिलता कहां है?
aioobe

निर्माण के लिए बहुत समय (O (log (n) * n k) (k लंबाई है) छँटाई के लिए, O (n k) की तुलना में trie बनाने के लिए)। इसके अलावा अंतरिक्ष इष्टतम से बहुत दूर है, क्योंकि अब सामान्य उपसर्ग व्यक्तिगत रूप से संग्रहीत होते हैं। खोज का समय भी इष्टतम नहीं है। इस तरह स्ट्रिंग डेटा के लिए संख्या की लंबाई को भूलना आसान है, जो खोज पर हावी है। यानी बाइनरी सर्च ओ (लॉग (एन) * के) है, जबकि एक ट्राइ को केवल ओ (के) की आवश्यकता होती है। जब आप निरंतर होते हैं, तो आप थ्रेस एक्सप्रेशन को कम कर सकते हैं, लेकिन यह एक सामान्य समस्या है जब डेटस्ट्रक्टर्स स्ट्रिंग्स के बारे में तर्क देते हैं।
लीकाओ

@ लिकाओ: तार के बारे में कुछ भी किसने कहा? मैं विशेष रूप से पूर्णांक चर के साथ काम कर रहा हूं इसलिए kअप्रासंगिक है।
एनपीई

1
ठीक है, मैं फिर जवाब गलत। फिर भी, सामान्य भागों को एक साथ संग्रहीत नहीं किया जाता है, इसलिए अंतरिक्ष दक्षता के बारे में बात बनी हुई है। 5 अंकों की संख्या के 1000 के लिए, सामान्य उपसर्गों की एक उचित मात्रा होगी, इसलिए इनको कम करने से बहुत मदद मिलेगी। साथ ही संख्या के मामले में हमारे पास स्ट्रिंग्स के लिए O (लॉग (n)) बनाम O (k) है, जो अभी भी तेज है।
लीकाओ

1
@ गीक: 17 बिट्स के 1001 समूह 17017 बिट्स या 2128 बाइट्स (कुछ बदलाव के साथ) हैं।
एनपीई

22

http://en.wikipedia.org/wiki/Acyclic_deterministic_finite_automaton

मेरे पास एक बार एक साक्षात्कार था जहां उन्होंने डेटा संरचनाओं के बारे में पूछा था। मैं "ऐरे" को भूल गया।


1
+1 यह निश्चित रूप से जाने का रास्ता है। मैंने इसे एक अन्य नाम, लाइब्रेरी ट्री या लेक्सिकल सर्च ट्री या कुछ के तहत सीखा जब मैं एक छात्र था (यदि कोई याद करता है कि पुराना नाम कृपया बताएं)।
वालमंड

6
यह 4000 बाइट आवश्यकता को पूरा नहीं करता है। अकेले प्‍वाइंटर स्‍टोरेज के लिए, सबसे खराब स्थिति यह है कि आपको 1-4 वें पत्‍ते के लिए अगले स्‍तर पर 1 प्वाइंटर की जरूरत होगी, 5 वें के लिए 10 पॉइंटर्स, 6 वें के लिए 100 और 7 वें, 8 वें और 9 वें लेवल के लिए 1000 , जो हमारे पॉइंटर को कुल 3114 तक लाता है। यह पॉइंटर्स को इंगित करने के लिए कम से कम 3114 अलग-अलग मेमोरी लोकेशन देता है, जिसका मतलब है कि आपको प्रत्येक पॉइंटर के लिए कम से कम 12 बिट्स की आवश्यकता होगी। 12 * 3114 = 37368 बिट्स = 4671 बाइट्स> 4000 बाइट्स, और यह भी आंकड़ा नहीं है कि आप प्रत्येक पत्ती के मूल्य का प्रतिनिधित्व कैसे करते हैं!
Briguy37

16

मैं शायद एक ट्राइ के कुछ संपीड़ित संस्करण का उपयोग करने पर विचार करूँगा (संभवतः @Misha द्वारा सुझाया गया DAWG)।

यह स्वचालित रूप से इस तथ्य का लाभ उठाएगा कि वे सभी एक सामान्य उपसर्ग हैं।

खोज निरंतर समय में की जाएगी, और मुद्रण रैखिक समय में किया जाएगा।


सवाल डेटा को स्टोर करने के सबसे अधिक स्थान-कुशल तरीके के बारे में है। क्या आप इस बात का कुछ अनुमान प्रदान करेंगे कि 1000 फोन नंबरों के लिए इस विधि की कितनी जगह की आवश्यकता होगी? धन्यवाद।
एनपीई

तीनों के लिए स्थान सबसे अधिक O (n * k) पर है जहाँ n स्ट्रिंग्स की संख्या है और k प्रत्येक स्ट्रिंग की लंबाई है। इस बात को ध्यान में रखते हुए कि आपको संख्याओं का प्रतिनिधित्व करने के लिए 8 बिट वर्णों की आवश्यकता नहीं है, मैं सुझाव दूंगा कि 4 हेक्साडेसिमल इंडेक्स हेक्साडेक्सिमल और शेष बिट के लिए एक। इस तरह आपको अधिकतम 17 बिट प्रति संख्या की आवश्यकता होती है। क्योंकि आप सभी मामलों में इस कोडिंग के साथ सभी स्तरों पर झड़प करेंगे, आप वास्तव में इससे नीचे आ सकते हैं। यह उम्मीद करते हुए कि हम 1000 नंबर स्टोर करते हैं, हम पहले स्तर पर होने वाली झड़पों के लिए पहले से ही कुल 250 बिट्स बचा सकते हैं। सर्वश्रेष्ठ उदाहरण डेटा पर सही कोडिंग का परीक्षण करें।
लीकाओ

@LiKao, सही है, और यह देखते हुए कि, उदाहरण के लिए, 1000 संख्याओं में 100 से अधिक विभिन्न अंतिम दो अंक नहीं हो सकते हैं, अंतिम स्तर पर तीनों का काफी पतन हो सकता है।
anioobe

@ वायो: पत्तियां आखिरी स्तर पर ढह सकती हैं क्योंकि बच्चे नहीं हैं। हालांकि, दूसरे से अंतिम स्तर पर पत्तियों को 2 ^ 10 = 1024 राज्यों की आवश्यकता होती है (प्रत्येक अंतिम अंक चालू या बंद हो सकता है), इसलिए यह इस मामले में फिर से उपयोग करने योग्य नहीं है क्योंकि केवल 1000 नंबर हैं। इसका मतलब है कि सबसे खराब स्थिति वाले बिंदुओं की संख्या 3114 पर है (मीशा के उत्तर पर मेरी टिप्पणी देखें) जबकि आवश्यक पत्ते 5 + 10 + 100 + 1000 + 1000 + 10 = 2125 पर जाते हैं, जो प्रत्येक के लिए आवश्यक 12 बाइट्स नहीं बदलता है सूचक। इस प्रकार, यह अभी भी केवल संकेत बिंदुओं पर विचार करते हुए 4671 बाइट्स में एक ट्राई समाधान डालता है।
Briguy37

@ Briguy37, मुझे यकीन नहीं है कि मुझे आपका " प्रत्येक अंतिम अंक " तर्क पर या बंद हो सकता है। सभी संख्याएं 10 अंकों की लंबी, सही हैं?
एरियोबे

15

मैंने पहले इस समस्या के बारे में सुना है (लेकिन पहले-5-अंकों के बिना-एक ही धारणा), और इसे करने का सबसे सरल तरीका था राइस कोडिंग :

1) चूंकि ऑर्डर मायने नहीं रखता है इसलिए हम उन्हें सॉर्ट कर सकते हैं, और लगातार मूल्यों के बीच के अंतर को बचा सकते हैं। हमारे मामले में औसत अंतर 100.000 / 1000 = 100 होगा

2) राइस कोड (बेस 128 या 64) या यहां तक ​​कि गोलम कोड (बेस 100) का उपयोग करके अंतरों को एनकोड करें।

EDIT: राइस कोडिंग के लिए एक अनुमान 128 बेस के साथ (ऐसा नहीं है क्योंकि यह सर्वोत्तम परिणाम देगा, लेकिन क्योंकि इसकी गणना करना आसान है):

हम (32 बिट्स) के रूप में पहला मान सहेजेंगे।
बाकी 999 मान अंतर हैं (हम उम्मीद करते हैं कि वे छोटे होंगे, औसतन 100) में शामिल होंगे:

यूनिरी वैल्यू value / 128(बिट्स के रूप में बिट्स + 1 बिट्स) (7 बिट्स) के
लिए बाइनरी वैल्यूvalue % 128

हमें VBLचर बिट्स की संख्या के लिए किसी भी सीमा (इसे कॉल करें ) का अनुमान लगाना होगा :
निचली सीमा: विचार करें कि हम भाग्यशाली हैं, और कोई अंतर हमारे आधार से बड़ा नहीं है (इस मामले में 128)। इसका मतलब होगा 0 अतिरिक्त बिट्स देना।
उच्च सीमा: चूंकि आधार से छोटे सभी अंतरों को संख्या के द्विआधारी भाग में एन्कोड किया जाएगा, इसलिए अधिकतम संख्या जिसे हमें संयुक्त रूप से सांकेतिक शब्दों में बदलना होगा, वह 100000/128 = 781.25 (इससे भी कम है, क्योंकि हम अंतर के अधिकांश शून्य होने की उम्मीद नहीं करते हैं )।

तो, परिणाम 32 + 999 * (1 + 7) + चर (0..782) बिट्स = 1003 + चर (0..98) बाइट्स है।


क्या आप जिस तरह से एन्कोडिंग कर रहे हैं और अंतिम आकार गणना के बारे में अधिक जानकारी दे सकते हैं। 1101 बाइट्स या 8808 बिट्स 8091 बिट्स की सैद्धांतिक सीमा के बहुत करीब लगती हैं, इसलिए मैं बहुत हैरान हूं, कि व्यवहार में ऐसा कुछ हासिल करना संभव है।
LiKao

क्या यह 32 + 999 * (1 + 7 + variable(0..782))बिट्स नहीं होगा ? 999 नंबर में से प्रत्येक को एक प्रतिनिधित्व की आवश्यकता है value / 128
कर्क ब्रॉडहर्स्ट

1
@ किर्क: नहीं, यदि वे सभी 5 अंकों की सीमा में हैं। ऐसा इसलिए है क्योंकि हम उम्मीद करेंगे कि इन सभी अंतरों को याद रखें (याद रखें, हम लगातार मूल्यों के बीच अंतरों को कूटबद्ध करते हैं, न कि पहले और Nth मूल्य के बीच) 100000 (सबसे खराब स्थिति में भी) से नीचे होगा
ruslik

पहले मूल्य (9,999,999,999> 2 ^ 32 = 4,294,967,296) का प्रतिनिधित्व करने के लिए आपको 32 बिट्स के बजाय 34 बिट्स की आवश्यकता है। इसके अलावा, संख्याओं के विशिष्ट होने के बाद से अधिकतम अंतर 00000 से 99001 तक होगा, जो आधार 128 के लिए 782 के बजाय 774 1 को जोड़ देगा। इस प्रकार आधार 128 के लिए 1,000 नंबरों के भंडारण के लिए आपकी सीमा 8026-8800 बिट्स या 1004-1100 बाइट्स है। 64-बिट बेस 879-1072 बाइट्स से बेहतर स्टोरेज देता है।
Briguy37

1
@raisercostin: यही किर्क ने पूछा है। आपके उदाहरण में, पहले दो मूल्यों के बीच 20k अंतर पर एक बार एन्कोडिंग करके, अधिकतम सीमा का केवल 80k भविष्य में घटाना संभव होगा। यह अधिकतम 782 में से 20k / 128 = 156 यूनिक बिट्स का उपयोग करेगा (जो कि 100k के अनुरूप है)
ruslik

7

यह बेंटले के प्रोग्रामिंग पर्ल से एक अच्छी तरह से ज्ञात समस्या है।

समाधान: संख्याओं के पहले पाँच अंकों को पट्टी करें क्योंकि वे हर संख्या के लिए समान हैं। फिर शेष 9999 संभावित मूल्य का प्रतिनिधित्व करने के लिए बिटवाइज़-ऑपरेशन का उपयोग करें। आपको संख्याओं का प्रतिनिधित्व करने के लिए केवल 2 ^ 17 बिट्स की आवश्यकता होगी। प्रत्येक बिट एक संख्या का प्रतिनिधित्व करता है। यदि बिट सेट है, तो नंबर टेलीफ़ोन बुक में है।

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

आप O (1) में एक संख्या की खोज कर सकते हैं और बिट की पुनरावृत्ति के कारण अंतरिक्ष दक्षता अधिकतम है।

एचटीएच क्रिस।


3
यह संख्या के घने सेट के लिए एक अच्छा तरीका होगा। दुर्भाग्य से, यहां सेट बहुत विरल है: संभावित 100,000 में से केवल 1,000 नंबर हैं। इसलिए यह दृष्टिकोण औसतन प्रति संख्या 100 बिट्स की आवश्यकता होगी। एक विकल्प के लिए मेरा जवाब देखें जिसे केवल ~ 17 बिट्स की आवश्यकता है।
एनपीई

1
क्या सभी संख्याओं को प्रिंट करने में लगने वाला समय 1,000 के बजाय 100,000 के अनुपात में नहीं होगा?
एयरोबे

दो विचारों को मिलाकर आप मूल रूप से तुरंत तीनों प्राप्त करते हैं। १००,००० प्रविष्टियों के साथ एक बिटवेक्टर का उपयोग करना समग्र तरीके से होता है और ज्यादा जगह लेता है। हालाँकि O (लॉग (n)) लुकअप अक्सर बहुत धीमा होता है (यहाँ प्रश्नों की संख्या पर निर्भर करता है)। इसलिए अनुक्रमण के लिए बिट सेटों की एक श्रेणी का उपयोग करते हुए, आप O (1) लुकअप प्राप्त करते हुए, अधिकतम 17 बिट्स प्रति नंबर पर संग्रहीत करेंगे। यह त्रिगुण कैसे काम करता है। मुद्रण के लिए भी समय ट्राइ के लिए ओ (एन) में है, जो इसे हल किए गए मामले से विरासत में मिला है।
लीकाओ

यह "ऐसा करने के लिए सबसे कुशल अंतरिक्ष बचत तरीका" नहीं है।
जेक बर्गर

5

1,000 नंबरों के लिए 1073 बाइट्स का निश्चित भंडारण:

इस संग्रहण विधि का मूल प्रारूप पहले 5 अंक, प्रत्येक समूह के लिए एक गिनती और प्रत्येक समूह में प्रत्येक संख्या के लिए ऑफसेट को संग्रहीत करना है।

उपसर्ग:
हमारा 5 अंकों का उपसर्ग पहले 17 बिट्स लेता है ।

समूहीकरण:
अगला, हमें संख्याओं के लिए एक अच्छे आकार के समूह का पता लगाने की आवश्यकता है। आइए कोशिश करें कि प्रति समूह लगभग 1 नंबर हो। चूंकि हम जानते हैं कि स्टोर करने के लिए लगभग 1000 नंबर हैं, हम 99,999 को लगभग 1000 भागों में विभाजित करते हैं। यदि हमने समूह आकार 100 के रूप में चुना है, तो व्यर्थ बिट्स होंगे, तो आइए 128 के समूह आकार का प्रयास करें, जिसे 7 बिट्स के साथ दर्शाया जा सकता है। यह हमारे साथ काम करने के लिए 782 समूह देता है।

गणना:
अगला, 782 समूहों में से प्रत्येक के लिए, हमें प्रत्येक समूह में प्रविष्टियों की गणना करने की आवश्यकता है। प्रत्येक समूह के लिए 7-बिट की गणना होगी 7*782=5,474 bits, जो बहुत ही अक्षम है क्योंकि प्रतिनिधित्व की गई औसत संख्या लगभग 1 है क्योंकि हमने अपने समूहों को कैसे चुना।

इस प्रकार, इसके बजाय हमारे पास समूह में प्रत्येक संख्या के लिए अग्रणी 1 के साथ चर आकार मायने रखता है 0. इसके बाद एक समूह है। यदि हमारे पास xएक समूह में संख्याएं हैं , तो हमने गिनती का प्रतिनिधित्व करने के लिए x 1'sएक 0का पालन ​​किया होगा । उदाहरण के लिए, यदि हमारे पास समूह में 5 संख्याएँ होती हैं, तो गिनती का प्रतिनिधित्व किया जाएगा 111110। इस पद्धति के साथ, अगर 1000 की संख्या है, तो हम 1000 1 और 782 0 के साथ कुल 1000 + 782 = 1,782 बिट्स के लिए समाप्त होते हैं ।

ऑफसेट:
अंतिम, प्रत्येक संख्या का प्रारूप सिर्फ प्रत्येक समूह के लिए 7-बिट ऑफसेट होगा। उदाहरण के लिए, यदि 00-12 और 00001 0-127 समूह में केवल संख्याएँ हैं, तो उस समूह के लिए बिट्स होंगे 110 0000000 0000001। 1,000 नंबरों को मानते हुए, ऑफसेट के लिए 7,000 बिट्स होंगे ।

इस प्रकार हमारी अंतिम संख्या 1000 संख्या मानती है:

17 (prefix) + 1,782 (counts) + 7,000 (offsets) = 8,799 bits = 1100 bytes

अब, देखते हैं कि क्या हमारे समूह-आकार का चयन 128 बिट तक गोल करके समूह आकार के लिए सबसे अच्छा विकल्प था। xप्रत्येक समूह का प्रतिनिधित्व करने के लिए बिट्स की संख्या के रूप में चुनना , आकार के लिए सूत्र है:

Size in bits = 17 (prefix) + 1,000 + 99,999/2^x + x * 1,000

के पूर्णांक मूल्यों के लिए इस समीकरण को न्यूनतम xदेता है x=6, जो करीब 8,580 बिट = पैदावार 1,073 बाइट्स । इस प्रकार, हमारा आदर्श भंडारण निम्नानुसार है:

  • समूह का आकार: 2 ^ 6 = 64
  • समूहों की संख्या: 1,562
  • कुल संग्रहण:

    1017 (prefix plus 1's) + 1563 (0's in count) + 6*1000 (offsets) = 8,580 bits = 1,073 bytes


1

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

इसके साथ समस्या यह है, कि आपको अपने प्रोग्राम में 2 ^ 8000 सेट में से प्रत्येक का प्रतिनिधित्व एक लुट के रूप में करना होगा, और यह भी नहीं कि Google इसके लिए दूरस्थ रूप से सक्षम होगा।

लुकअप O (1) होगा, जो सभी नंबर O (n) को प्रिंट करेगा। सम्मिलन O (2 ^ 8000) होगा जो सिद्धांत में O (1) है, लेकिन व्यवहार में अनुपयोगी है।

एक साक्षात्कार में मैं केवल यह उत्तर दूंगा, अगर मुझे यकीन था, कि कंपनी किसी ऐसे व्यक्ति की तलाश कर रही है जो बॉक्स से बाहर बहुत कुछ सोच सके। अन्यथा यह आपको वास्तविक दुनिया की चिंताओं के साथ एक सिद्धांतवादी की तरह लग सकता है।

संपादित करें : ठीक है, यहाँ एक "कार्यान्वयन" है।

कार्यान्वयन के निर्माण के लिए कदम:

  1. 100 000 * आकार का एक निरंतर सरणी लें (1000 100 000 चुनें) बिट्स। हां, मैं इस तथ्य से अवगत हूं कि इस सरणी को ब्रह्मांड में परमाणुओं की तुलना में कई परिमाणों से अधिक जगह की आवश्यकता होगी।
  2. 100 000 प्रत्येक के विखंडू में इस बड़े सरणी को अलग करें।
  3. प्रत्येक कबाड़ में पिछले पांच अंकों के एक विशिष्ट संयोजन के लिए थोड़ा सा सरणी स्टोर करें।

यह प्रोग्राम नहीं है, बल्कि एक तरह का मेटा प्रोग्राम है, जो एक विशाल एलयूटी का निर्माण करेगा जिसे अब एक प्रोग्राम में उपयोग किया जा सकता है। अंतरिक्ष दक्षता की गणना करते समय प्रोग्राम की निरंतर सामग्री को आम तौर पर नहीं गिना जाता है, इसलिए हम इस सरणी के बारे में परवाह नहीं करते हैं, जब हमारी गणना करते हैं।

यहाँ इस LUT का उपयोग कैसे किया जाता है:

  1. जब कोई आपको 1000 नंबर देता है, तो आप पहले पांच अंकों को अलग-अलग स्टोर करते हैं।
  2. पता लगाएँ कि आपके सरणी में से कौन सा हिस्सा इस सेट से मेल खाता है।
  3. सेट की संख्या को एक एकल 8074 बिट संख्या (इस सी को कॉल करें) में स्टोर करें।

भंडारण के लिए इसका मतलब है कि हमें केवल 8091 बिट्स की आवश्यकता है, जिसे हमने यहां इष्टतम एन्कोडिंग साबित किया है। हालांकि सही चंक को खोजने में O (100 000 * (100 000 चुनें 1000)) लगता है, जो कि गणित के नियमों के अनुसार O (1) है, लेकिन व्यवहार में ब्रह्मांड के समय से अधिक समय लगेगा।

हालांकि लुकअप सरल है:

  1. पहले पाँच अंकों की पट्टी (शेष संख्या को n 'कहा जाएगा)।
  2. यदि वे मेल खाते हैं तो परीक्षण करें
  3. I = c * 100000 + n 'की गणना करें
  4. जांचें कि क्या LUT में आई बिट एक पर सेट है

सभी नंबरों को प्रिंट करना भी सरल है (और O (100000) = O (1) वास्तव में लेता है, क्योंकि आपको हमेशा वर्तमान चंक के सभी बिट्स की जांच करनी होती है, इसलिए मैंने इसे ऊपर गलत किया है)।

मैं इसे "कार्यान्वयन" नहीं कहूंगा, क्योंकि सीमाओं की घोर अवहेलना (ब्रह्मांड का आकार और समय यह ब्रह्मांड रहता है या यह पृथ्वी मौजूद होगी)। हालांकि सिद्धांत रूप में यह इष्टतम समाधान है। छोटी समस्याओं के लिए, यह वास्तव में किया जा सकता है, और कभी-कभी किया जाएगा। उदाहरण के लिए, सॉर्टिंग नेटवर्क कोडिंग के इस तरीके के लिए एक उदाहरण हैं, और एक बड़ा स्पीडअप प्राप्त करने के लिए, पुनरावर्ती सॉर्टिंग एल्गोरिदम में अंतिम चरण के रूप में उपयोग किया जा सकता है।


1
ऐसा करने के लिए सबसे कुशल अंतरिक्ष बचत तरीका क्या है?
स्वेन

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

1

यह 100,000 से कम प्रत्येक में एक हजार गैर-नकारात्मक पूर्णांक रखने के बराबर है। हम ऐसा करने के लिए अंकगणितीय एन्कोडिंग जैसी किसी चीज़ का उपयोग कर सकते हैं।

अंततः, क्रमबद्ध सूची में संख्याओं को संग्रहीत किया जाएगा। मैं ध्यान देता हूं कि सूची में आसन्न संख्याओं के बीच अनुमानित अंतर १००,००० / १००० = १०० है, जिसे। बिट्स में दर्शाया जा सकता है। ऐसे कई मामले भी होंगे जहां 7 से अधिक बिट्स आवश्यक हैं। इन कम सामान्य मामलों का प्रतिनिधित्व करने का एक सरल तरीका utf-8 योजना को अपनाना है जहां एक बाइट 7-बिट पूर्णांक का प्रतिनिधित्व करता है जब तक कि पहला बिट सेट नहीं होता है, उस स्थिति में जब अगले बाइट को 14-बिट पूर्णांक बनाने के लिए पढ़ा जाता है, जब तक कि इसका पहला बिट सेट है, जिस स्थिति में अगले बाइट को 21-बिट पूर्णांक का प्रतिनिधित्व करने के लिए पढ़ा जाता है।

तो लगातार पूर्णांक के बीच के कम से कम आधे अंतर को एक बाइट के साथ दर्शाया जा सकता है, और लगभग सभी को दो बाइट की आवश्यकता होती है। 16,384 की तुलना में बड़े अंतर से अलग किए गए कुछ नंबरों के लिए तीन बाइट्स की आवश्यकता होगी, लेकिन इनमें से 61 से अधिक नहीं हो सकते। औसत भंडारण तब प्रति संख्या लगभग 12 बिट्स, या थोड़ा कम, या अधिकतम 1500 बाइट्स होगा।

इस दृष्टिकोण के लिए नकारात्मक पक्ष यह है कि एक संख्या के अस्तित्व की जांच अब ओ (एन) है। हालांकि, किसी भी समय जटिलता की आवश्यकता निर्दिष्ट नहीं की गई थी।

लिखने के बाद, मैंने देखा कि रसिक ने पहले से ही अंतर विधि का सुझाव दिया था, एकमात्र अंतर एन्कोडिंग योजना है। मेरा होने की संभावना सरल लेकिन कम कुशल है।


1

बस किसी भी कारण को जल्दी से पूछने के लिए कि हम संख्याओं को आधार 36 में बदलना नहीं चाहेंगे। यह उतनी जगह नहीं बचा सकता है, लेकिन यह निश्चित रूप से खोज पर समय की बचत करेगा, क्योंकि यू बहुत कम दिख रहा है तो 10digts। या मैं उन्हें प्रत्येक समूह के आधार पर फाइलों में विभाजित कर दूंगा। इसलिए मैं एक फ़ाइल का नाम (111) -222.txt रखूंगा और फिर मैं केवल उन संख्याओं को संग्रहीत करूंगा जो उस समूह में फिट होते हैं और फिर उन्हें संख्यात्मक क्रम में खोजा जा सकता है इस तरह से मैं हमेशा यह देखने के लिए चक सकता हूं कि फ़ाइल बाहर निकलती है या नहीं। इससे पहले कि मैं एक बड़ी खोज चलाता हूं। या सही होने के लिए मैं द्विआधारी खोज के लिए एक फ़ाइल के लिए चला जाएगा यह देखने के लिए कि क्या यह बाहर निकलता है। और फ़ाइल की सामग्री पर एक और बोनरी खोज


0

इसे सरल क्यों नहीं रखा जाए? एक संरचना का उपयोग करें।

इसलिए हम पहले 5 अंको को एक स्थिरांक के रूप में सहेज सकते हैं, इसलिए अभी के लिए उन्हें भूल जाएं।

65535 सबसे अधिक है जिसे 16-बिट संख्या में संग्रहीत किया जा सकता है, और हमारे पास अधिकतम संख्या 99999 हो सकती है, जो अधिकतम 131071 के साथ 17 वें बिट नंबर के साथ फिट बैठता है।

32-बिट डेटा प्रकारों का उपयोग करना एक अपव्यय है क्योंकि हमें केवल 1 बिट अतिरिक्त 16 बिट्स की आवश्यकता होती है ... इसलिए, हम एक संरचना को परिभाषित कर सकते हैं जिसमें एक बूलियन (या वर्ण) और 16-बिट नंबर है।

सी / सी ++ मानकर

typedef struct _number {

    uint16_t number;
    bool overflow;
}Number;

इस संरचना में केवल 3-बाइट्स लगते हैं, और हमें 1000 की एक सरणी की आवश्यकता होती है, इसलिए कुल 3000 बाइट्स। हमने कुल स्पेस में 25% की कमी की है!

जहाँ तक संख्याओं को संचय करने की बात है, हम सरल बिटवाइज़ गणित कर सकते हैं

overflow = (number5digits & 0x10000) >> 4;
number = number5digits & 0x1111;

और उलटा

//Something like this should work
number5digits = number | (overflow << 4);

उन सभी को प्रिंट करने के लिए, हम सरणी पर एक साधारण लूप का उपयोग कर सकते हैं। एक विशिष्ट संख्या को प्राप्त करना निश्चित रूप से निरंतर समय में होता है, क्योंकि यह एक सरणी है।

for(int i=0;i<1000;i++) cout << const5digits << number5digits << endl;

एक संख्या की खोज करने के लिए, हम एक क्रमबद्ध सरणी चाहते हैं। इसलिए जब संख्याएं बच जाती हैं, तो सरणी को सॉर्ट करें (मैं व्यक्तिगत रूप से एक मर्ज सॉर्ट चुनूंगा, ओ (नॉग्लन))। अब खोज करने के लिए, मैं एक मर्ज सॉर्ट दृष्टिकोण जाएगा। सरणी को विभाजित करें, और देखें कि हमारा नंबर किसके बीच आता है। फिर फ़ंक्शन को केवल उस सरणी पर कॉल करें। जब तक आपके पास एक मैच न हो और इंडेक्स वापस न करें, तब तक इसे पुन: करें, अन्यथा, यह मौजूद नहीं है और एक त्रुटि कोड प्रिंट करता है। यह खोज काफी तेज होगी, और सबसे खराब स्थिति अभी भी O (nlogn) से बेहतर है क्योंकि यह मर्ज सॉर्ट की तुलना में कम समय में पूरी तरह से निष्पादित होगी (केवल दोनों पक्षों के बजाय प्रत्येक बार विभाजन के 1 पक्ष को दोहराते हुए :)), जो O (nlogn) है।


0

मेरा समाधान: सबसे अच्छा मामला 7.025 बिट्स / संख्या, सबसे खराब स्थिति 14.193 बिट्स / संख्या, औसत औसत 8.551 बिट्स / संख्या। स्ट्रीम-एन्कोडेड, कोई रैंडम एक्सेस नहीं।

रसिक के उत्तर को पढ़ने से पहले ही, मैंने तुरंत प्रत्येक संख्या के बीच अंतर को एन्कोडिंग करने के बारे में सोचा, क्योंकि यह छोटा होगा और अपेक्षाकृत संगत होना चाहिए, लेकिन समाधान भी सबसे खराब स्थिति को समायोजित करने में सक्षम होना चाहिए। हमारे पास 100000 नंबरों की एक जगह है जिसमें केवल 1000 नंबर हैं। पूरी तरह से एक समान फोन बुक में, प्रत्येक संख्या पिछले संख्या से 100 से अधिक होगी:

55555-12 3 45
55555-12 4 45
55555-12 5 45

यदि ऐसा होता, तो संख्याओं के बीच अंतर को सांकेतिक रूप से अंकित करने के लिए शून्य भंडारण की आवश्यकता होती, क्योंकि यह एक ज्ञात स्थिरांक है। दुर्भाग्य से, संख्याएं 100 के आदर्श चरणों से भिन्न हो सकती हैं। मैं 100 के आदर्श वेतन वृद्धि से अंतर को सांकेतिक शब्दों में बदलना होगा, ताकि यदि दो आसन्न संख्याएं 103 से भिन्न हों, तो मैं संख्या 3 को सांकेतिक शब्दों में बदलना चाहूंगा और यदि दो आसन्न संख्याएं 92 से भिन्न हैं, तो मैं एनकोड करना होगा -8। मैं 100 " विचरण " के एक आदर्श वेतन वृद्धि से डेल्टा को बुलाता हूं ।

विचरण -99 (यानी दो लगातार संख्या) से लेकर 99000 तक हो सकता है (संपूर्ण फोनबुक में 00000 नंबर ... 00999 और एक अतिरिक्त दूर-दूर की संख्या 99999 है), जो 99100 संभावित मूल्यों की एक सीमा है।

यदि मैं बड़े अंतरों (जैसे प्रोटोजोफ ) का सामना करूं तो सबसे आम अंतरों को एनकोड करने और भंडारण का विस्तार करने के लिए एक न्यूनतम भंडारण आवंटित करना चाहता हूं।varint ) का । मैं सात बिट्स, छह भंडारण के लिए और अंत में एक अतिरिक्त फ्लैग बिट का उपयोग करने के लिए इंगित करता हूं कि यह विचरण वर्तमान एक के बाद एक अतिरिक्त चंक के साथ संग्रहीत किया गया है, अधिकतम तीन चंक्स तक (जो अधिकतम प्रदान करेगा 3 * 6 = 18 बिट्स स्टोरेज, जो कि 262144 संभावित मान हैं, जो संभावित वेरिएंस (99100) की संख्या से अधिक हैं। एक उठाए गए झंडे का अनुसरण करने वाले प्रत्येक अतिरिक्त चंक में उच्च महत्व के बिट्स होते हैं, इसलिए पहला चंक हमेशा बिट्स 0- होता है। 5, वैकल्पिक दूसरी विखंडू में 6-11 बिट्स हैं, और वैकल्पिक तीसरे चंक में बिट्स 12-17 हैं।

एक एकल चंक भंडारण के छह बिट्स प्रदान करता है जो 64 मूल्यों को समायोजित कर सकता है। मैं उस सिंगल चंक (यानी -32 से +31 तक के वेरिएंट) में फिट होने के लिए 64 सबसे छोटे वेरिएंट को मैप करना चाहता हूं, इसलिए मैं ProtoBuf ZigZag एन्कोडिंग का उपयोग करूँगा, -99 के वेरिएंट से +98 तक (क्योंकि कोई ज़रूरत नहीं है) -99 से परे एक नकारात्मक विचरण के लिए), जिस बिंदु पर मैं नियमित एन्कोडिंग पर जाऊंगा, 98 से ऑफसेट:  

विचरण | एन्कोड किया गया मान
----------- + ----------------
    0 | 0
   -1 | 1
    1 | 2
   -2 | 3
    2 | 4
   -3 | 5
    3 | 6
   ... | ...
  -31 | 61
   31 | 62
  -32 | 63
----------- | --------------- 6 बिट्स
   32 | 64
  -33 | 65
   33 | 66
   ... | ...
  -98 | 195
   98 | 196
  -99 | 197
----------- | --------------- जिगजैग का अंत
   100 | 198
   101 | 199
   ... | ...
  3996 | 4094
  3997 | 4095
----------- | --------------- १२ बिट्स
  3998 | 4096
  3999 | 4097
   ... | ...
 262045 | 262,143
----------- | --------------- १। बिट्स

अतिरिक्त चंक को इंगित करने के लिए झंडे सहित बिटियन के रूप में कैसे भिन्न होंगे, इसके कुछ उदाहरण:

विचरण | एन्कोडेड बिट्स
----------- + ----------------
     0 | 000000 ०
     5 | 001010 0
    -8 | ००११११ ०
   -32 | ११११११ ०
    32 | 000000 1 000001 0
   -99 | 000101 1 000011 0
   177 | 010011 1 000100 0
 14444 | 001110 1 100011 1 000011 0

इसलिए नमूना फोन बुक के पहले तीन नंबर बिट्स की एक धारा के रूप में इनकोड किए जाएंगे:

BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0
PH # 55555-12345 55555-12448 55555-12491
पीओएस 1 2 3

सबसे अच्छी स्थिति , फोन बुक कुछ हद तक समान रूप से वितरित की जाती है और ऐसे दो फोन नंबर नहीं होते हैं, जिनमें 32 से अधिक का विचरण हो, इसलिए यह कुल संख्या के लिए 7 बिट प्रति प्लस और 32 बिट्स का उपयोग करेगा, जो कि कुल संख्या 32 + 7 * 999 के लिए होगा। = 7025 बिट्स
एक मिश्रित परिदृश्य , जहां 800 फोन नंबरों का विचरण एक चंक (800 * 7 = 5600) के भीतर फिट होता है, 180 नंबर दो विखंडू में फिट होते हैं (180 * 2 * 7 = 2520) और 19 नंबर तीन विखंडू में फिट होते हैं (20 * 3) * 7 = 399), प्रारंभिक 32 बिट्स, 8551 बिट्स योग ।
सबसे खराब स्थिति , 25 संख्याएँ तीन विखंडू में फिट होती हैं (25 * 3 * 7 = 525 बिट्स) और शेष 974 संख्याएँ दो विखंडू (974 * 2 * 7 = 13636 बिट्स) में फिट होती हैं, साथ ही एक ग्रैंड के लिए पहली संख्या के लिए 32 बिट्स कुल14193 बिट्स

   एन्कोडेड नंबरों की राशि |
 1-चंक | 2-विखंडू | 3-विखंडू | कुल बिट्स
--------- + ---------- + ---------- + ------------
   999 | 0 | 0 | 7025
   800 | 180 | 19 | 8551
    0 | 974 | 25 | 14,193

मैं चार अतिरिक्त अनुकूलन देख सकता हूं जो आवश्यक स्थान को और कम करने के लिए किया जा सकता है:

  1. तीसरे चंक को पूरे सात बिट्स की जरूरत नहीं है, यह सिर्फ पांच बिट्स और बिना फ्लैग बिट के हो सकता है।
  2. प्रत्येक चंक के लिए सर्वोत्तम आकारों की गणना करने के लिए संख्याओं का एक प्रारंभिक पास हो सकता है। हो सकता है कि एक निश्चित फोनबुक के लिए, यह सबसे अच्छा होगा कि पहले चंक में 5 + 1 बिट्स हों, दूसरा 7 + 1 और तीसरा 5 + 1 हो। यह आगे आकार को कम से कम 6 * 999 + 32 = 6026 बिट्स, प्लस तीन बिट्स के दो सेटों को 1 और 2 के आकार को संग्रहीत करने के लिए करेगा (कुल मिलाकर 3 बिट्स का आकार शेष 16 बिट्स के लिए शेष है) 6032 बिट्स की!
  3. वही प्रारंभिक पास डिफ़ॉल्ट 100 की तुलना में बेहतर प्रत्याशित वृद्धि की गणना कर सकता है। हो सकता है कि 55555-50000 से शुरू होने वाली फोन बुक हो, और इसलिए इसकी आधी संख्या सीमा हो, इसलिए अपेक्षित वेतन वृद्धि 50 होनी चाहिए। या हो सकता है कि कोई गैर-रैखिक हो वितरण (मानक विचलन शायद) और कुछ अन्य इष्टतम अपेक्षित वेतन वृद्धि का उपयोग किया जा सकता है। यह विशिष्ट विचरण को कम करेगा और उपयोग करने के लिए एक छोटा सा पहला हिस्सा भी अनुमति दे सकता है।
  4. फोन पास को विभाजित करने की अनुमति देने के लिए पहले पास में आगे का विश्लेषण किया जा सकता है, प्रत्येक विभाजन के पास अपनी अपेक्षित वृद्धि और चंक आकार के अनुकूलन होते हैं। यह फोन बुक के कुछ अत्यधिक समरूप भागों के लिए एक छोटे से पहले चंक आकार की अनुमति देता है (भस्म बिट्स की संख्या को कम करता है) और गैर-समान भागों के लिए बड़ा हिस्सा आकार (निरंतरता झंडे पर व्यर्थ बिट्स की संख्या को कम करना)।

0

असली सवाल पाँच-अंकीय फ़ोन नंबर संग्रहीत करने में से एक है।

चाल यह है कि आपको 0..99,999 से संख्या की सीमा को स्टोर करने के लिए 17 बिट्स की आवश्यकता होगी। लेकिन पारंपरिक 8-बाइट शब्द सीमाओं पर 17-बिट्स संग्रहीत करना एक परेशानी है। इसलिए वे पूछ रहे हैं कि क्या आप 32-बिट पूर्णांक का उपयोग न करके 4k से कम में कर सकते हैं।

प्रश्न: क्या सभी संख्या संयोजन संभव हैं?

टेलीफोन प्रणाली की प्रकृति के कारण, 65k से कम संभव संयोजन हो सकते हैं। मैं मानूंगा कि हां क्योंकि हम फोन नंबर में बाद के पांच पदों के बारे में बात कर रहे हैं, जैसा कि क्षेत्र कोड या विनिमय उपसर्गों के विपरीत है।

प्रश्न: क्या यह सूची स्थिर होगी या इसे अपडेट का समर्थन करने की आवश्यकता होगी?

यदि यह स्थिर है , तो जब डेटाबेस को पॉप्युलेट करने का समय आता है, तो अंकों की संख्या <50,000 और अंकों की संख्या = 50,000 की गणना करें। की दो सरणियों का आवंटन करेंuint16उपयुक्त लंबाई के : पूर्णांक के नीचे 50,000 और उच्च सेट के लिए एक। जब पूर्णांक में पूर्णांक बनाते हैं, तो 50,000 घटाएं और जब उस सरणी से पूर्णांक पढ़ते हैं, तो 50,000 जोड़ें। अब आपने अपने 1,000 पूर्णांकों को 2,000 8-बाइट शब्दों में संग्रहीत कर लिया है।

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

यदि यह गतिशील है , तो 1000 या तो एक सरणी आवंटित करें uint16, और क्रमबद्ध क्रम में संख्याएं जोड़ें। पहले बाइट को 50,001 पर सेट करें, और दूसरे बाइट को Null या 65,000 जैसे एक उपयुक्त शून्य मान पर सेट करें। जब आप संख्याओं को संग्रहीत करते हैं, तो उन्हें क्रमबद्ध क्रम में संग्रहीत करें। यदि कोई संख्या 50,001 से कम है तो उसे 50,001 मार्कर से पहले संग्रहित करें । यदि कोई संख्या 50,001 या अधिक है, तो इसे 50,001 मार्कर के बाद स्टोर करें , लेकिन संग्रहीत मूल्य से 50,000 घटाएं।

आपकी सरणी कुछ इस तरह दिखाई देगी:

00001 = 00001
12345 = 12345
50001 = reserved
00001 = 50001
12345 = 62345
65000 = end-of-list

इसलिए, जब आप फोनबुक में एक नंबर देखते हैं, तो आप सरणी को पार कर लेंगे और यदि आप 50,001 मूल्य पर हिट कर चुके हैं, तो आप अपने सरणी मूल्यों में 50,000 जोड़ना शुरू करेंगे।

यह आवेषण बहुत महंगा बनाता है, लेकिन लुकअप आसान है, और आप भंडारण पर 2k से अधिक खर्च नहीं करने जा रहे हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.