2012-07-12 10 views

답변

6

하스켈에서 FIFO 대기열을 롤업하는 것은 실제로 어렵지 않습니다. 나는 당신이 이것을 위해 표준 typeclass를 사용하고 싶어하는 것에 대해 감사 할 수있다. 그리고 그것은 당신이해야하는 거의 확실한 것이다. 그러나 저는 지난 주에 대해 배웠습니다. 나는 그것에 대해 쓰지 않기에 너무나 기쁩니다.

다음은 간단한 대기열 클래스입니다.이 클래스를 사용하면 대기열이 비어 있는지 확인할 수 있습니다. 대기열의 첫 번째 요소를 가져 와서 나머지 대기열을 반환하고 새 요소를 대기열에 삽입 할 수 있습니다 .

class Queue q where 
    empty :: q a -> Bool 
    get :: q a -> (a, q a) 
    ins :: a -> q a -> q a 

는 FIFO 큐를 확인하는 가장 간단한 방법

이 목록을 사용하고 있습니다 :

instance Queue [] where 
    empty = null 

    get []  = error "Can't retrieve elements from an empty list" 
    get (x:xs) = (x, xs) 

    ins x xs = xs ++ [x] 

그러나,이 끔찍하게 비효율적이다. 큐에 현재 n 요소가있는 경우 새 요소를 삽입하려면 O (n) 시간이 걸립니다. 빈 큐에 m 요소를 삽입하려면 O (m) 시간이 필요합니다. O (1) 시간 (또는 최소, O (1) 상각 시간)에 요소를 삽입하고 검색하는 대기열을 만들 수 있습니까?

data Fifo a = F [a] [a] 

instance Queue Fifo where 

큐 앞뒤 양쪽 경우 비어 :

트릭 역방향에 저장되는 큐의 후면과 전면 분리 목록에 큐 다시 저장하는 것이다 비어 있음 :

empty (F xs ys) = null xs && null ys 

새 요소를 목록에 삽입하려면 O (1) 시간이 소요되는 대기열에 넣으십시오. 거기에 대기 요소 (이 큐가 비어있는 경우 우리가 오류가 발생)에 요소가없는 경우,

get (F []  []) = error "Can't retrieve elements from an empty queue" 
    get (F (x:xs) ys) = (x, F xs ys) 

마지막 때 큐의 앞쪽에서 요소를 얻기

ins y (F xs ys) = F xs (y:ys) 

쉽게 대기열의 앞에서 기다린 다음 대기열의 뒤를 뒤집어서 앞에 놓습니다. (O 상각 -

get (F [] ys) = get (F (reverse ys) []) 

당신이 한 :이 O를 취했지만 (N) 시간, 우리는 그래서 우리의 GET 작업의 평균 (1) 시간 O 밖으로, 각 요소에 대해 한 번해야 1) 기능적 언어로 FIFO 대기열.


편집 :는 Efie는 코멘트에 상각 O (1)의 성능에 대해 물었다. 상각 된 상수 시간에 대한 논의는 매우 간단합니다.

n 빈 큐에 대한 삽입 다음에 n 검색이 이어지는 것으로 간주하십시오. 삽입은 시간이 n 걸립니다. 첫 번째 검색에서 대기열의 앞면이 비어 있으므로 대기열의 뒤를 되돌려 야합니다. 또한 n에 1을 더하여 요소를 검색합니다. 우리가 만든 1 = 3 N

- 마지막으로, 다음 N - 총 시간은

N + N + 1 + N 그래서 1 취득에서는이 시간이 1 각을 2 n 총 호출이므로 상환 시간은 3 (n/2 n = 3/2)이며 O (1)입니다. insget에 대한 호출이 어떻게 인터리브되었는지에 상관없이 동일한 인수가 작동합니다. 두 번의 호출에서 각 요소는 한 번에 한 번에 한 번만 이동되고 한 번만 이동하고 한 번만 수행 할 수 있습니다.

+0

감사합니다. 나는 귀하의 게시물을 좋아합니다. 오류가 발생하지 않도록 요소를 가져 오기 전에 매번 목록이 null인지 확인해야합니다. 그렇지 않습니까? get :: q a -> (get a, q a)의 형식을 변경하는 것보다 낫습니까? – efie

+3

'안전한'방법은 형식을'get :: qa -> Maybe (a, qa)'로 변경하는 것입니다 (튜플을 감싸는'Maybe '로 나머지 부분을 반환하는 것은 의미가 없으므로). 첫 번째 요소를 검색하지 못한 경우 대기열). 구현을 간단하게하기 위해 이것을 무시 했으므로 코드를 안전하게 사용하기 전에 목록이 null인지 확인해야합니다. 'Maybe' 래퍼를 사용하면 호출 후'Nothing' *을 확인해야하므로이 작업은 더 이상 필요하지 않습니다. 그러나 래퍼를 사용하면 형식 시스템에서 확인하지 않아도되므로 안전하지 않은 코드를 작성할 수 있습니다. –

+0

요소를 가져 오는 평균적인 경우가 O (1) 인 경우를 확장하고 싶습니다. 큐에 n 개의 요소가 있으면 (n + 1) 개 있습니다! 그들을 두 개의 목록에 할당하는 방법 : n! n 개의 요소를 정렬하는 방법, 각 배열을 두 개의 목록으로 나누는 (n + 1) 개의 방법. n이 있습니다! xs가 비어있는 경우 ys에 요소를 정렬하는 방법. probes ("xsIsEmpty") * 비용 ("xsIsEmpty") + prob ("xsNotEmpty") * 비용 ("xsNotEmpty") = n!/(n + 1)! * n + ... * 0 = n/n + 1 = O (1). – efie

2

원하는 작업에 따라 다릅니다. queuelikedequeue 패키지에는 대기열에 대한 유형 클래스가 있습니다.