比較しないソートの作成
Posted feedbacks - Nested
Flatten HiddenSqueak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 | | sort |
sort := [:min :max :size :data |
| bag out |
bag := data asBag.
out := OrderedCollection new: size.
min to: max do: [:each |
(bag occurrencesOf: each) timesRepeat: [out add: each]].
out asArray].
sort valueWithArguments: #(-1 10 10 (-1 9 4 8 9 6 3 9 5 2))
"=> #(-1 2 3 4 5 6 8 9 9 9) "
|
Counting sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private import std.stdio;
void main() {
int[] a = [1, 9, 4, 8, 9, 6, 3, 9, 5, 2];
a.countingSort(1, 10);
writeln(a);
}
void countingSort(int[] array, int min, int max) {
auto counts = new uint[max - min + 1];
foreach(n; array) {
counts[n - min]++;
}
auto p = array.ptr;
foreach(i, c; counts) {
p[0..c] = i + min;
p += c;
}
}
|
Radix sort (内部アルゴリズムはBucket sort)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | private import std.stdio, std.stdint;
void main() {
int64_t[] a = [int64_t.max, 0, -1, 3, 1 << 17, -1 << 30, int64_t.min];
writeln(a); // [9223372036854775807 0 -1 3 131072 -1073741824 -9223372036854775808]
a.radixSort();
writeln(a); // [-9223372036854775808 -1073741824 -1 0 3 131072 9223372036854775807]
}
private import std.traits : unsigned;
void radixSort(T)(T[] array) if(is(unsigned!(T))) {
alias unsigned!(T) U;
auto uarray = new U[array.length];
foreach(i, ref n; uarray) {
n = array[i] - T.min;
}
foreach(i; 0 .. T.sizeof * 8 / 4) {
auto buckets = new U[][1 << 4];
foreach(n; uarray) {
buckets[n >> i * 4 & 0b1111] ~= n;
}
auto p = uarray.ptr;
foreach(bucket; buckets) {
p[0 .. bucket.length] = bucket;
p += bucket.length;
}
}
foreach(i, ref n; array) {
n = uarray[i] + T.min;
}
}
|
クイックソート的にやりました。
しかし、終了条件が悪いので遅いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Data.List (group,sort)
main :: IO ()
main = print $ qsort (-1) 10 [-1,9,4,8,9,6,3,9,5,2]
uniq :: Ord a => [a] -> [a]
uniq ns = map head $ group $ sort ns
qsort :: Integral a => a -> a -> [a] -> [a]
qsort _ _ [] = []
qsort _ _ ns | length (uniq ns) == 1 = ns
qsort min max ns = let mid = div (max + min) 2
in qsort min mid [y | y <- ns, y < mid] ++ qsort mid max [y | y <- ns, y >=mid ]
|
uniq の中で sort を使ってしまっていますよ。(^_^;)
以下のリスト内包表記内でも比較が使われていますね。
1 | [y | y <- ns, y < mid] ++ qsort mid max [y | y <- ns, y >=mid ]
|
問題文に 「最大値や最低値を元に算出した数値との比較は使用しても問題ありません。」 とあるのでその比較は問題ないんじゃないでしょうか。
counting sortを実装しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import java.util.Arrays;
public class Sample187 {
public static int[] countingSort(int min, int max, int[] data) {
int[] counter = new int[max - min + 1];
for (int i: data) {
counter[i - min]++;
}
int[] result = new int[data.length];
int index = 0;
for (int i = 0; i < counter.length; i++) {
for (int count = 0; count < counter[i]; count++) {
result[index++] = i + min;
}
}
return result;
}
public static void main(String[] args) {
int[] sort = countingSort(-1, 10, new int[] {-1, 9, 4, 8, 9, 6, 3, 9, 5, 2});
System.out.println(Arrays.toString(sort));
}
}
|
horiuchiさんの#6648をコピペしてC#のコードに改変しました。
殆ど一緒です。行数まで一致しています。
JavaとC#って似てますよね。
殆ど一緒です。行数まで一致しています。
JavaとC#って似てますよね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System;
public class Sample187 {
public static int[] countingSort(int min, int max, int[] data) {
int[] counter = new int[max - min + 1];
foreach(int i in data) {
counter[i - min]++;
}
int[] result = new int[data.Length];
int index = 0;
for(int i = 0; i < counter.Length; i++) {
for(int count = 0; count < counter[i]; count++) {
result[index++] = i + min;
}
}
return result;
}
public static void Main(String[] args) {
int[] sort = countingSort(-1, 10, new int[] { -1, 9, 4, 8, 9, 6, 3, 9, 5, 2 });
foreach(int i in sort) Console.Write(i + " ");
}
}
|
バケツで。
see: バケットソート
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php
$min = -1;
$max = 10;
$input = array(-1, 9, 4, 8, 9, 6, 3, 9, 5, 2);
$sorted = bucketsort($min, $max, $input);
function bucketsort($min, $max, $input){
for($i = $min; $i <= $max; $i++)
$temp[$i] = 0;
foreach($input as $v)
$temp[$v]++;
foreach($temp as $k => $v)
for($i = 0; $i < $v; $i++)
$sorted[] = $k;
return $sorted;
}
|
Mosh (Scheme) で書きました。
データ個数を終了条件に使えばもっと効率よくできそうです。
1 2 3 4 5 6 7 8 9 10 11 12 | (define count-sort (lambda (range-min range-max range-len data)
(let loop1 ((i range-min) (result '()))
(if (>= i range-max)
result
(loop1 (+ i 1) (append result
(let loop2 ((ls data) (rs '()))
(if (pair? ls)
(loop2 (cdr ls) (if (= i (car ls)) (cons i rs) rs))
rs))))))))
(write (count-sort -1 10 10 '(-1 9 4 8 9 6 3 9 5 2)))
(newline)
|
しまった。。。
バケットソートというのがあるんですね。
あんまり余裕がないので Gauche で書き直し。
バケットソートというのがあるんですね。
あんまり余裕がないので Gauche で書き直し。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (use gauche.sequence)
(define bucket-sort (lambda (range-min range-max data-len data)
(let* ((range-len (+ 1 (- range-max range-min)))
(bucket (make-vector range-len 0))
(result '()))
(for-each (lambda (i)
(let ((j (- i range-min)))
(vector-set! bucket j (+ 1 (vector-ref bucket j)))))
data)
(for-each-with-index
(lambda (i count)
(set! result (append result
(make-list count (+ i range-min)))))
bucket)
result)))
(define main (lambda (args)
(write (bucket-sort -1 10 10 '(-1 9 4 8 9 6 3 9 5 2)))
(newline)
0))
|
mc さんの #6658 を参考にして、だいぶすっきりしたコードになりました。
ありがとうございます。
ありがとうございます。
1 2 3 4 5 6 7 8 | (define bucket-sort (lambda (range-min range-max data-len data)
(let ((bucket (make-vector (+ 1 (- range-max range-min)) '())))
(for-each
(lambda (i)
(let ((j (- i range-min)))
(vector-set! bucket j (cons i (vector-ref bucket j)))))
data)
(fold-right append '() (vector->list bucket)))))
|
JavaScript。クイックソート、かな?
効率悪そう。
効率悪そう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Array.prototype.sort2 = function(minVal, maxVal) {
if (this.length <= 1) return this;
var mid = (minVal + maxVal) / 2;
var lt = [], eq = [], gt = [];
for (var i=0; i < this.length; i++) {
if (this[i] > mid)
gt.push(this[i]);
else if (this[i] < mid)
lt.push(this[i]);
else
eq.push(this[i]);
}
return lt.sort2(minVal, mid).concat(eq, gt.sort2(mid, maxVal));
};
[-1,9,4,8,9,6,3,9,5,2].sort2(-1,10)
|
おっと。無駄が多すぎた。
以下の修正で関数に入る回数が109→15に改善しました。
以下の修正で関数に入る回数が109→15に改善しました。
1 2 3 4 | 3c3
< var mid = (minVal + maxVal) / 2;
---
> var mid = Math.floor((minVal + maxVal) / 2);
|
重複する要素が一個にまとめられてしまいます。
あぁ、情けなし。
1 2 3 4 5 6 7 8 9 10 11 | module Main where
sort_noComp min max xs = foldr (addCount) (map (flip (,) $ 0) [min..max]) xs >>= \(x, c) -> replicate c x
where
addCount :: Int -> [(Int, Int)] -> [(Int, Int)]
addCount i [] = []
addCount i ((j, x):xs)
| i == j = (j, x + 1) : xs
| otherwise = (j, x) : addCount i xs
main = print $ sort_noComp 1 9 [4, 8, 9, 6, 3, 9, 5, 2]
|
baalさんの #6653 を参考にバケットソートで書いてみました。
(bucket-sort -1 10 10 '(-1 9 4 8 9 6 3 9 5 2))
;=> (-1 2 3 4 5 6 8 9 9 9)
(bucket-sort -1 10 10 '(-1 9 4 8 9 6 3 9 5 2))
;=> (-1 2 3 4 5 6 8 9 9 9)
1 2 3 4 5 6 | (defun bucket-sort (min max size data)
(declare (integer min max size) (list data))
(loop :with tem := (make-array (max size (- max min)) :initial-element () )
:for item :of-type integer :in data
:do (push item (svref tem (- item min)))
:finally (return (reduce #'nconc tem))))
|
アルゴリズム的にはcounting sort相当になると思います。
1 2 3 | sort.uncompare <- function(min, max, num, l){
unlist(sapply(min:max, function(n)(l[l==n])))
}
|
これでいいのかな。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def sort(min, max, a):
counts = [0] * (max - min + 1)
for x in a:
counts[x - min] += 1
result = []
for i, count in enumerate(counts):
for _ in xrange(count):
result.append(i + min)
return result
def main():
print sort(-1, 10, [-1, 9, 4, 8, 9, 6, 3, 9, 5, 2])
if __name__ == '__main__':
main()
|
基数ソートです。 引数の最大値と最小値はメソッド内で使用してません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | using System;
using System.Linq;
class Program
{
static void Main()
{
int[] x = { -1, 9, 4, 8, 9, 6, 3, 9, 5, 2 };
foreach (var item in RadixSort(x, int.MinValue, int.MaxValue))
{
Console.Write(item + " ");
}
Console.WriteLine();
}
static int[] RadixSort(int[] a, int min, int max)
{
for (uint x = 1; x != 0; x <<= 1)
{
a = a.Where(n => (n & x) == 0).Concat(a.Where(n => (n & x) != 0)).ToArray();
}
return a.SkipWhile(n => 0 <= n).Concat(a.TakeWhile(n => 0 <= n)).ToArray();
}
}
|
途中で (max-min+1)*n の配列ができちゃう。メモリ使いすぎ。
1 2 3 4 5 6 7 8 | sortx=:3 :0
min=. 0 { y
max=. 1 { y
n=. 2 { y
a=. 3 }. y
b=. min + i. 1 + max - min
(+/"1 b =/ a) # b
)
|
短くする方向で書いてみました。個数は要りません。
1 | mysort min max ns = concat [filter (== x) ns | x <- [min..max]]
|
こんな感じでしょうか。配列と最小値だけ必要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ●sort(data,min)
tmpとは配列
bufとは配列
iとは整数
dataを反復
tmp[対象-min]=tmp[対象-min]+1
iで0から(tmpの配列要素数)-1まで繰り返す
(tmp[i])回
bufにi+minを配列追加
bufで戻る
a="-1 9 4 8 9 6 3 9 5 2"を" "で区切る
sort(a,-1)を表示
|
counting sortを実装しました。 > ghc --make -O2 CountingSort.hs > ./CountingSort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import qualified Data.Map as M
import Control.Monad.State
counter min max xs = recur (M.fromAscList $ zip [min..max] (repeat 0)) xs
where recur ctr [] = M.toAscList ctr
recur ctr (x:xs) = recur (M.update (\v -> Just (succ v)) x ctr) xs
countingSort :: (Ord a, Enum a, Num a) => a -> a -> [a] -> [a]
countingSort min max xs = let ctr = counter min max xs
result = M.fromAscList $ zip [0..len] (repeat 0)
in evalState (countingSort_S min ctr) (0,result)
where len = fromIntegral $ length xs - 1
countingSort_S :: (Ord a, Enum a, Num a) => a -> [(a,a)] -> State (a,M.Map a a) [a]
countingSort_S _ [] = get >>= return . M.elems . snd
countingSort_S min ((x,y):xs) = do
forM_ [1..y] update
countingSort_S min xs
where update _ = do
(index,result) <- get
put (succ index, M.update f index result)
f _ = Just x
main :: IO ()
main = do
print $ countingSort (-1) 10 [-1,9,4,8,9,6,3,9,5,2]
print $ countingSort (-100000) 100000 [-100000..100000]
|
ちょっと修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import qualified Data.Map as M
import Control.Monad.State
counter min max xs = recur (M.fromAscList $ zip [min..max] (repeat 0)) xs
where recur ctr [] = M.toAscList ctr
recur ctr (x:xs) = recur (M.update (\v -> Just (succ v)) x ctr) xs
countingSort :: (Ord a, Enum a, Num a) => a -> a -> [a] -> [a]
countingSort min max xs = let ctr = counter min max xs
in evalState (countingSort_S min ctr) []
where len = fromIntegral $ length xs - 1
countingSort_S :: (Ord a, Enum a, Num a) => a -> [(a,a)] -> State [a] [a]
countingSort_S _ [] = get >>= return . reverse
countingSort_S min ((x,y):xs) = do
forM_ [1< |





sweetie089 #6628() Rating3/3=1.00
[ reply ]