कोड हफमैन!


13

वरना वह आवेश करेगा और अपना घर फूंक देगा!

वह पूरी तरह अप्रासंगिक था। यह चुनौती वास्तव में हफमैन कोडिंग के बारे में है । इसका सार यह है कि किसी दिए गए पाठ में वर्णों की आवृत्ति का उपयोग उसके प्रतिनिधित्व को कम करने के लिए किया जाता है। दूसरे शब्दों में, मान लें कि हमारी वर्णमाला अंतरिक्ष और अंतरिक्ष के aमाध्यम से zहै। वह 27 अक्षर का है। उनमें से प्रत्येक को केवल 5 बिट्स में विशिष्ट रूप से एन्कोड किया जा सकता है क्योंकि 5 बिट्स में 32 अक्षरों के लिए पर्याप्त जगह है। हालाँकि, कई स्थितियों में (जैसे सामान्य रूप से अंग्रेजी, या भाषाएं), कुछ पात्र दूसरों की तुलना में अधिक होते हैं। हम अधिक लगातार पात्रों के लिए कम बिट्स का उपयोग कर सकते हैं और (शायद) कम लगातार पात्रों के लिए अधिक बिट्स का। सही किया, बिट्स की संख्या में समग्र बचत है और मूल पाठ अभी भी विशिष्ट रूप से खंगाला जा सकता है।

आइए एक उदाहरण के रूप में "यह प्रश्न हफ़मैन कोडिंग के बारे में है"। यह पाठ 37 वर्ण लंबा है, जो सामान्य रूप से 37 * 8 = 296 बिट्स होगा, हालांकि यदि हम प्रत्येक वर्ण के लिए केवल 5 बिट्स का उपयोग करते हैं तो केवल 37 * 5 = 185 बिट्स । यह याद रखना।

पाठ में प्रत्येक वर्ण और उनकी आवृत्तियों की तालिका (सॉर्टा) है, जो कम से कम बार (जहां _ एक स्थान के लिए खड़ा है) से क्रमबद्ध है:

_ 5
i 4
n 3
o 3
s 3
t 3
u 3
a 2
f 2
h 2
b 1
c 1
d 1
e 1
g 1
m 1
q 1

एक संबद्ध इष्टतम कोडिंग हो सकती है:

_ 101
i 011
n 1100
o 1101
s 1110
t 1111
u 001
a 10011
f 0001
h 0101
b 00000
c 00001
d 01000
e 01001
g 10000
m 10001
q 10010

यह तुरंत स्पष्ट होना चाहिए कि यह हर चरित्र के लिए केवल 5 बिट्स का उपयोग करने से बेहतर एन्कोडिंग होगा। आइए जानें कि कितना बेहतर है, हालांकि!

185 के साथ तुलना में 145 बिट्स ! यह 40 बिट की बचत है, या सिर्फ 20% से अधिक है! (यह, निश्चित रूप से, यह मानते हुए कि संरचना के बारे में जानकारी डिकोडिंग के लिए उपलब्ध है।) यह कोडिंग इष्टतम है क्योंकि किसी भी चरित्र के प्रतिनिधित्व को बदलकर और अधिक बिट्स नहीं गिराए जा सकते।

काम

  • एक पैरामीटर के साथ एक प्रोग्राम या फ़ंक्शन लिखें ...
  • एसटीडीआईएन (या समतुल्य) या एकल तर्क के रूप में इनपुट लेता है।
  • एक इष्टतम हफमैन कोडिंग को आउटपुट के रूप में आवृत्ति के अनुसार क्रमबद्ध किया जाता है (एक आवृत्ति वर्ग के भीतर क्रम कोई फर्क नहीं पड़ता)।
  • आप मान सकते हैं कि इनपुट में वर्ण ASCII सीमा 32..126और एक नई रेखा तक ही सीमित हैं ।
  • आप मान सकते हैं कि इनपुट 10,000 वर्णों से अधिक नहीं है (आदर्श रूप में, सिद्धांत रूप में, इनपुट अनबाउंड होना चाहिए)।
  • आपका कोड यथोचित तेजी से समाप्त होना चाहिए। ऊपर दिए गए उदाहरण में एक मिनट या उससे अधिक नहीं लेना चाहिए। (यह क्रूर बल से शासन करने का इरादा है।)
  • स्कोरिंग बाइट्स में है।

उदाहरण

x
---
x 0

xxxxxxxxx
---
x 0

xxxxxxxxy
---
x 0
y 1 (these may be swapped)

xxxxxyyyz
---
x 0
y 10
z 11

uuvvwwxxyyzz
---   (or) 
u 000      000
v 001      001
w 100      010
x 101      011
y 01       10
z 11       11

this question is about huffman coding
---
  101
i 011
n 1100
o 1101
s 1110
t 1111
u 001
a 10011
f 0001
h 0101
b 00000
c 00001
d 01000
e 01001
g 10000
m 10001
q 10010

हैप्पी कोडिंग!


ध्यान दें कि यह समान प्रश्न बारीकी से संबंधित है, यहां तक ​​कि इस बात के लिए कि यह एक डुप्लिकेट है। हालांकि, मेटा पर अब तक आम सहमति यह है कि पुराने को इस एक की नकल माना जाना चाहिए।


1
मैं आपके नोट से असहमत हूं: यह वही प्रश्न है जो मौजूदा उत्तरों के लिए आउटपुट स्वरूप के एक सरल परिवर्तन की आवश्यकता है, और इस प्रश्न के किसी भी जवाब को स्वचालित रूप से पिछले प्रश्न का उत्तर है।
पीटर टेलर

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

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

के अपने उदाहरण में this question is about huffman coding, मैं बिट्स की संख्या गणना हो 145 , नहीं 136.
TFeld

1
मैं वास्तव में चम्मच में इस चुनौती को पूरा करने की कोशिश कर रहा था , लेकिन 2 घंटे की दिमागी कसरत के बाद मैंने फैसला किया कि इसे छोड़ देना सबसे अच्छा होगा ...
बैसड्रॉफ़ कम्बरबुबवबब

जवाबों:


2

पायथ, 53 बाइट्स

jo_/zhNee.WtHa>JohNZ2+shKC<J2]s.b+RYNeKU2m,/zd]+d\ {z

प्रदर्शन

यहां एक संस्करण है जो आंतरिक स्थिति दिखाता है, जिससे आप एन्कोडिंग का निर्माण देख सकते हैं:

jo_/zhNee.WtHvp+`a>JohNZ2+shKC<J2]s.b+RYNeKU2bm,/zd]+d\ {z

प्रदर्शन

एक स्पष्ट तस्वीर के लिए व्यापक लाइनों वाले वातावरण में आउटपुट की प्रतिलिपि बनाएँ।


4

पायथन 2, 299 बाइट्स

यहाँ एक उत्तर में मेरा प्रयास है।

हफ़मैन कोड दिए गए उदाहरणों से अलग हैं, लेकिन फिर भी इष्टतम होना चाहिए।

i=raw_input();m=n=[(c,i.count(c))for c in set(i)]
while n[1:]:n.sort(key=lambda x:(x[1]));(a,b),(c,d)=n[:2];n=[((a,c),b+d)]+n[2:]
n=n[0][0]
r=[]
def a(b,s):
 if b[1:]:a(b[0],s+'0');a(b[1],s+'1')
 else:r.append(b+(s if s[1:]else s+'0'))
a(n,' ')
for y in sorted(r,key=lambda x:-dict(m)[x[0]]):print y

2

मतलाब, 116 बाइट्स

tabulateएक आवृत्ति तालिका बनाता है। huffmandictप्रत्येक प्रतीक के लिए प्रतीकों और संभावनाओं की एक सूची लेता है, और कोड की गणना करता है।

t=tabulate(input('')');
d=huffmandict(t(:,1),cell2mat(t(:,3))/100);
for i=1:size(d,1);disp([d{i,1},' ',d{i,2}+48]);end

2

माणिक, 189 180 बाइट्स

कार्य प्रगति पर है।

->s{m=s.chars.uniq.map{|c|[c,s.count(c)]}
while m[1]
(a,x),(b,y),*m=m.sort_by &:last
m<<[[a,b],x+y]
end
h={}
f=->q="",c{Array===c&&f[q+?0,c[0]]&&f[q+?1,c[1]]||h[c]=q}
f[m[0][0]]
h}

यह एक अनाम कार्य है; उदाहरण के लिए f, इसे किसी चीज़ को असाइन करें और इसके साथ कॉल करें

f["some test string"]`

जो इस तरह से एक हैश लौटाता है:

{"t"=>"00", "g"=>"0100", "o"=>"0101", " "=>"011", "e"=>"100", "n"=>"1010", "i"=>"1011", "m"=>"1100", "r"=>"1101", "s"=>"111"}

1

हास्केल, 227 बाइट्स

import Data.List
s=sortOn.(length.)
f x|[c]<-nub x=[(c,"0")]|1<2=g[(a,[(a!!0,"")])|a<-group$sort x]
g=h.s fst
h[x]=snd x
h((a,b):(c,d):e)=g$(a++c,map('0'#)b++map('1'#)d):e
n#(a,b)=(a,n:b)
p=unlines.map(\(a,b)->a:" "++b).s snd.f

उपयोग उदाहरण:

*Main> putStr $ p "this question is about huffman coding"
u 000
i 011
  101
a 0010
f 0011
h 1000
s 1100
t 1101
n 1110
o 1111
d 01000
e 01001
b 01010
c 01011
q 10010
g 100110
m 100111

यह काम किस प्रकार करता है:

pकॉल fजो हफ़मैन तालिका को (चरित्र, एन्कोडिंग) की सूची के रूप में बनाता है, जैसे [ ('a',"0"), ('b',"1") ], एन्कोडिंग की लंबाई के आधार पर तालिका को छाँटते हैं, आउटपुट के लिए प्रत्येक जोड़ी को प्रारूपित करते हैं और नए-नए के साथ जुड़ते हैं।

fपहले एकल पत्र मामले की जाँच करता है और संबंधित तालिका लौटाता है। अन्यथा यह इनपुट स्ट्रिंग और समूहों को समान वर्णों के अनुक्रमों (जैसे "ababa"-> ["aaa","bb"]) से अलग करता है और उन्हें जोड़े में मैप करता है (sequence , [(char, "")]), (-> [ ("aaa", [('a',"")]), ("bb", [('b', "")])]पहला तत्व आवृत्ति का ट्रैक रखने के लिए उपयोग किया जाता है, दूसरा तत्व किसी वर्ण के जोड़े की सूची है। और यह एन्कोडिंग है (जो शुरू में खाली है)। ये रूप से उम्मीद सब एक तत्व Huffman टेबल हैं pऔर से जोड़ दिया जाता है gऔर h

gपहले तत्व की लंबाई यानी आवृत्ति और कॉल पर जोड़े की सूची को क्रमबद्ध करें hhपहले दो तत्वों के हफ़मैन तालिकाओं को जोड़ती है, आवृत्तियों को समाप्‍त करके और 0( क 1) पहले (दूसरे) तालिका के हर तत्व के सामने रखते हैं। दोनों तालिकाओं को मिलाएं। gफिर से कॉल करें, तब रुकें जब एक भी तत्व शेष हो, आवृत्ति भाग को फेंक दें और पूर्ण हफमैन तालिका वापस करें।


1

के (ngn / k) , 78 बाइट्स

{h::0#'x;(#1_){{h[x],:!2;y,,,/x}.0 2_x@<#'x}/.=x;(?,/'x,'" ",'|'$h)(?x)?>#'=x}

इसे ऑनलाइन आज़माएं!

मुद्रण के लिए तार की एक सूची देता है

h::0#'xप्रत्येक वर्ण के लिए एक खाली सूची बनाता है (तकनीकी रूप से, यह प्रत्येक वर्ण को लंबाई 0 पर आकार देता है)। हम वहां उलटे हफ़मैन कोड स्टोर करेंगे। हम वैश्विक बनाने ::के :लिए असाइनमेंट के बजाय उपयोग करते हैं , hइसलिए यह उप-कार्यों में दिखाई देता है।

.=x सूचियों की एक सूची है - चरित्र मूल्य द्वारा समूहीकृत स्ट्रिंग के सूचकांक

(#1_) एक ऐसा फ़ंक्शन है जो तर्क की लंबाई के सत्य होने पर लौटा देता है> 1 (तकनीकी रूप से "1 बूंद की लंबाई ...")

(#1_){... का }/अर्थ है: जबकि तर्क में लंबाई> 1 है, घुंघराले-ब्रेस फ़ंक्शन को लागू करना जारी रखें

x@<#'x लंबाई के अनुसार तर्क को क्रमबद्ध करें

0 2_ इसे 2-तत्व के सिर और एक पूंछ में काट लें

{h[x],:!2;y,,,/x}hसिर में निहित सूचकांकों में 0 और 1 जोड़कर अद्यतन ; एकल तत्व के रूप में सिर के साथ पूंछ लौटाएं

(?,/'x,'" ",'|'$h)(?x)?>#'=xप्रत्येक में से h, क्रमबद्ध, अद्वितीय, इसी वर्णों को पूर्ववत करें , और अच्छी तरह से प्रारूपित करें


0

जावास्क्रिप्ट (ईएस 6) 279

मूलतः, विकिपीडिया से मूल एल्गोरिथ्म। मैं शायद बेहतर कर सकता हूं।

f=s=>{for(n=[...new Set(s)].map(c=>({c:c,f:[...s].filter(x=>x==c).length}));n[1];n.push({l:a=n.pop(),r:b=n.pop(),f:a.f+b.f,c:a.c+b.c}))n.sort((a,b)=>b.f-a.f);t=(n,b)=>(n.b=b,n.r)?(t(n.l,b+0),t(n.r,b+1)):o.push(n);t(n[0],'',o=[]);return o.sort((a,b)=>b.f-a.f).map(x=>x.c+' '+x.b)}

नीचे स्निपेट के अंदर अधिक पठनीय

f=s=>{
  for(n=[...new Set(s)].map(c=>({c:c,f:[...s].filter(x=>x==c).length}));
      n[1];
      n.push({l:a=n.pop(),r:b=n.pop(),f:a.f+b.f,c:a.c+b.c}))
    n.sort((a,b)=>b.f-a.f);
  t=(n,b)=>(n.b=b,n.r)?(t(n.l,b+0),t(n.r,b+1)):o.push(n);
  t(n[0],'',o=[]);
  return o.sort((a,b)=>b.f-a.f).map(x=>x.c+' '+x.b)
}

//TEST
console.log=x=>O.innerHTML+=x+'\n'

test=['xxxxxxxxy','uuvvwwxxyyzz','this question is about huffman coding']
.forEach(t=>console.log(t+'\n'+f(t).join`\n`+'\n'))
<pre id=O></pre>

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