นี่เป็นปัญหาคลาสสิกที่ได้รับการกำทอนในปี 1986 เมื่อโดนัลด์คุทท์ใช้วิธีแก้ปัญหาอย่างรวดเร็วด้วยการลองแฮชในโปรแกรมยาว 8 หน้าเพื่อแสดงให้เห็นถึงเทคนิคการเขียนโปรแกรมของเขาในขณะที่ดั๊กแม็กอิลรอย สายการบินเดียวที่ไม่เร็ว แต่ได้งานเสร็จแล้ว:
tr -cs A-Za-z '\n' | tr A-Z a-z | sort | uniq -c | sort -rn | sed 10q
แน่นอนว่าทางออกของ McIlroy มีความซับซ้อนของเวลา O (N log N) โดยที่ N คือจำนวนคำทั้งหมด มีวิธีแก้ปัญหาที่เร็วกว่ามาก ตัวอย่างเช่น:
นี่คือการประยุกต์ใช้ C ++ ที่มีความซับซ้อนของเวลาที่ถูกผูกไว้ O ((N + k) บันทึก k) ซึ่งโดยทั่วไป - เกือบเป็นเชิงเส้น
ด้านล่างนี้เป็นการนำ Python ไปใช้อย่างรวดเร็วโดยใช้พจนานุกรมแฮชและฮีปที่มีความซับซ้อนของเวลา O (N + k บันทึก Q) โดยที่ Q คือคำที่ไม่ซ้ำกันจำนวนหนึ่ง:
import collections, re, sys
filename = sys.argv[1]
k = int(sys.argv[2]) if len(sys.argv)>2 else 10
text = open(filename).read()
counts = collections.Counter(re.findall('[a-z]+', text.lower()))
for i, w in counts.most_common(k):
print(i, w)
การเปรียบเทียบเวลา CPU (เป็นวินาที):
bible32 bible256
C++ (prefix tree + heap) 5.659 44.730
Python (Counter) 10.314 100.487
Sheharyar (AWK + sort) 30.864 251.301
McIlroy (tr + sort + uniq) 60.531 690.906
หมายเหตุ:
- bible32 คือการตัดแบ่งคัมภีร์ไบเบิลกับตัวเอง 32 ครั้ง (135 MB), bible256 - 256 ครั้งตามลำดับ (1.1 GB)
- การที่สคริปต์ไม่ทำงานช้าลงของ Python เกิดจากความจริงที่ว่ามันประมวลผลไฟล์ในหน่วยความจำอย่างสมบูรณ์ดังนั้นค่าโสหุ้ยจะเพิ่มขึ้นสำหรับไฟล์ขนาดใหญ่
- หากมีเครื่องมือ Unix ที่สามารถสร้างฮีปและเลือกองค์ประกอบจากด้านบนของฮีปโซลูชัน AWK สามารถสร้างความซับซ้อนของเวลาใกล้เชิงเส้นได้ในขณะนี้คือ O (N + Q log Q)