我正在尝试在Haskell中创建一个CycleSort,这是我的任务,但没有人让我明白如何使用Haskell,我已经多次尝试过,尝试从其他语言“翻译”代码,但它没有不行。我到处寻找它,但什么都没有。如果有人帮我解决这个问题,我会非常非常感激。 Java中有CycleSort的代码。
// Function sort the array using Cycle sort
public static void cycleSort(int arr[], int n)
{
// count number of memory writes
int writes = 0;
// traverse array elements and put it to on
// the right place
for (int cycle_start = 0; cycle_start <= n - 2; cycle_start++) {
// initialize item as starting point
int item = arr[cycle_start];
// Find position where we put the item. We basically
// count all smaller elements on right side of item.
int pos = cycle_start;
for (int i = cycle_start + 1; i < n; i++)
if (arr[i] < item)
pos++;
// If item is already in correct position
if (pos == cycle_start)
continue;
// ignore all duplicate elements
while (item == arr[pos])
pos += 1;
// put the item to it's right position
if (pos != cycle_start) {
int temp = item;
item = arr[pos];
arr[pos] = temp;
writes++;
}
// Rotate rest of the cycle
while (pos != cycle_start) {
pos = cycle_start;
// Find position where we put the element
for (int i = cycle_start + 1; i < n; i++)
if (arr[i] < item)
pos += 1;
// ignore all duplicate elements
while (item == arr[pos])
pos += 1;
// put the item to it's right position
if (item != arr[pos]) {
int temp = item;
item = arr[pos];
arr[pos] = temp;
writes++;
}
}
}
}
答案 0 :(得分:4)
不要试图翻译,而是转到wikipedia's definition:
算法
给定元素a,我们可以找到它将在其中出现的索引 通过简单计算整个列表中的元素数量来排序列表 小于a。现在
- 如果元素已经处于正确位置,则不执行任何操作。
- 如果不是,我们会将其写入预定位置。那个位置是 居住在不同的元素b,然后我们必须移动到它 正确的位置。这个过程将元素置换到正确的位置 位置继续,直到元素移动到原始位置 一个。这样就完成了一个循环。
醇>对每个元素重复此过程,只需一次写入即可对列表进行排序 当且仅当元素尚未处于正确位置时才进行操作。 计算正确的位置需要每个单独的O(n)时间 元素,从而产生二次时间算法,写入次数 操作最小化。
实施
要从上面的大纲创建工作实现, 需要解决两个问题:
- 在计算正确的位置时,我们必须确保不要 重复计算周期的第一个元素。
- 如果存在重复元素,我们可以尝试移动元素a 到了正确的位置,这个位置恰好是一个人居住的地方。 简单地交换这些将导致算法无限循环。 相反,我们必须在任何重复之后插入元素。
醇>
在haskell中实现cycleSort
,我们的第一个问题应该是应该做什么
cycleSort
的类型是什么?
正常
sort
类型为sort :: Ord a => [a] -> [a]
,但这不适用于cycleSort
。
循环排序是一种就地算法,因此排序列表毫无意义。相反,
我们要对mutable
vector进行排序。
cycleSort :: Ord a => MVector s a -> MVector s a
但这种类型并不完全正确。 MVector
的操作并不纯粹 - 他们
返回某些monad中的操作,通常为ST s
或IO
。所以这种类型需要一个
小调整。
我们将返回一个将对其进行排序的操作,而不是返回已排序的向量 执行时可变向量:
cycleSort :: (PrimMonad m, Ord a) => MVector (PrimState m) a -> m ()
(PrimMonad m
只是意味着m
可以构造改变向量的动作,
PrimState m
用于将MVector
与此特定monad绑定。
为了与其他实现进行比较,我们可能需要计算数量 写道:
cycleSort :: (PrimMonad m, Ord a) => MVector (PrimState m) a -> m Int
所以现在我们可以研究算法本身。
由于这是一项任务,我不会为您提供解决方案,但这里是 一些有用的功能:
Data.Vector.Mutable.length :: MVector s a -> Int
获取可变载体的长度Data.Vector.Mutable.read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
读取可变向量中索引的值Data.Vector.Mutable.write :: PrimMonad m => MVector (PrimState m) a -> Int -> a -> m ()
在可变向量中的索引处写入值有关使用的示例,这是一个反转MVector的函数:
import Control.Monad (when)
import Control.Monad.Primitive (PrimMonad, PrimState)
import qualified Data.Vector.Mutable as MV
reverseMVector :: PrimMonad m => MV.MVector (PrimState m) a -> m ()
reverseMVector v = loop 0 (MV.length v - 1) where
loop lo hi = when (lo < hi) $ do
a <- MV.read v lo
b <- MV.read v hi
MV.write v lo b
MV.write v hi a
loop (lo+1) (hi-1)
有许多先进的技术可以使解决方案更漂亮,但是
递归函数(如上面的loop
)就足够了。
例如,可以翻译
// ignore all duplicate elements
while (item == arr[pos])
pos += 1;
作为
-- ignore all duplicate elements
let skipDupes pos = do
jtem <- MV.read v pos
if item == jtem
then skipDupes (pos + 1)
else return pos
pos <- skipDupes pos
如果要在各种输入上测试代码,请使用
Data.Vector.thaw
/ Data.Vector.freeze
将Vector a
与...进行转换
MVector s a
。
当您遇到问题时,请发布您目前为止的代码以及您遇到的错误 碰上了。