हम इसे एक संरचना बनाकर बहुत कुशलता से कर सकते हैं जिसे हम उप-रैखिक समय में अनुक्रमित कर सकते हैं।
लेकिन पहले,
{-# LANGUAGE BangPatterns #-}
import Data.Function (fix)
चलो परिभाषित करते हैं f
, लेकिन इसे सीधे कॉल करने के बजाय 'खुली पुनरावृत्ति' का उपयोग करते हैं।
f :: (Int -> Int) -> Int -> Int
f mf 0 = 0
f mf n = max n $ mf (n `div` 2) +
mf (n `div` 3) +
mf (n `div` 4)
आप f
का उपयोग करके एक unmemoized प्राप्त कर सकते हैंfix f
यह आपको यह परखने देगा कि f
छोटे मूल्यों के लिए आपका क्या मतलब हैf
कॉलिंग के , उदाहरण के लिए:fix f 123 = 144
हम इसे परिभाषित करके याद कर सकते हैं:
f_list :: [Int]
f_list = map (f faster_f) [0..]
faster_f :: Int -> Int
faster_f n = f_list !! n
जो कि अच्छा प्रदर्शन करता है, और बदलता है कि O (n ^ 3) लेने जा रहा है है कि मध्यवर्ती परिणामों को याद रखने वाली चीज़ के साथ समय ।
लेकिन यह अभी भी रैखिक समय लेता है सूचकांक के लिए बस के लिए ज्ञापन जवाब खोजने के लिए mf
। इसका मतलब है कि परिणाम:
*Main Data.List> faster_f 123801
248604
सहनीय हैं, लेकिन परिणाम इससे बेहतर नहीं है। हम बेहतर कर सकते हैं!
सबसे पहले, एक अनंत पेड़ को परिभाषित करते हैं:
data Tree a = Tree (Tree a) a (Tree a)
instance Functor Tree where
fmap f (Tree l m r) = Tree (fmap f l) (f m) (fmap f r)
और फिर हम इसमें अनुक्रमित करने का एक तरीका परिभाषित करेंगे, इसलिए हम इसके बजाय O (लॉग एन) समय n
में सूचकांक के साथ एक नोड पा सकते हैं :
index :: Tree a -> Int -> a
index (Tree _ m _) 0 = m
index (Tree l _ r) n = case (n - 1) `divMod` 2 of
(q,0) -> index l q
(q,1) -> index r q
... और हमें प्राकृतिक संख्याओं से भरा एक पेड़ मिल सकता है जो सुविधाजनक हो ताकि हमें उन सूचकांकों के साथ इधर-उधर न भटकना पड़े:
nats :: Tree Int
nats = go 0 1
where
go !n !s = Tree (go l s') n (go r s')
where
l = n + s
r = l + s
s' = s * 2
चूंकि हम इंडेक्स कर सकते हैं, आप बस एक पेड़ को सूची में बदल सकते हैं:
toList :: Tree a -> [a]
toList as = map (index as) [0..]
आप जो सत्यापन करते हैं, toList nats
उसे सत्यापित करके आप अब तक के काम को देख सकते हैं[0..]
अभी,
f_tree :: Tree Int
f_tree = fmap (f fastest_f) nats
fastest_f :: Int -> Int
fastest_f = index f_tree
ऊपर दी गई सूची के साथ ही काम करता है, लेकिन प्रत्येक नोड को खोजने के लिए रैखिक समय लेने के बजाय, यह लघुगणक समय में पीछा कर सकता है।
परिणाम काफी तेज है:
*Main> fastest_f 12380192300
67652175206
*Main> fastest_f 12793129379123
120695231674999
वास्तव में यह तो बहुत तेजी से है कि आप के माध्यम से जाने के लिए और जगह ले सकता है Int
के साथ Integer
ऊपर और लगभग तुरंत हास्यास्पद बड़ा जवाब पाने
*Main> fastest_f' 1230891823091823018203123
93721573993600178112200489
*Main> fastest_f' 12308918230918230182031231231293810923
11097012733777002208302545289166620866358