- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现 Haskell Data.Vector.*
错过 C++ std::vector::push_back
的功能。有grow
/unsafeGrow
,但它们似乎具有 O(n) 复杂度。
有没有办法在一个元素的 O(1) 摊销时间内增长向量?
最佳答案
不,Data.Vector
中真的没有这样的设施。 .使用 MutableArray
从头开始实现这一点并不难喜欢 Data.Vector.Mutable
确实(见下面我的实现),但有一些明显的缺点。特别是,它的所有操作最终都发生在一些状态上下文中,通常是 ST
。或 IO
.这有以下缺点
vector
这样的库使用一个非常聪明的东西,叫做 fusion优化中间分配。这种事情在状态上下文中是不可能的。 ST
我什至不能有两个线程和 IO
我将在所有地方都有比赛条件。这里令人讨厌的一点是,任何共享都必须在 IO
中进行。 . containers
GHC 附带的一些替代方案包括:
push_back
,也许你只想要一个堆栈(一个普通的旧 [a]
)。 push_back
比查找, Data.Sequence
给你O(1)
附加到任一端和 O(log n)
抬头。 Data.IntMap
非常优化。即使这些操作的理论成本是 O(log n)
,你需要一个相当大的IntMap
开始感受这些成本。 vector
的东西
data-default
和
primitive
)。
newVector
。 - 其他一切都“修改”现有向量。由于pushBack
不返回新的 GrowVector
,它必须修改现有的(包括它的长度和/或容量),所以length
和 capacity
必须是“指针”。反过来,这意味着即使获得 length
是一元操作。 vector
不会太困难小号 data family
approach - 这只是乏味1。 module GrowVector (
GrowVector, newEmpty, size, read, write, pushBack, popBack
) where
import Data.Primitive.Array
import Data.Primitive.MutVar
import Data.Default
import Control.Monad
import Control.Monad.Primitive (PrimState, PrimMonad)
import Prelude hiding (length, read)
data GrowVector s a = GrowVector
{ underlying :: MutVar s (MutableArray s a) -- ^ underlying array
, length :: MutVar s Int -- ^ perceived length of vector
, capacity :: MutVar s Int -- ^ actual capacity
}
type GrowVectorIO = GrowVector (PrimState IO)
-- | Make a new empty vector with the given capacity. O(n)
newEmpty :: (Default a, PrimMonad m) => Int -> m (GrowVector (PrimState m) a)
newEmpty cap = do
arr <- newArray cap def
GrowVector <$> newMutVar arr <*> newMutVar 0 <*> newMutVar cap
-- | Read an element in the vector (unchecked). O(1)
read :: PrimMonad m => GrowVector (PrimState m) a -> Int -> m a
g `read` i = do arr <- readMutVar (underlying g); arr `readArray` i
-- | Find the size of the vector. O(1)
size :: PrimMonad m => GrowVector (PrimState m) a -> m Int
size g = readMutVar (length g)
-- | Double the vector capacity. O(n)
resize :: (Default a, PrimMonad m) => GrowVector (PrimState m) a -> m ()
resize g = do
curCap <- readMutVar (capacity g) -- read current capacity
curArr <- readMutVar (underlying g) -- read current array
curLen <- readMutVar (length g) -- read current length
newArr <- newArray (2 * curCap) def -- allocate a new array twice as big
copyMutableArray newArr 1 curArr 1 curLen -- copy the old array over
underlying g `writeMutVar` newArr -- use the new array in the vector
capacity g `modifyMutVar'` (*2) -- update the capacity in the vector
-- | Write an element to the array (unchecked). O(1)
write :: PrimMonad m => GrowVector (PrimState m) a -> Int -> a -> m ()
write g i x = do arr <- readMutVar (underlying g); writeArray arr i x
-- | Pop an element of the vector, mutating it (unchecked). O(1)
popBack :: PrimMonad m => GrowVector (PrimState m) a -> m a
popBack g = do
s <- size g;
x <- g `read` (s - 1)
length g `modifyMutVar'` (+ negate 1)
pure x
-- | Push an element. (Amortized) O(1)
pushBack :: (Default a, PrimMonad m) => GrowVector (PrimState m) a -> a -> m ()
pushBack g x = do
s <- readMutVar (length g) -- read current size
c <- readMutVar (capacity g) -- read current capacity
when (s+1 == c) (resize g) -- if need be, resize
write g (s+1) x -- write to the back of the array
length g `modifyMutVar'` (+1) -- increase te length
grow
的当前语义
I think the intended semantics are that it may do a realloc, but not guaranteed to, and all the current implementations do the simpler copying semantics because for on heap allocations the cost should be roughly the same.
grow
当您想要一个增加大小的新可变向量时,从旧向量的元素开始(不再关心旧向量)。这非常有用 - 例如可以实现
GrowVector
使用
MVector
和
grow
.
data instance
将您的类型“扩展”为固定数量的未装箱数组(或其他未装箱向量)。这是
data family
的重点- 允许一个类型的不同实例具有完全不同的运行时表示,并且也是可扩展的(如果需要,您可以添加自己的
data instance
)。
关于Haskell 向量 C++ push_back 类比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31598273/
这个问题在这里已经有了答案: Passing by value vs const & and && overloads (3 个答案) 关闭 8 年前。 为什么push_back的函数签名如下? v
代码如下: std::vector s; s.push_back(~Dword(0)); 什么是~Dword?它是如何工作的? 最佳答案 Dword 这里是一个数字类型(可能是 DWORD 的类型别名
我正在测试 C++ 中推回对象与推回对象指针到 Vector 之间的性能差异。 我在 Stackoverflow 和其他文章中读到,您应该避免向后推指针,除非您必须这样做... 但是,我意识到推回指针
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我有一个很大的 .txt 文件,需要加载并存储在 vector 中。该文件大小约为 5MB,500 000 行,每行约 10-20 个字符,以 '\n' 分隔。我正在使用以下示例代码对读取整个文件所需
这个问题在这里已经有了答案: What is object slicing? (18 个答案) 关闭 9 年前。 我有这两个类: class A { public: A(); vir
在我当前的代码中,我想将新的 DrawObjects 插入到我创建的 vector 中, std::vector 对象; 有什么区别: objects.push_back(DrawObject(nam
我将 Cygwin 与 GCC 一起使用,最终我想将字 rune 件读入字符 vector ,并使用此代码 #include #include #include using namespace
以下代码创建一个临时对象 A 并将其推送到一个 vector 中。 在 push_back 期间删除复制构造函数并调用移动构造函数。我不确定这段代码的设计是否正确,肯定存在内存泄漏。 #include
我知道push_back可以抛出bad_alloc异常,并且如果没有try catch block ,则调用析构函数是不正确的。如果有任何push_back抛出并且它不在try catch block
正如 Scott Meyers 所指出的(http://channel9.msdn.com/Events/GoingNative/2013/An-Effective-Cpp11-14-Sampler
我正在写一个 push_back将临时容器添加到另一个容器的函数。 并且它应该在使用 push_back 之前调整或保留容器(如果两者都可用,它应该更喜欢保留而不是调整大小) 当前代码是: names
这个问题在这里已经有了答案: Create an array when the size is a variable not a constant (2 个答案) 关闭 3 年前。 我认为我在代码中
代码: // test2.cpp #include #include struct test_class { test_class() = default; test_class(
我试图在 forloop 的 vector 中推回一个 const char*。 char_temp 是一个名为 segment 的结构,而 chars_temp 是一个结构 vector 。请参阅下
在 C++ 入门书第 (3) 章中,有以下 for 循环将 vector 中的元素重置为零。 vector ivec; //UPDATE: vector declaration for (vector
class A { public: A():a(0) {} A(int x):a(x) { coutve
我正在尝试使用 Visual Leak Detector 查找内存泄漏。它告诉我 m_neighbors.push_back(ent);导致泄漏。 (简短调用堆栈 = NeighborCalculat
我们正在制作一个包含棋盘游戏信息(名称、年份、分数)的列表。我们从 .csv 文件中扫描信息,根据该信息创建一个结构,然后将该结构添加到列表中。我们一直这样做,直到文档阅读完毕。问题是列表的 push
以下代码是将“非重叠”的 TablePath 从 vector v 移动到 vector u。我在“u.push_back(*it1);”行遇到段错误。我没有复制对象(而是只复制对象的指针)所以我相信
我是一名优秀的程序员,十分优秀!