Performance 统一随机索引的平均情况)。

Performance 统一随机索引的平均情况)。,performance,haskell,random,set,Performance,Haskell,Random,Set,从数据开始。Set模块有一个elemAt函数,该函数通过元素排序序列中的零基索引检索值。所以现在编写这个函数很简单 import Control.Monad.Random import Data.Set (Set) import qualified Data.Set as Set randElem :: (MonadRandom m, Ord a) -> Set a -> m (a, Set a) randElem xs = do n &

数据开始。Set
模块有一个
elemAt
函数,该函数通过元素排序序列中的零基索引检索值。所以现在编写这个函数很简单

import           Control.Monad.Random
import           Data.Set (Set)
import qualified Data.Set as Set

randElem :: (MonadRandom m, Ord a) -> Set a -> m (a, Set a)
randElem xs = do
  n <- getRandomR (0, Set.size xs - 1)
  return (Set.elemAt n xs, Set.deleteAt n xs)
import Control.Monad.Random
导入数据集(Set)
导入符合条件的数据。设置为集合
兰德兰::(莫纳德兰多姆,作战命令a)->设定a->m(a,设定a)
randElem xs=do

顺便说一句,这种情况更为复杂(∞), 因为随机生成器可能只拾取空的插槽。必须确保始终有足够的元素剩余。例如,如果删除了最高的元素,可以减少元素的数量。但是平均大小写复杂性O(log(n)):-)你是怎么得出这个数字的?@fuzzxl:仔细想想:-)更严重的是——如果没有删除,情况就很简单了。对于m次删除,需要平均时间
n/n-m
生成集合中包含的随机数,每次“未命中”的查找成本与最终“命中”相同。所以我们确实有
O(n/n-m*log(n))
n/n-m
变大时,它确实会变得无穷大,但是对于任何有界的孔与总大小的比率,对我来说都保持在O(logn)
集的全部要点是,它允许您快速判断元素是否是成员(记录时间)。这种方式不允许你这么做。相关的思考食物:为什么要投否决票?谢谢到目前为止,我认为这是满足提问者提供o(n)的要求的唯一解决方案(也就是说,我注意到了这个答案,它看起来确实与我想要的最接近。在看了代码之后,尽管杂乱无章,但它看起来确实是一个不错的实现。你可以将丑陋的if/then序列转化为警卫来清理。此外,你需要使用
==
进行平等性比较。但是代码背后的想法看起来不错;我认为这个想法最适合我的要求。这个randElem有一个不同的类型(需要数字元素),所以它不能解决一般的问题。而且,如果有关系的话,最坏的情况复杂性是O(n*log(n))是的,我对这些观点进行了评论。非正式地说,从集合类型的接口可以“清楚”地看出,唯一有效的方法是以某种形式按值搜索;而且,这本质上取决于集合元素的顺序类型。不幸的是,这看起来是大致最佳的方法。考虑到对
Data.Set内部的访问,您可以轻松地为集合实现O(logn)
elemAt
。它目前仅为地图定义,这感觉像是一种疏忽。对此有一个问题()和一些电子邮件讨论()。我认为它没有实现的原因是它过于依赖于当前的实现。目前这是对这个问题的最佳答案。它很简单,O(log n)并且不需要访问
集合
内部。
import Data.Set as Set
import System.Random (getStdGen, randomR, RandomGen)

randElem :: (RandomGen g) => Set a -> g -> (a, g)
randElem s g = (Set.toList s !! n, g')
    where (n, g') = randomR (0, Set.size s - 1) g

-- simple test drive
main = do g <- getStdGen
          print . fst $ randElem s g
    where s = Set.fromList [1,3,5,7,9]
import Data.Set as Set
import System.Random (getStdGen, randomR, RandomGen)

getNth (s, n) = if n = 0 then (Set.findMin s) else if n + 1 = Set.size s then Set.findMax s
    else if n < Set.size bott then getNth (bott, n) else if pres and Set.size bott = n then n
    else if pres then getNth (top, n - Set.size bott - 1) else getNth (top, n - Set.size)
    where mid = ((Set.findMax s) - (Set.findMin s)) /2 + (Set.findMin s)
          (bott, pres, top) = (splitMember mid s)

randElem s g = (getNth(s, n), g')
    where (n, g') = randomR (0, Set.size s - 1) g
import qualified Data.Vector 
import qualified Data.Set

newtype RandSet a = RandSet (V.Vector a)

randElem :: RandSet a -> RandomGen -> (a, RandomGen)
randElem (RandSet v) g
  | V.empty v = error "Cannot select from empty set" 
  | otherwise = 
    let (i,g') = randomR (0, V.length v - 1) g
    in (v ! i, g')

-- Of course you have to rebuild array on insertion/deletion which is O(n)
insert :: a -> RandSet a -> RandSet a
insert x = V.fromList . Set.toList . Set.insert x . Set.fromList . V.toList`
randomElems :: Set a -> RandomGen -> [a]
randomElems set = map (table !) . randomRs bounds where
    bounds = (1, size set)
    table  = listArray bounds (toList set)
import qualified Data.Map as M
import Data.Map(member, size, empty)
import System.Random

type Set a = M.Map a ()

insert :: (Ord a) => a -> Set a -> Set a
insert a = M.insert a ()

fromList :: Ord a => [a] -> Set a
fromList = M.fromList . flip zip (repeat ())

elemAt i = fst . M.elemAt i

randElem :: (RandomGen g) => Set a -> g -> (a, g)
randElem s g = (elemAt n s, g')
    where (n, g') = randomR (0, size s - 1) g
import           Control.Monad.Random
import           Data.Set (Set)
import qualified Data.Set as Set

randElem :: (MonadRandom m, Ord a) -> Set a -> m (a, Set a)
randElem xs = do
  n <- getRandomR (0, Set.size xs - 1)
  return (Set.elemAt n xs, Set.deleteAt n xs)