Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
5
Task/Quickselect-algorithm/00-META.yaml
Normal file
5
Task/Quickselect-algorithm/00-META.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
category:
|
||||
- Sorting
|
||||
from: http://rosettacode.org/wiki/Quickselect_algorithm
|
||||
note: Sorting Algorithms
|
||||
8
Task/Quickselect-algorithm/00-TASK.txt
Normal file
8
Task/Quickselect-algorithm/00-TASK.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{{Sorting Algorithm}}
|
||||
|
||||
Use the [[wp:Quickselect|quickselect algorithm]] on the vector
|
||||
: [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
To show the first, second, third, ... up to the tenth largest member of the vector, in order, here on this page.
|
||||
|
||||
* Note: Quick''sort'' has a separate [[Sorting algorithms/Quicksort|task]]. <br><br>
|
||||
|
||||
40
Task/Quickselect-algorithm/11l/quickselect-algorithm.11l
Normal file
40
Task/Quickselect-algorithm/11l/quickselect-algorithm.11l
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
F partition(&vector, left, right, pivotIndex)
|
||||
V pivotValue = vector[pivotIndex]
|
||||
swap(&vector[pivotIndex], &vector[right])
|
||||
V storeIndex = left
|
||||
L(i) left .< right
|
||||
I vector[i] < pivotValue
|
||||
swap(&vector[storeIndex], &vector[i])
|
||||
storeIndex++
|
||||
swap(&vector[right], &vector[storeIndex])
|
||||
R storeIndex
|
||||
|
||||
F _select(&vector, =left, =right, =k)
|
||||
‘Returns the k-th smallest, (k >= 0), element of vector within vector[left:right+1] inclusive.’
|
||||
L
|
||||
V pivotIndex = (left + right) I/ 2
|
||||
V pivotNewIndex = partition(&vector, left, right, pivotIndex)
|
||||
V pivotDist = pivotNewIndex - left
|
||||
I pivotDist == k
|
||||
R vector[pivotNewIndex]
|
||||
E I k < pivotDist
|
||||
right = pivotNewIndex - 1
|
||||
E
|
||||
k -= pivotDist + 1
|
||||
left = pivotNewIndex + 1
|
||||
|
||||
F select(&vector, k)
|
||||
‘
|
||||
Returns the k-th smallest, (k >= 0), element of vector within vector[left:right+1].
|
||||
left, right default to (0, len(vector) - 1) if omitted
|
||||
’
|
||||
V left = 0
|
||||
V lv1 = vector.len - 1
|
||||
V right = lv1
|
||||
assert(!vector.empty & k >= 0, ‘Either null vector or k < 0 ’)
|
||||
assert(left C 0 .. lv1, ‘left is out of range’)
|
||||
assert(right C left .. lv1, ‘right is out of range’)
|
||||
R _select(&vector, left, right, k)
|
||||
|
||||
V v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
print((0.<10).map(i -> select(&:v, i)))
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
BEGIN
|
||||
# returns the kth lowest element of list using the quick select algorithm #
|
||||
PRIO QSELECT = 1;
|
||||
OP QSELECT = ( INT k, REF[]INT list )INT:
|
||||
IF LWB list > UPB list THEN
|
||||
# empty list #
|
||||
0
|
||||
ELSE
|
||||
# non-empty list #
|
||||
# partitions the subset of list from left to right #
|
||||
PROC partition = ( REF[]INT list, INT left, right, pivot index )INT:
|
||||
BEGIN
|
||||
# swaps elements a and b in list #
|
||||
PROC swap = ( REF[]INT list, INT a, b )VOID:
|
||||
BEGIN
|
||||
INT t = list[ a ];
|
||||
list[ a ] := list[ b ];
|
||||
list[ b ] := t
|
||||
END # swap # ;
|
||||
INT pivot value = list[ pivot index ];
|
||||
swap( list, pivot index, right );
|
||||
INT store index := left;
|
||||
FOR i FROM left TO right - 1 DO
|
||||
IF list[ i ] < pivot value THEN
|
||||
swap( list, store index, i );
|
||||
store index +:= 1
|
||||
FI
|
||||
OD;
|
||||
swap( list, right, store index );
|
||||
store index
|
||||
END # partition # ;
|
||||
INT left := LWB list, right := UPB list, result := 0;
|
||||
BOOL found := FALSE;
|
||||
WHILE NOT found DO
|
||||
IF left = right THEN
|
||||
result := list[ left ];
|
||||
found := TRUE
|
||||
ELSE
|
||||
INT pivot index = partition( list, left, right, left + ENTIER ( ( random * ( right - left ) + 1 ) ) );
|
||||
IF k = pivot index THEN
|
||||
result := list[ k ];
|
||||
found := TRUE
|
||||
ELIF k < pivot index THEN
|
||||
right := pivot index - 1
|
||||
ELSE
|
||||
left := pivot index + 1
|
||||
FI
|
||||
FI
|
||||
OD;
|
||||
result
|
||||
FI # QSELECT # ;
|
||||
# test cases #
|
||||
FOR i TO 10 DO
|
||||
[ 1 : 10 ]INT test := []INT( 9, 8, 7, 6, 5, 0, 1, 2, 3, 4 );
|
||||
print( ( whole( i, -2 ), ": ", whole( i QSELECT test, -3 ), newline ) )
|
||||
OD
|
||||
END
|
||||
637
Task/Quickselect-algorithm/ATS/quickselect-algorithm.ats
Normal file
637
Task/Quickselect-algorithm/ATS/quickselect-algorithm.ats
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
(*------------------------------------------------------------------*)
|
||||
(*
|
||||
|
||||
For linear linked lists, using a random pivot:
|
||||
|
||||
* stable three-way "separation" (a variant of quickselect)
|
||||
* quickselect
|
||||
* stable quicksort
|
||||
|
||||
Also a couple of routines for splitting lists according to a
|
||||
predicate.
|
||||
|
||||
Linear list operations are destructive but may avoid doing many
|
||||
unnecessary allocations. Also they do not require a garbage
|
||||
collector.
|
||||
|
||||
*)
|
||||
|
||||
#include "share/atspre_staload.hats"
|
||||
|
||||
staload UN = "prelude/SATS/unsafe.sats"
|
||||
|
||||
#define NIL list_vt_nil ()
|
||||
#define :: list_vt_cons
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(* A simple linear congruential generator for pivot selection. *)
|
||||
|
||||
(* The multiplier lcg_a comes from Steele, Guy; Vigna, Sebastiano (28
|
||||
September 2021). "Computationally easy, spectrally good multipliers
|
||||
for congruential pseudorandom number generators".
|
||||
arXiv:2001.05304v3 [cs.DS] *)
|
||||
macdef lcg_a = $UN.cast{uint64} 0xf1357aea2e62a9c5LLU
|
||||
|
||||
(* lcg_c must be odd. *)
|
||||
macdef lcg_c = $UN.cast{uint64} 0xbaceba11beefbeadLLU
|
||||
|
||||
var seed : uint64 = $UN.cast 0
|
||||
val p_seed = addr@ seed
|
||||
|
||||
fn
|
||||
random_double () :<!wrt> double =
|
||||
let
|
||||
val (pf, fpf | p_seed) = $UN.ptr0_vtake{uint64} p_seed
|
||||
val old_seed = ptr_get<uint64> (pf | p_seed)
|
||||
|
||||
(* IEEE "binary64" or "double" has 52 bits of precision. We will
|
||||
take the high 48 bits of the seed and divide it by 2**48, to
|
||||
get a number 0.0 <= randnum < 1.0 *)
|
||||
val high_48_bits = $UN.cast{double} (old_seed >> 16)
|
||||
val divisor = $UN.cast{double} (1LLU << 48)
|
||||
val randnum = high_48_bits / divisor
|
||||
|
||||
(* The following operation is modulo 2**64, by virtue of standard
|
||||
C behavior for uint64_t. *)
|
||||
val new_seed = (lcg_a * old_seed) + lcg_c
|
||||
|
||||
val () = ptr_set<uint64> (pf | p_seed, new_seed)
|
||||
prval () = fpf pf
|
||||
in
|
||||
randnum
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
(* Destructive split into two lists: a list of leading elements that
|
||||
satisfy a predicate, and the tail of that split. (This is similar
|
||||
to "span!" in SRFI-1.) *)
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_span {n : int}
|
||||
(pred : &((&a) -<cloptr1> bool),
|
||||
lst : list_vt (a, n))
|
||||
: [n1, n2 : nat | n1 + n2 == n]
|
||||
@(list_vt (a, n1),
|
||||
list_vt (a, n2))
|
||||
|
||||
(* Destructive, stable partition into elements less than the pivot,
|
||||
elements equal to the pivot, and elements greater than the
|
||||
pivot. *)
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_three_way_partition
|
||||
{n : int}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
pivot : &a,
|
||||
lst : list_vt (a, n))
|
||||
: [n1, n2, n3 : nat | n1 + n2 + n3 == n]
|
||||
@(list_vt (a, n1),
|
||||
list_vt (a, n2),
|
||||
list_vt (a, n3))
|
||||
|
||||
(* Destructive, stable partition into elements less than the kth least
|
||||
element, elements equal to it, and elements greater than it. *)
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_three_way_separation
|
||||
{n, k : int | 0 <= k; k < n}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
k : int k,
|
||||
lst : list_vt (a, n))
|
||||
: [n1, n2, n3 : nat | n1 + n2 + n3 == n;
|
||||
n1 <= k; k < n1 + n2]
|
||||
@(int n1, list_vt (a, n1),
|
||||
int n2, list_vt (a, n2),
|
||||
int n3, list_vt (a, n3))
|
||||
|
||||
(* Destructive quickselect for linear elements. *)
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_select_linear
|
||||
{n, k : int | 0 <= k; k < n}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
k : int k,
|
||||
lst : list_vt (a, n)) : a
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_select_linear$clear (x : &a >> a?) : void
|
||||
|
||||
(* Destructive quickselect for non-linear elements. *)
|
||||
extern fun {a : t@ype}
|
||||
list_vt_select
|
||||
{n, k : int | 0 <= k; k < n}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
k : int k,
|
||||
lst : list_vt (a, n)) : a
|
||||
|
||||
(* Stable quicksort. Also returns the length. *)
|
||||
extern fun {a : vt@ype}
|
||||
list_vt_stable_sort
|
||||
{n : int}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
lst : list_vt (a, n))
|
||||
: @(int n, list_vt (a, n))
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
implement {a}
|
||||
list_vt_span {n} (pred, lst) =
|
||||
let
|
||||
fun
|
||||
loop {n : nat} .<n>.
|
||||
(pred : &((&a) -<cloptr1> bool),
|
||||
cursor : &list_vt (a, n) >> list_vt (a, m),
|
||||
tail : &List_vt a? >> list_vt (a, n - m))
|
||||
: #[m : nat | m <= n] void =
|
||||
case+ cursor of
|
||||
| NIL => tail := NIL
|
||||
| @ elem :: rest =>
|
||||
if pred (elem) then
|
||||
(* elem satisfies the predicate. Move the cursor to the next
|
||||
cons-pair in the list. *)
|
||||
let
|
||||
val () = loop {n - 1} (pred, rest, tail)
|
||||
prval () = fold@ cursor
|
||||
in
|
||||
end
|
||||
else
|
||||
(* elem does not satisfy the predicate. Split the list at
|
||||
the cursor. *)
|
||||
let
|
||||
prval () = fold@ cursor
|
||||
val () = tail := cursor
|
||||
val () = cursor := NIL
|
||||
in
|
||||
end
|
||||
|
||||
prval () = lemma_list_vt_param lst
|
||||
|
||||
var cursor = lst
|
||||
var tail : List_vt a?
|
||||
val () = loop {n} (pred, cursor, tail)
|
||||
in
|
||||
@(cursor, tail)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
implement {a}
|
||||
list_vt_three_way_partition {n} (compare, pivot, lst) =
|
||||
//
|
||||
// WARNING: This implementation is NOT tail-recursive.
|
||||
//
|
||||
let
|
||||
var current_sign : int = 0
|
||||
|
||||
val p_compare = addr@ compare
|
||||
val p_pivot = addr@ pivot
|
||||
val p_current_sign = addr@ current_sign
|
||||
|
||||
var pred = (* A linear closure. *)
|
||||
lam (elem : &a) : bool =<cloptr1>
|
||||
(* Return true iff the sign of the comparison of elem with the
|
||||
pivot matches the current_sign. *)
|
||||
let
|
||||
val @(pf_compare, fpf_compare | p_compare) =
|
||||
$UN.ptr0_vtake{(&a, &a) -<cloptr1> int} p_compare
|
||||
val @(pf_pivot, fpf_pivot | p_pivot) =
|
||||
$UN.ptr0_vtake{a} p_pivot
|
||||
val @(pf_current_sign, fpf_current_sign | p_current_sign) =
|
||||
$UN.ptr0_vtake{int} p_current_sign
|
||||
|
||||
macdef compare = !p_compare
|
||||
macdef pivot = !p_pivot
|
||||
macdef current_sign = !p_current_sign
|
||||
|
||||
val sign = compare (elem, pivot)
|
||||
val truth =
|
||||
(sign < 0 && current_sign < 0) ||
|
||||
(sign = 0 && current_sign = 0) ||
|
||||
(sign > 0 && current_sign > 0)
|
||||
|
||||
prval () = fpf_compare pf_compare
|
||||
prval () = fpf_pivot pf_pivot
|
||||
prval () = fpf_current_sign pf_current_sign
|
||||
in
|
||||
truth
|
||||
end
|
||||
|
||||
fun
|
||||
recurs {n : nat}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
pred : &((&a) -<cloptr1> bool),
|
||||
pivot : &a,
|
||||
current_sign : &int,
|
||||
lst : list_vt (a, n))
|
||||
: [n1, n2, n3 : nat | n1 + n2 + n3 == n]
|
||||
@(list_vt (a, n1),
|
||||
list_vt (a, n2),
|
||||
list_vt (a, n3)) =
|
||||
case+ lst of
|
||||
| ~ NIL => @(NIL, NIL, NIL)
|
||||
| @ elem :: tail =>
|
||||
let
|
||||
macdef append = list_vt_append<a>
|
||||
val cmp = compare (elem, pivot)
|
||||
val () = current_sign := cmp
|
||||
prval () = fold@ lst
|
||||
val @(matches, rest) = list_vt_span<a> (pred, lst)
|
||||
val @(left, middle, right) =
|
||||
recurs (compare, pred, pivot, current_sign, rest)
|
||||
in
|
||||
if cmp < 0 then
|
||||
@(matches \append left, middle, right)
|
||||
else if cmp = 0 then
|
||||
@(left, matches \append middle, right)
|
||||
else
|
||||
@(left, middle, matches \append right)
|
||||
end
|
||||
|
||||
prval () = lemma_list_vt_param lst
|
||||
val retvals = recurs (compare, pred, pivot, current_sign, lst)
|
||||
|
||||
val () = cloptr_free ($UN.castvwtp0{cloptr0} pred)
|
||||
in
|
||||
retvals
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
fn {a : vt@ype}
|
||||
three_way_partition_with_random_pivot
|
||||
{n : nat}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
n : int n,
|
||||
lst : list_vt (a, n))
|
||||
: [n1, n2, n3 : nat | n1 + n2 + n3 == n]
|
||||
@(int n1, list_vt (a, n1),
|
||||
int n2, list_vt (a, n2),
|
||||
int n3, list_vt (a, n3)) =
|
||||
let
|
||||
macdef append = list_vt_append<a>
|
||||
|
||||
var pivot : a
|
||||
|
||||
val randnum = random_double ()
|
||||
val i_pivot = $UN.cast{Size_t} (randnum * $UN.cast{double} n)
|
||||
prval () = lemma_g1uint_param i_pivot
|
||||
val () = assertloc (i_pivot < i2sz n)
|
||||
val i_pivot = sz2i i_pivot
|
||||
|
||||
val @(left, right) = list_vt_split_at<a> (lst, i_pivot)
|
||||
val+ ~ (pivot_val :: right) = right
|
||||
val () = pivot := pivot_val
|
||||
|
||||
val @(left1, middle1, right1) =
|
||||
list_vt_three_way_partition<a> (compare, pivot, left)
|
||||
val @(left2, middle2, right2) =
|
||||
list_vt_three_way_partition<a> (compare, pivot, right)
|
||||
|
||||
val left = left1 \append left2
|
||||
val middle = middle1 \append (pivot :: middle2)
|
||||
val right = right1 \append right2
|
||||
|
||||
val n1 = length<a> left
|
||||
val n2 = length<a> middle
|
||||
val n3 = n - n1 - n2
|
||||
in
|
||||
@(n1, left, n2, middle, n3, right)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
implement {a}
|
||||
list_vt_three_way_separation {n, k} (compare, k, lst) =
|
||||
(* This is a quickselect with random pivot, returning a three-way
|
||||
partition, in which the middle partition contains the (k+1)st
|
||||
least element. *)
|
||||
let
|
||||
macdef append = list_vt_append<a>
|
||||
|
||||
fun
|
||||
loop {n1, n2, n3, k : nat | 0 <= k; k < n;
|
||||
n1 + n2 + n3 == n}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
k : int k,
|
||||
n1 : int n1,
|
||||
left : list_vt (a, n1),
|
||||
n2 : int n2,
|
||||
middle : list_vt (a, n2),
|
||||
n3 : int n3,
|
||||
right : list_vt (a, n3))
|
||||
: [n1, n2, n3 : nat | n1 + n2 + n3 == n;
|
||||
n1 <= k; k < n1 + n2]
|
||||
@(int n1, list_vt (a, n1),
|
||||
int n2, list_vt (a, n2),
|
||||
int n3, list_vt (a, n3)) =
|
||||
if k < n1 then
|
||||
let
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n1, left)
|
||||
in
|
||||
loop (compare, k, m1, left1, m2, middle1,
|
||||
m3 + n2 + n3,
|
||||
right1 \append (middle \append right))
|
||||
end
|
||||
else if n1 + n2 <= k then
|
||||
let
|
||||
val @(m1, left2, m2, middle2, m3, right2) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n3, right)
|
||||
in
|
||||
loop (compare, k, n1 + n2 + m1,
|
||||
left \append (middle \append left2),
|
||||
m2, middle2, m3, right2)
|
||||
end
|
||||
else
|
||||
@(n1, left, n2, middle, n3, right)
|
||||
|
||||
prval () = lemma_list_vt_param lst
|
||||
|
||||
val @(n1, left, n2, middle, n3, right) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, length<a> lst, lst)
|
||||
in
|
||||
loop (compare, k, n1, left, n2, middle, n3, right)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
implement {a}
|
||||
list_vt_select_linear {n, k} (compare, k, lst) =
|
||||
(* This is a quickselect with random pivot. It is like
|
||||
list_vt_three_way_separation, but throws away parts of the list that
|
||||
will not be needed later on. *)
|
||||
let
|
||||
implement
|
||||
list_vt_freelin$clear<a> (x) =
|
||||
$effmask_all list_vt_select_linear$clear<a> (x)
|
||||
|
||||
macdef append = list_vt_append<a>
|
||||
|
||||
fun
|
||||
loop {n1, n2, n3, k : nat | 0 <= k; k < n1 + n2 + n3}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
k : int k,
|
||||
n1 : int n1,
|
||||
left : list_vt (a, n1),
|
||||
n2 : int n2,
|
||||
middle : list_vt (a, n2),
|
||||
n3 : int n3,
|
||||
right : list_vt (a, n3)) : a =
|
||||
if k < n1 then
|
||||
let
|
||||
val () = list_vt_freelin<a> middle
|
||||
val () = list_vt_freelin<a> right
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n1, left)
|
||||
in
|
||||
loop (compare, k, m1, left1, m2, middle1, m3, right1)
|
||||
end
|
||||
else if n1 + n2 <= k then
|
||||
let
|
||||
val () = list_vt_freelin<a> left
|
||||
val () = list_vt_freelin<a> middle
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n3, right)
|
||||
in
|
||||
loop (compare, k - n1 - n2,
|
||||
m1, left1, m2, middle1, m3, right1)
|
||||
end
|
||||
else
|
||||
let
|
||||
val () = list_vt_freelin<a> left
|
||||
val () = list_vt_freelin<a> right
|
||||
val @(middle1, middle2) =
|
||||
list_vt_split_at<a> (middle, k - n1)
|
||||
val () = list_vt_freelin<a> middle1
|
||||
val+ ~ (element :: middle2) = middle2
|
||||
val () = list_vt_freelin<a> middle2
|
||||
in
|
||||
element
|
||||
end
|
||||
|
||||
prval () = lemma_list_vt_param lst
|
||||
|
||||
val @(n1, left, n2, middle, n3, right) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, length<a> lst, lst)
|
||||
in
|
||||
loop (compare, k, n1, left, n2, middle, n3, right)
|
||||
end
|
||||
|
||||
implement {a}
|
||||
list_vt_select {n, k} (compare, k, lst) =
|
||||
let
|
||||
implement
|
||||
list_vt_select_linear$clear<a> (x) = ()
|
||||
in
|
||||
list_vt_select_linear<a> {n, k} (compare, k, lst)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
implement {a}
|
||||
list_vt_stable_sort {n} (compare, lst) =
|
||||
(* This is a stable quicksort with random pivot. *)
|
||||
let
|
||||
macdef append = list_vt_append<a>
|
||||
|
||||
fun
|
||||
recurs {n : int}
|
||||
{n1, n2, n3 : nat | n1 + n2 + n3 == n}
|
||||
(compare : &((&a, &a) -<cloptr1> int),
|
||||
n1 : int n1,
|
||||
left : list_vt (a, n1),
|
||||
n2 : int n2,
|
||||
middle : list_vt (a, n2),
|
||||
n3 : int n3,
|
||||
right : list_vt (a, n3))
|
||||
: @(int n, list_vt (a, n)) =
|
||||
if 1 < n1 then
|
||||
let
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n1, left)
|
||||
val @(_, left) =
|
||||
recurs {n1} (compare, m1, left1, m2, middle1, m3, right1)
|
||||
in
|
||||
if 1 < n3 then
|
||||
let
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n3, right)
|
||||
val @(_, right) =
|
||||
recurs {n3} (compare, m1, left1, m2, middle1,
|
||||
m3, right1)
|
||||
in
|
||||
@(n1 + n2 + n3, left \append (middle \append right))
|
||||
end
|
||||
else
|
||||
@(n1 + n2 + n3, left \append (middle \append right))
|
||||
end
|
||||
else if 1 < n3 then
|
||||
let
|
||||
val @(m1, left1, m2, middle1, m3, right1) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, n3, right)
|
||||
val @(_, right) =
|
||||
recurs {n3} (compare, m1, left1, m2, middle1, m3, right1)
|
||||
in
|
||||
@(n1 + n2 + n3, left \append (middle \append right))
|
||||
end
|
||||
else
|
||||
@(n1 + n2 + n3, left \append (middle \append right))
|
||||
|
||||
prval () = lemma_list_vt_param lst
|
||||
|
||||
val @(n1, left, n2, middle, n3, right) =
|
||||
three_way_partition_with_random_pivot<a>
|
||||
(compare, length<a> lst, lst)
|
||||
in
|
||||
recurs {n} (compare, n1, left, n2, middle, n3, right)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
fn
|
||||
print_kth (direction : int,
|
||||
k : int,
|
||||
lst : !List_vt int) : void =
|
||||
let
|
||||
var compare =
|
||||
lam (x : &int, y : &int) : int =<cloptr1>
|
||||
if x < y then
|
||||
~direction
|
||||
else if x = y then
|
||||
0
|
||||
else
|
||||
direction
|
||||
|
||||
val lst = copy<int> lst
|
||||
val n = length<int> lst
|
||||
val k = g1ofg0 k
|
||||
val () = assertloc (1 <= k)
|
||||
val () = assertloc (k <= n)
|
||||
val element = list_vt_select<int> (compare, k - 1, lst)
|
||||
|
||||
val () = cloptr_free ($UN.castvwtp0{cloptr0} compare)
|
||||
in
|
||||
print! (element)
|
||||
end
|
||||
|
||||
fn
|
||||
demonstrate_quickselect () : void =
|
||||
let
|
||||
var example_for_select = $list_vt (9, 8, 7, 6, 5, 0, 1, 2, 3, 4)
|
||||
|
||||
val () = print! ("With < as order predicate: ")
|
||||
val () = print_kth (1, 1, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 2, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 3, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 4, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 5, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 6, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 7, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 8, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 9, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (1, 10, example_for_select)
|
||||
val () = println! ()
|
||||
|
||||
val () = print! ("With > as order predicate: ")
|
||||
val () = print_kth (~1, 1, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 2, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 3, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 4, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 5, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 6, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 7, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 8, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 9, example_for_select)
|
||||
val () = print! (" ")
|
||||
val () = print_kth (~1, 10, example_for_select)
|
||||
val () = println! ()
|
||||
|
||||
val () = list_vt_free<int> example_for_select
|
||||
in
|
||||
end
|
||||
|
||||
fn
|
||||
demonstrate_quicksort () : void =
|
||||
let
|
||||
var example_for_sort =
|
||||
$list_vt ("elephant", "duck", "giraffe", "deer",
|
||||
"earwig", "dolphin", "wildebeest", "pronghorn",
|
||||
"woodlouse", "whip-poor-will")
|
||||
|
||||
var compare =
|
||||
lam (x : &stringGt 0,
|
||||
y : &stringGt 0) : int =<cloptr1>
|
||||
if x[0] < y[0] then
|
||||
~1
|
||||
else if x[0] = y[0] then
|
||||
0
|
||||
else
|
||||
1
|
||||
|
||||
val () = println! ("stable sort by first character:")
|
||||
val @(_, sorted_lst) =
|
||||
list_vt_stable_sort<stringGt 0>
|
||||
(compare, copy<stringGt 0> example_for_sort)
|
||||
val () = println! ($UN.castvwtp1{List0 string} sorted_lst)
|
||||
in
|
||||
list_vt_free<string> sorted_lst;
|
||||
list_vt_free<string> example_for_sort;
|
||||
cloptr_free ($UN.castvwtp0{cloptr0} compare)
|
||||
end
|
||||
|
||||
implement
|
||||
main0 (argc, argv) =
|
||||
let
|
||||
|
||||
(* Currently there is no demonstration of
|
||||
list_vt_three_way_separation. *)
|
||||
|
||||
val demo_name =
|
||||
begin
|
||||
if 2 <= argc then
|
||||
$UN.cast{string} argv[1]
|
||||
else
|
||||
begin
|
||||
println!
|
||||
("Please choose \"quickselect\" or \"quicksort\".");
|
||||
exit (1)
|
||||
end
|
||||
end : string
|
||||
|
||||
in
|
||||
|
||||
if demo_name = "quickselect" then
|
||||
demonstrate_quickselect ()
|
||||
else if demo_name = "quicksort" then
|
||||
demonstrate_quicksort ()
|
||||
else
|
||||
begin
|
||||
println! ("Please choose \"quickselect\" or \"quicksort\".");
|
||||
exit (1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
PROC Swap(BYTE ARRAY tab INT i,j)
|
||||
BYTE tmp
|
||||
|
||||
tmp=tab(i) tab(i)=tab(j) tab(j)=tmp
|
||||
RETURN
|
||||
|
||||
BYTE FUNC QuickSelect(BYTE ARRAY tab INT count,index)
|
||||
INT px,i,j,k
|
||||
BYTE pv
|
||||
|
||||
DO
|
||||
px=count/2
|
||||
pv=tab(px)
|
||||
Swap(tab,px,count-1)
|
||||
|
||||
i=0
|
||||
FOR j=0 TO count-2
|
||||
DO
|
||||
IF tab(j)<pv THEN
|
||||
Swap(tab,i,j)
|
||||
i==+1
|
||||
FI
|
||||
OD
|
||||
|
||||
IF i=index THEN
|
||||
RETURN (pv)
|
||||
ELSEIF i>index THEN
|
||||
;left part of tab from 0 to i-1
|
||||
count=i
|
||||
ELSE
|
||||
Swap(tab,i,count-1)
|
||||
;right part of tab from i+1 to count-1
|
||||
tab==+(i+1)
|
||||
count==-(i+1)
|
||||
index==-(i+1)
|
||||
FI
|
||||
OD
|
||||
RETURN (0)
|
||||
|
||||
PROC Main()
|
||||
DEFINE COUNT="10"
|
||||
BYTE ARRAY data=[9 8 7 6 5 0 1 2 3 4],tab(COUNT)
|
||||
BYTE i,res
|
||||
|
||||
FOR i=0 TO COUNT-1
|
||||
DO
|
||||
MoveBlock(tab,data,COUNT)
|
||||
res=QuickSelect(tab,COUNT,i)
|
||||
PrintB(res) Put(32)
|
||||
OD
|
||||
RETURN
|
||||
257
Task/Quickselect-algorithm/Ada/quickselect-algorithm.ada
Normal file
257
Task/Quickselect-algorithm/Ada/quickselect-algorithm.ada
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
----------------------------------------------------------------------
|
||||
|
||||
with Ada.Numerics.Float_Random;
|
||||
with Ada.Text_IO;
|
||||
|
||||
procedure quickselect_task
|
||||
is
|
||||
|
||||
use Ada.Numerics.Float_Random;
|
||||
use Ada.Text_IO;
|
||||
|
||||
gen : Generator;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- procedure partition
|
||||
--
|
||||
-- Partitioning a subarray into two halves: one with elements less
|
||||
-- than or equal to a pivot, the other with elements greater than or
|
||||
-- equal to a pivot.
|
||||
--
|
||||
|
||||
generic
|
||||
type T is private;
|
||||
type T_Array is array (Natural range <>) of T;
|
||||
procedure partition
|
||||
(less_than : access function
|
||||
(x, y : T)
|
||||
return Boolean;
|
||||
pivot : in T;
|
||||
i_first, i_last : in Natural;
|
||||
arr : in out T_Array;
|
||||
i_pivot : out Natural);
|
||||
|
||||
procedure partition
|
||||
(less_than : access function
|
||||
(x, y : T)
|
||||
return Boolean;
|
||||
pivot : in T;
|
||||
i_first, i_last : in Natural;
|
||||
arr : in out T_Array;
|
||||
i_pivot : out Natural)
|
||||
is
|
||||
i, j : Integer;
|
||||
temp : T;
|
||||
begin
|
||||
|
||||
i := Integer (i_first) - 1;
|
||||
j := i_last + 1;
|
||||
|
||||
while i /= j loop
|
||||
-- Move i so everything to the left of i is less than or equal
|
||||
-- to the pivot.
|
||||
i := i + 1;
|
||||
while i /= j and then not less_than (pivot, arr (i)) loop
|
||||
i := i + 1;
|
||||
end loop;
|
||||
|
||||
-- Move j so everything to the right of j is greater than or
|
||||
-- equal to the pivot.
|
||||
if i /= j then
|
||||
j := j - 1;
|
||||
while i /= j and then not less_than (arr (j), pivot) loop
|
||||
j := j - 1;
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
-- Swap entries.
|
||||
temp := arr (i);
|
||||
arr (i) := arr (j);
|
||||
arr (j) := temp;
|
||||
end loop;
|
||||
|
||||
i_pivot := i;
|
||||
|
||||
end partition;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- procedure quickselect
|
||||
--
|
||||
-- Quickselect with a random pivot. Returns the (k+1)st element of a
|
||||
-- subarray, according to the given order predicate. Also rearranges
|
||||
-- the subarray so that anything "less than" the (k+1)st element is to
|
||||
-- the left of it, and anything "greater than" it is to its right.
|
||||
--
|
||||
-- I use a random pivot to get O(n) worst case *expected* running
|
||||
-- time. Code using a random pivot is easy to write and read, and for
|
||||
-- most purposes comes close enough to a criterion set by Scheme's
|
||||
-- SRFI-132: "Runs in O(n) time." (See
|
||||
-- https://srfi.schemers.org/srfi-132/srfi-132.html)
|
||||
--
|
||||
-- Of course we are not bound here by SRFI-132, but still I respect
|
||||
-- it as a guide.
|
||||
--
|
||||
-- A "median of medians" pivot gives O(n) running time, but
|
||||
-- quickselect with such a pivot is a complicated algorithm requiring
|
||||
-- many comparisons of array elements. A random number generator, by
|
||||
-- contrast, requires no comparisons of array elements.
|
||||
--
|
||||
|
||||
generic
|
||||
type T is private;
|
||||
type T_Array is array (Natural range <>) of T;
|
||||
procedure quickselect
|
||||
(less_than : access function
|
||||
(x, y : T)
|
||||
return Boolean;
|
||||
i_first, i_last : in Natural;
|
||||
k : in Natural;
|
||||
arr : in out T_Array;
|
||||
the_element : out T;
|
||||
the_elements_index : out Natural);
|
||||
|
||||
procedure quickselect
|
||||
(less_than : access function
|
||||
(x, y : T)
|
||||
return Boolean;
|
||||
i_first, i_last : in Natural;
|
||||
k : in Natural;
|
||||
arr : in out T_Array;
|
||||
the_element : out T;
|
||||
the_elements_index : out Natural)
|
||||
is
|
||||
procedure T_partition is new partition (T, T_Array);
|
||||
|
||||
procedure qselect
|
||||
(less_than : access function
|
||||
(x, y : T)
|
||||
return Boolean;
|
||||
i_first, i_last : in Natural;
|
||||
k : in Natural;
|
||||
arr : in out T_Array;
|
||||
the_element : out T;
|
||||
the_elements_index : out Natural)
|
||||
is
|
||||
i, j : Natural;
|
||||
i_pivot : Natural;
|
||||
i_final : Natural;
|
||||
pivot : T;
|
||||
begin
|
||||
|
||||
i := i_first;
|
||||
j := i_last;
|
||||
|
||||
while i /= j loop
|
||||
i_pivot :=
|
||||
i + Natural (Float'Floor (Random (gen) * Float (j - i + 1)));
|
||||
i_pivot := Natural'Min (j, i_pivot);
|
||||
pivot := arr (i_pivot);
|
||||
|
||||
-- Move the last element to where the pivot had been. Perhaps
|
||||
-- the pivot was already the last element, of course. In any
|
||||
-- case, we shall partition only from i to j - 1.
|
||||
arr (i_pivot) := arr (j);
|
||||
|
||||
-- Partition the array in the range i .. j - 1, leaving out
|
||||
-- the last element (which now can be considered garbage).
|
||||
T_partition (less_than, pivot, i, j - 1, arr, i_final);
|
||||
|
||||
-- Now everything that is less than the pivot is to the left
|
||||
-- of I_final.
|
||||
|
||||
-- Put the pivot at i_final, moving the element that had been
|
||||
-- there to the end. If i_final = j, then this element is
|
||||
-- actually garbage and will be overwritten with the pivot,
|
||||
-- which turns out to be the greatest element. Otherwise, the
|
||||
-- moved element is not less than the pivot and so the
|
||||
-- partitioning is preserved.
|
||||
arr (j) := arr (i_final);
|
||||
arr (i_final) := pivot;
|
||||
|
||||
-- Compare i_final and k, to see what to do next.
|
||||
if i_final < k then
|
||||
i := i_final + 1;
|
||||
elsif k < i_final then
|
||||
j := i_final - 1;
|
||||
else
|
||||
-- Exit the loop.
|
||||
i := i_final;
|
||||
j := i_final;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
the_element := arr (i);
|
||||
the_elements_index := i;
|
||||
|
||||
end qselect;
|
||||
begin
|
||||
-- Adjust k for the subarray's position.
|
||||
qselect
|
||||
(less_than, i_first, i_last, k + i_first, arr, the_element,
|
||||
the_elements_index);
|
||||
end quickselect;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
type Integer_Array is array (Natural range <>) of Integer;
|
||||
|
||||
procedure integer_quickselect is new quickselect
|
||||
(Integer, Integer_Array);
|
||||
|
||||
procedure print_kth
|
||||
(less_than : access function
|
||||
(x, y : Integer)
|
||||
return Boolean;
|
||||
k : in Positive;
|
||||
i_first, i_last : in Integer;
|
||||
arr : in out Integer_Array)
|
||||
is
|
||||
copy_of_arr : Integer_Array (0 .. i_last);
|
||||
the_element : Integer;
|
||||
the_elements_index : Natural;
|
||||
begin
|
||||
for j in 0 .. i_last loop
|
||||
copy_of_arr (j) := arr (j);
|
||||
end loop;
|
||||
integer_quickselect
|
||||
(less_than, i_first, i_last, k - 1, copy_of_arr, the_element,
|
||||
the_elements_index);
|
||||
Put (Integer'Image (the_element));
|
||||
end print_kth;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
example_numbers : Integer_Array := (9, 8, 7, 6, 5, 0, 1, 2, 3, 4);
|
||||
|
||||
function lt
|
||||
(x, y : Integer)
|
||||
return Boolean
|
||||
is
|
||||
begin
|
||||
return (x < y);
|
||||
end lt;
|
||||
|
||||
function gt
|
||||
(x, y : Integer)
|
||||
return Boolean
|
||||
is
|
||||
begin
|
||||
return (x > y);
|
||||
end gt;
|
||||
|
||||
begin
|
||||
Put ("With < as order predicate: ");
|
||||
for k in 1 .. 10 loop
|
||||
print_kth (lt'Access, k, 0, 9, example_numbers);
|
||||
end loop;
|
||||
Put_Line ("");
|
||||
Put ("With > as order predicate: ");
|
||||
for k in 1 .. 10 loop
|
||||
print_kth (gt'Access, k, 0, 9, example_numbers);
|
||||
end loop;
|
||||
Put_Line ("");
|
||||
end quickselect_task;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
on quickselect(theList, l, r, k)
|
||||
script o
|
||||
property lst : theList's items -- Shallow copy.
|
||||
end script
|
||||
|
||||
repeat
|
||||
-- Median-of-3 pivot selection.
|
||||
set leftValue to item l of o's lst
|
||||
set rightValue to item r of o's lst
|
||||
set pivot to item ((l + r) div 2) of o's lst
|
||||
set leftGreaterThanRight to (leftValue > rightValue)
|
||||
if (leftValue > pivot) then
|
||||
if (leftGreaterThanRight) then
|
||||
if (rightValue > pivot) then set pivot to rightValue
|
||||
else
|
||||
set pivot to leftValue
|
||||
end if
|
||||
else if (pivot > rightValue) then
|
||||
if (leftGreaterThanRight) then
|
||||
set pivot to leftValue
|
||||
else
|
||||
set pivot to rightValue
|
||||
end if
|
||||
end if
|
||||
|
||||
-- Initialise pivot store indices and swap the already compared outer values here if necessary.
|
||||
set pLeft to l - 1
|
||||
set pRight to r + 1
|
||||
if (leftGreaterThanRight) then
|
||||
set item r of o's lst to leftValue
|
||||
set item l of o's lst to rightValue
|
||||
if (leftValue = pivot) then
|
||||
set pRight to r
|
||||
else if (rightValue = pivot) then
|
||||
set pLeft to l
|
||||
end if
|
||||
else
|
||||
if (leftValue = pivot) then set pLeft to l
|
||||
if (rightValue = pivot) then set pRight to r
|
||||
end if
|
||||
|
||||
-- Continue three-way partitioning.
|
||||
set i to l + 1
|
||||
set j to r - 1
|
||||
repeat until (i > j)
|
||||
set leftValue to item i of o's lst
|
||||
repeat while (leftValue < pivot)
|
||||
set i to i + 1
|
||||
set leftValue to item i of o's lst
|
||||
end repeat
|
||||
|
||||
set rightValue to item j of o's lst
|
||||
repeat while (rightValue > pivot)
|
||||
set j to j - 1
|
||||
set rightValue to item j of o's lst
|
||||
end repeat
|
||||
|
||||
if (j > i) then
|
||||
if (leftValue = pivot) then
|
||||
set pRight to pRight - 1
|
||||
if (pRight > j) then
|
||||
set leftValue to item pRight of o's lst
|
||||
set item pRight of o's lst to pivot
|
||||
end if
|
||||
end if
|
||||
if (rightValue = pivot) then
|
||||
set pLeft to pLeft + 1
|
||||
if (pLeft < i) then
|
||||
set rightValue to item pLeft of o's lst
|
||||
set item pLeft of o's lst to pivot
|
||||
end if
|
||||
end if
|
||||
set item j of o's lst to leftValue
|
||||
set item i of o's lst to rightValue
|
||||
else if (i > j) then
|
||||
exit repeat
|
||||
end if
|
||||
|
||||
set i to i + 1
|
||||
set j to j - 1
|
||||
end repeat
|
||||
-- Swap stored pivot(s) into a central partition.
|
||||
repeat with p from l to pLeft
|
||||
if (j > pLeft) then
|
||||
set item p of o's lst to item j of o's lst
|
||||
set item j of o's lst to pivot
|
||||
set j to j - 1
|
||||
else
|
||||
set j to p - 1
|
||||
exit repeat
|
||||
end if
|
||||
end repeat
|
||||
repeat with p from r to pRight by -1
|
||||
if (i < pRight) then
|
||||
set item p of o's lst to item i of o's lst
|
||||
set item i of o's lst to pivot
|
||||
set i to i + 1
|
||||
else
|
||||
set i to p + 1
|
||||
exit repeat
|
||||
end if
|
||||
end repeat
|
||||
|
||||
-- If k's in either of the outer partitions, repeat for that partition. Othewise return the item in slot k.
|
||||
if (k ≥ i) then
|
||||
set l to i
|
||||
else if (k ≤ j) then
|
||||
set r to j
|
||||
else
|
||||
return item k of o's lst
|
||||
end if
|
||||
end repeat
|
||||
end quickselect
|
||||
|
||||
-- Task code:
|
||||
set theVector to {9, 8, 7, 6, 5, 0, 1, 2, 3, 4}
|
||||
set selected to {}
|
||||
set vectorLength to (count theVector)
|
||||
repeat with i from 1 to vectorLength
|
||||
set end of selected to quickselect(theVector, 1, vectorLength, i)
|
||||
end repeat
|
||||
return selected
|
||||
|
|
@ -0,0 +1 @@
|
|||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
----------------------- QUICKSELECT ------------------------
|
||||
|
||||
-- quickSelect :: Ord a => [a] -> Int -> a
|
||||
on quickSelect(xxs)
|
||||
script
|
||||
on |λ|(k)
|
||||
script go
|
||||
on |λ|(xxs, k)
|
||||
set {x, xs} to {item 1 of xxs, rest of xxs}
|
||||
set {ys, zs} to partition(gt(x), xs)
|
||||
|
||||
set lng to length of ys
|
||||
if k < lng then
|
||||
|λ|(ys, k)
|
||||
else
|
||||
if k > lng then
|
||||
|λ|(zs, k - lng - 1)
|
||||
else
|
||||
x
|
||||
end if
|
||||
end if
|
||||
end |λ|
|
||||
end script
|
||||
if 0 ≤ k and k < length of xxs then
|
||||
tell go to |λ|(xxs, k)
|
||||
else
|
||||
missing value
|
||||
end if
|
||||
end |λ|
|
||||
end script
|
||||
end quickSelect
|
||||
|
||||
|
||||
--------------------------- TEST ---------------------------
|
||||
on run
|
||||
set xs to {9, 8, 7, 6, 5, 0, 1, 2, 3, 4}
|
||||
map(quickSelect(xs), enumFromTo(0, (length of xs) - 1))
|
||||
end run
|
||||
|
||||
|
||||
----------- GENERAL AND REUSABLE PURE FUNCTIONS ------------
|
||||
|
||||
-- enumFromTo :: Int -> Int -> [Int]
|
||||
on enumFromTo(m, n)
|
||||
if m ≤ n then
|
||||
set lst to {}
|
||||
repeat with i from m to n
|
||||
set end of lst to i
|
||||
end repeat
|
||||
lst
|
||||
else
|
||||
{}
|
||||
end if
|
||||
end enumFromTo
|
||||
|
||||
|
||||
-- gt :: Ord a => a -> a -> Bool
|
||||
on gt(x)
|
||||
script
|
||||
on |λ|(y)
|
||||
x > y
|
||||
end |λ|
|
||||
end script
|
||||
end gt
|
||||
|
||||
|
||||
-- map :: (a -> b) -> [a] -> [b]
|
||||
on map(f, xs)
|
||||
-- The list obtained by applying f
|
||||
-- to each element of xs.
|
||||
tell mReturn(f)
|
||||
set lng to length of xs
|
||||
set lst to {}
|
||||
repeat with i from 1 to lng
|
||||
set end of lst to |λ|(item i of xs, i, xs)
|
||||
end repeat
|
||||
return lst
|
||||
end tell
|
||||
end map
|
||||
|
||||
|
||||
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
|
||||
on mReturn(f)
|
||||
-- 2nd class handler function lifted into 1st class script wrapper.
|
||||
if script is class of f then
|
||||
f
|
||||
else
|
||||
script
|
||||
property |λ| : f
|
||||
end script
|
||||
end if
|
||||
end mReturn
|
||||
|
||||
|
||||
-- partition :: (a -> Bool) -> [a] -> ([a], [a])
|
||||
on partition(p, xs)
|
||||
tell mReturn(p)
|
||||
set {ys, zs} to {{}, {}}
|
||||
repeat with x in xs
|
||||
set v to contents of x
|
||||
if |λ|(v) then
|
||||
set end of ys to v
|
||||
else
|
||||
set end of zs to v
|
||||
end if
|
||||
end repeat
|
||||
end tell
|
||||
{ys, zs}
|
||||
end partition
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
quickselect: function [a k][
|
||||
arr: new a
|
||||
while ø [
|
||||
indx: random 0 (size arr)-1
|
||||
pivot: arr\[indx]
|
||||
remove 'arr .index indx
|
||||
left: select arr 'item -> item<pivot
|
||||
right: select arr 'item -> item>pivot
|
||||
|
||||
case [k]
|
||||
when? [= size left]-> return pivot
|
||||
when? [< size left]-> arr: new left
|
||||
else [
|
||||
k: (k - size left) - 1
|
||||
arr: new right
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
v: [9 8 7 6 5 0 1 2 3 4]
|
||||
|
||||
print map 0..(size v)-1 'i ->
|
||||
quickselect v i
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
MyList := [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
Loop, 10
|
||||
Out .= Select(MyList, 1, MyList.MaxIndex(), A_Index) (A_Index = MyList.MaxIndex() ? "" : ", ")
|
||||
MsgBox, % Out
|
||||
return
|
||||
|
||||
Partition(List, Left, Right, PivotIndex) {
|
||||
PivotValue := List[PivotIndex]
|
||||
, Swap(List, pivotIndex, Right)
|
||||
, StoreIndex := Left
|
||||
, i := Left - 1
|
||||
Loop, % Right - Left
|
||||
if (List[j := i + A_Index] <= PivotValue)
|
||||
Swap(List, StoreIndex, j)
|
||||
, StoreIndex++
|
||||
Swap(List, Right, StoreIndex)
|
||||
return StoreIndex
|
||||
}
|
||||
|
||||
Select(List, Left, Right, n) {
|
||||
if (Left = Right)
|
||||
return List[Left]
|
||||
Loop {
|
||||
PivotIndex := (Left + Right) // 2
|
||||
, PivotIndex := Partition(List, Left, Right, PivotIndex)
|
||||
if (n = PivotIndex)
|
||||
return List[n]
|
||||
else if (n < PivotIndex)
|
||||
Right := PivotIndex - 1
|
||||
else
|
||||
Left := PivotIndex + 1
|
||||
}
|
||||
}
|
||||
|
||||
Swap(List, i1, i2) {
|
||||
t := List[i1]
|
||||
, List[i1] := List[i2]
|
||||
, List[i2] := t
|
||||
}
|
||||
14
Task/Quickselect-algorithm/C++/quickselect-algorithm-1.cpp
Normal file
14
Task/Quickselect-algorithm/C++/quickselect-algorithm-1.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int a[] = {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
|
||||
std::nth_element(a, a + i, a + sizeof(a)/sizeof(*a));
|
||||
std::cout << a[i];
|
||||
if (i < 9) std::cout << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
37
Task/Quickselect-algorithm/C++/quickselect-algorithm-2.cpp
Normal file
37
Task/Quickselect-algorithm/C++/quickselect-algorithm-2.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
template <typename Iterator>
|
||||
Iterator select(Iterator begin, Iterator end, int n) {
|
||||
typedef typename std::iterator_traits<Iterator>::value_type T;
|
||||
while (true) {
|
||||
Iterator pivotIt = begin + std::rand() % std::distance(begin, end);
|
||||
std::iter_swap(pivotIt, end-1); // Move pivot to end
|
||||
pivotIt = std::partition(begin, end-1, std::bind2nd(std::less<T>(), *(end-1)));
|
||||
std::iter_swap(end-1, pivotIt); // Move pivot to its final place
|
||||
if (n == pivotIt - begin) {
|
||||
return pivotIt;
|
||||
} else if (n < pivotIt - begin) {
|
||||
end = pivotIt;
|
||||
} else {
|
||||
n -= pivotIt+1 - begin;
|
||||
begin = pivotIt+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::srand(std::time(NULL));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int a[] = {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
|
||||
std::cout << *select(a, a + sizeof(a)/sizeof(*a), i);
|
||||
if (i < 9) std::cout << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
173
Task/Quickselect-algorithm/C-sharp/quickselect-algorithm.cs
Normal file
173
Task/Quickselect-algorithm/C-sharp/quickselect-algorithm.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// ----------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Program.cs - QuickSelect
|
||||
//
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuickSelect
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
#region Static Members
|
||||
|
||||
private static void Main()
|
||||
{
|
||||
var inputArray = new[] {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
|
||||
// Loop 10 times
|
||||
Console.WriteLine( "Loop quick select 10 times." );
|
||||
for( var i = 0 ; i < 10 ; i++ )
|
||||
{
|
||||
Console.Write( inputArray.NthSmallestElement( i ) );
|
||||
if( i < 9 )
|
||||
Console.Write( ", " );
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
// And here is then more effective way to get N smallest elements from vector in order by using quick select algorithm
|
||||
// Basically we are here just sorting array (taking 10 smallest from array which length is 10)
|
||||
Console.WriteLine( "Just sort 10 elements." );
|
||||
Console.WriteLine( string.Join( ", ", inputArray.TakeSmallest( 10 ).OrderBy( v => v ).Select( v => v.ToString() ).ToArray() ) );
|
||||
// Here we are actually doing quick select once by taking only 4 smallest from array.
|
||||
Console.WriteLine( "Get 4 smallest and sort them." );
|
||||
Console.WriteLine( string.Join( ", ", inputArray.TakeSmallest( 4 ).OrderBy( v => v ).Select( v => v.ToString() ).ToArray() ) );
|
||||
Console.WriteLine( "< Press any key >" );
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal static class ArrayExtension
|
||||
{
|
||||
#region Static Members
|
||||
|
||||
/// <summary>
|
||||
/// Return specified number of smallest elements from array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
|
||||
/// <param name="array">The array to return elemnts from.</param>
|
||||
/// <param name="count">The number of smallest elements to return. </param>
|
||||
/// <returns>An IEnumerable(T) that contains the specified number of smallest elements of the input array. Returned elements are NOT sorted.</returns>
|
||||
public static IEnumerable<T> TakeSmallest<T>( this T[] array, int count ) where T : IComparable<T>
|
||||
{
|
||||
if( count < 0 )
|
||||
throw new ArgumentOutOfRangeException( "count", "Count is smaller than 0." );
|
||||
if( count == 0 )
|
||||
return new T[0];
|
||||
if( array.Length <= count )
|
||||
return array;
|
||||
|
||||
return QuickSelectSmallest( array, count - 1 ).Take( count );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns N:th smallest element from the array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
|
||||
/// <param name="array">The array to return elemnt from.</param>
|
||||
/// <param name="n">Nth element. 0 is smallest element, when array.Length - 1 is largest element.</param>
|
||||
/// <returns>N:th smalles element from the array.</returns>
|
||||
public static T NthSmallestElement<T>( this T[] array, int n ) where T : IComparable<T>
|
||||
{
|
||||
if( n < 0 || n > array.Length - 1 )
|
||||
throw new ArgumentOutOfRangeException( "n", n, string.Format( "n should be between 0 and {0} it was {1}.", array.Length - 1, n ) );
|
||||
if( array.Length == 0 )
|
||||
throw new ArgumentException( "Array is empty.", "array" );
|
||||
if( array.Length == 1 )
|
||||
return array[ 0 ];
|
||||
|
||||
return QuickSelectSmallest( array, n )[ n ];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partially sort array such way that elements before index position n are smaller or equal than elemnt at position n. And elements after n are larger or equal.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
|
||||
/// <param name="input">The array which elements are being partially sorted. This array is not modified.</param>
|
||||
/// <param name="n">Nth smallest element.</param>
|
||||
/// <returns>Partially sorted array.</returns>
|
||||
private static T[] QuickSelectSmallest<T>( T[] input, int n ) where T : IComparable<T>
|
||||
{
|
||||
// Let's not mess up with our input array
|
||||
// For very large arrays - we should optimize this somehow - or just mess up with our input
|
||||
var partiallySortedArray = (T[]) input.Clone();
|
||||
|
||||
// Initially we are going to execute quick select to entire array
|
||||
var startIndex = 0;
|
||||
var endIndex = input.Length - 1;
|
||||
|
||||
// Selecting initial pivot
|
||||
// Maybe we are lucky and array is sorted initially?
|
||||
var pivotIndex = n;
|
||||
|
||||
// Loop until there is nothing to loop (this actually shouldn't happen - we should find our value before we run out of values)
|
||||
var r = new Random();
|
||||
while( endIndex > startIndex )
|
||||
{
|
||||
pivotIndex = QuickSelectPartition( partiallySortedArray, startIndex, endIndex, pivotIndex );
|
||||
if( pivotIndex == n )
|
||||
// We found our n:th smallest value - it is stored to pivot index
|
||||
break;
|
||||
if( pivotIndex > n )
|
||||
// Array before our pivot index have more elements that we are looking for
|
||||
endIndex = pivotIndex - 1;
|
||||
else
|
||||
// Array before our pivot index has less elements that we are looking for
|
||||
startIndex = pivotIndex + 1;
|
||||
|
||||
// Omnipotent beings don't need to roll dices - but we do...
|
||||
// Randomly select a new pivot index between end and start indexes (there are other methods, this is just most brutal and simplest)
|
||||
pivotIndex = r.Next( startIndex, endIndex );
|
||||
}
|
||||
return partiallySortedArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort elements in sub array between startIndex and endIndex, such way that elements smaller than or equal with value initially stored to pivot index are before
|
||||
/// new returned pivot value index.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
|
||||
/// <param name="array">The array that is being sorted.</param>
|
||||
/// <param name="startIndex">Start index of sub array.</param>
|
||||
/// <param name="endIndex">End index of sub array.</param>
|
||||
/// <param name="pivotIndex">Pivot index.</param>
|
||||
/// <returns>New pivot index. Value that was initially stored to <paramref name="pivotIndex"/> is stored to this newly returned index. All elements before this index are
|
||||
/// either smaller or equal with pivot value. All elements after this index are larger than pivot value.</returns>
|
||||
/// <remarks>This method modifies paremater array.</remarks>
|
||||
private static int QuickSelectPartition<T>( this T[] array, int startIndex, int endIndex, int pivotIndex ) where T : IComparable<T>
|
||||
{
|
||||
var pivotValue = array[ pivotIndex ];
|
||||
// Initially we just assume that value in pivot index is largest - so we move it to end (makes also for loop more straight forward)
|
||||
array.Swap( pivotIndex, endIndex );
|
||||
for( var i = startIndex ; i < endIndex ; i++ )
|
||||
{
|
||||
if( array[ i ].CompareTo( pivotValue ) > 0 )
|
||||
continue;
|
||||
|
||||
// Value stored to i was smaller than or equal with pivot value - let's move it to start
|
||||
array.Swap( i, startIndex );
|
||||
// Move start one index forward
|
||||
startIndex++;
|
||||
}
|
||||
// Start index is now pointing to index where we should store our pivot value from end of array
|
||||
array.Swap( endIndex, startIndex );
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
private static void Swap<T>( this T[] array, int index1, int index2 )
|
||||
{
|
||||
if( index1 == index2 )
|
||||
return;
|
||||
|
||||
var temp = array[ index1 ];
|
||||
array[ index1 ] = array[ index2 ];
|
||||
array[ index2 ] = temp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
35
Task/Quickselect-algorithm/C/quickselect-algorithm.c
Normal file
35
Task/Quickselect-algorithm/C/quickselect-algorithm.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int qselect(int *v, int len, int k)
|
||||
{
|
||||
# define SWAP(a, b) { tmp = v[a]; v[a] = v[b]; v[b] = tmp; }
|
||||
int i, st, tmp;
|
||||
|
||||
for (st = i = 0; i < len - 1; i++) {
|
||||
if (v[i] > v[len-1]) continue;
|
||||
SWAP(i, st);
|
||||
st++;
|
||||
}
|
||||
|
||||
SWAP(len-1, st);
|
||||
|
||||
return k == st ?v[st]
|
||||
:st > k ? qselect(v, st, k)
|
||||
: qselect(v + st, len - st, k - st);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
# define N (sizeof(x)/sizeof(x[0]))
|
||||
int x[] = {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
|
||||
int y[N];
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
memcpy(y, x, sizeof(x)); // qselect modifies array
|
||||
printf("%d: %d\n", i, qselect(y, 10, i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
56
Task/Quickselect-algorithm/CLU/quickselect-algorithm.clu
Normal file
56
Task/Quickselect-algorithm/CLU/quickselect-algorithm.clu
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
quick = cluster [T: type] is select
|
||||
where T has lt: proctype (T,T) returns (bool)
|
||||
aT = array[T]
|
||||
sT = sequence[T]
|
||||
rep = null
|
||||
|
||||
swap = proc (list: aT, a, b: int)
|
||||
temp: T := list[a]
|
||||
list[a] := list[b]
|
||||
list[b] := temp
|
||||
end swap
|
||||
|
||||
partition = proc (list: aT, left, right, pivotIndex: int) returns (int)
|
||||
pivotValue: T := list[pivotIndex]
|
||||
swap(list, pivotIndex, right)
|
||||
storeIndex: int := left
|
||||
for i: int in int$from_to(left, right-1) do
|
||||
if list[i] < pivotValue then
|
||||
swap(list, storeIndex, i)
|
||||
storeIndex := storeIndex + 1
|
||||
end
|
||||
end
|
||||
swap(list, right, storeIndex)
|
||||
return(storeIndex)
|
||||
end partition
|
||||
|
||||
_select = proc (list: aT, left, right, k: int) returns (T)
|
||||
if left = right then
|
||||
return(list[left])
|
||||
end
|
||||
|
||||
pivotIndex: int := left + (right - left + 1) / 2
|
||||
pivotIndex := partition(list, left, right, pivotIndex)
|
||||
if k = pivotIndex then
|
||||
return(list[k])
|
||||
elseif k < pivotIndex then
|
||||
return(_select(list, left, pivotIndex-1, k))
|
||||
else
|
||||
return(_select(list, pivotIndex + 1, right, k))
|
||||
end
|
||||
end _select
|
||||
|
||||
select = proc (list: sT, k: int) returns (T)
|
||||
return(_select(sT$s2a(list), 1, sT$size(list), k))
|
||||
end select
|
||||
end quick
|
||||
|
||||
start_up = proc ()
|
||||
po: stream := stream$primary_output()
|
||||
vec: sequence[int] := sequence[int]$[9,8,7,6,5,0,1,2,3,4]
|
||||
|
||||
for k: int in int$from_to(1, 10) do
|
||||
item: int := quick[int]$select(vec, k)
|
||||
stream$putl(po, int$unparse(k) || ": " || int$unparse(item))
|
||||
end
|
||||
end start_up
|
||||
95
Task/Quickselect-algorithm/COBOL/quickselect-algorithm.cobol
Normal file
95
Task/Quickselect-algorithm/COBOL/quickselect-algorithm.cobol
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
CLASS-ID MainProgram.
|
||||
|
||||
METHOD-ID Partition STATIC USING T.
|
||||
CONSTRAINTS.
|
||||
CONSTRAIN T IMPLEMENTS type IComparable.
|
||||
|
||||
DATA DIVISION.
|
||||
LOCAL-STORAGE SECTION.
|
||||
01 pivot-val T.
|
||||
|
||||
PROCEDURE DIVISION USING VALUE arr AS T OCCURS ANY,
|
||||
left-idx AS BINARY-LONG, right-idx AS BINARY-LONG,
|
||||
pivot-idx AS BINARY-LONG
|
||||
RETURNING ret AS BINARY-LONG.
|
||||
MOVE arr (pivot-idx) TO pivot-val
|
||||
INVOKE self::Swap(arr, pivot-idx, right-idx)
|
||||
DECLARE store-idx AS BINARY-LONG = left-idx
|
||||
PERFORM VARYING i AS BINARY-LONG FROM left-idx BY 1
|
||||
UNTIL i > right-idx
|
||||
IF arr (i) < pivot-val
|
||||
INVOKE self::Swap(arr, i, store-idx)
|
||||
ADD 1 TO store-idx
|
||||
END-IF
|
||||
END-PERFORM
|
||||
INVOKE self::Swap(arr, right-idx, store-idx)
|
||||
|
||||
MOVE store-idx TO ret
|
||||
END METHOD.
|
||||
|
||||
METHOD-ID Quickselect STATIC USING T.
|
||||
CONSTRAINTS.
|
||||
CONSTRAIN T IMPLEMENTS type IComparable.
|
||||
|
||||
PROCEDURE DIVISION USING VALUE arr AS T OCCURS ANY,
|
||||
left-idx AS BINARY-LONG, right-idx AS BINARY-LONG,
|
||||
n AS BINARY-LONG
|
||||
RETURNING ret AS T.
|
||||
IF left-idx = right-idx
|
||||
MOVE arr (left-idx) TO ret
|
||||
GOBACK
|
||||
END-IF
|
||||
|
||||
DECLARE rand AS TYPE Random = NEW Random()
|
||||
DECLARE pivot-idx AS BINARY-LONG = rand::Next(left-idx, right-idx)
|
||||
DECLARE pivot-new-idx AS BINARY-LONG
|
||||
= self::Partition(arr, left-idx, right-idx, pivot-idx)
|
||||
DECLARE pivot-dist AS BINARY-LONG = pivot-new-idx - left-idx + 1
|
||||
|
||||
EVALUATE TRUE
|
||||
WHEN pivot-dist = n
|
||||
MOVE arr (pivot-new-idx) TO ret
|
||||
|
||||
WHEN n < pivot-dist
|
||||
INVOKE self::Quickselect(arr, left-idx, pivot-new-idx - 1, n)
|
||||
RETURNING ret
|
||||
|
||||
WHEN OTHER
|
||||
INVOKE self::Quickselect(arr, pivot-new-idx + 1, right-idx,
|
||||
n - pivot-dist) RETURNING ret
|
||||
END-EVALUATE
|
||||
END METHOD.
|
||||
|
||||
METHOD-ID Swap STATIC USING T.
|
||||
CONSTRAINTS.
|
||||
CONSTRAIN T IMPLEMENTS type IComparable.
|
||||
|
||||
DATA DIVISION.
|
||||
LOCAL-STORAGE SECTION.
|
||||
01 temp T.
|
||||
|
||||
PROCEDURE DIVISION USING arr AS T OCCURS ANY,
|
||||
VALUE idx-1 AS BINARY-LONG, idx-2 AS BINARY-LONG.
|
||||
IF idx-1 <> idx-2
|
||||
MOVE arr (idx-1) TO temp
|
||||
MOVE arr (idx-2) TO arr (idx-1)
|
||||
MOVE temp TO arr (idx-2)
|
||||
END-IF
|
||||
END METHOD.
|
||||
|
||||
METHOD-ID Main STATIC.
|
||||
PROCEDURE DIVISION.
|
||||
DECLARE input-array AS BINARY-LONG OCCURS ANY
|
||||
= TABLE OF BINARY-LONG(9, 8, 7, 6, 5, 0, 1, 2, 3, 4)
|
||||
DISPLAY "Loop quick select 10 times."
|
||||
PERFORM VARYING i AS BINARY-LONG FROM 1 BY 1 UNTIL i > 10
|
||||
DISPLAY self::Quickselect(input-array, 1, input-array::Length, i)
|
||||
NO ADVANCING
|
||||
|
||||
IF i < 10
|
||||
DISPLAY ", " NO ADVANCING
|
||||
END-IF
|
||||
END-PERFORM
|
||||
DISPLAY SPACE
|
||||
END METHOD.
|
||||
END CLASS.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
(defun quickselect (n _list)
|
||||
(let* ((ys (remove-if (lambda (x) (< (car _list) x)) (cdr _list)))
|
||||
(zs (remove-if-not (lambda (x) (< (car _list) x)) (cdr _list)))
|
||||
(l (length ys))
|
||||
)
|
||||
(cond ((< n l) (quickselect n ys))
|
||||
((> n l) (quickselect (- n l 1) zs))
|
||||
(t (car _list)))
|
||||
)
|
||||
)
|
||||
|
||||
(defparameter a '(9 8 7 6 5 0 1 2 3 4))
|
||||
(format t "~a~&" (mapcar (lambda (x) (quickselect x a)) (loop for i from 0 below (length a) collect i)))
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
def quickselect(a, k)
|
||||
arr = a.dup # we will be modifying it
|
||||
loop do
|
||||
pivot = arr.delete_at(rand(arr.size))
|
||||
left, right = arr.partition { |x| x < pivot }
|
||||
if k == left.size
|
||||
return pivot
|
||||
elsif k < left.size
|
||||
arr = left
|
||||
else
|
||||
k = k - left.size - 1
|
||||
arr = right
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
p v.each_index.map { |i| quickselect(v, i) }.to_a
|
||||
9
Task/Quickselect-algorithm/D/quickselect-algorithm-1.d
Normal file
9
Task/Quickselect-algorithm/D/quickselect-algorithm-1.d
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
void main() {
|
||||
import std.stdio, std.algorithm;
|
||||
|
||||
auto a = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
foreach (immutable i; 0 .. a.length) {
|
||||
a.topN(i);
|
||||
write(a[i], " ");
|
||||
}
|
||||
}
|
||||
48
Task/Quickselect-algorithm/D/quickselect-algorithm-2.d
Normal file
48
Task/Quickselect-algorithm/D/quickselect-algorithm-2.d
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import std.stdio, std.random, std.algorithm, std.range;
|
||||
|
||||
T quickSelect(T)(T[] arr, size_t n)
|
||||
in {
|
||||
assert(n < arr.length);
|
||||
} body {
|
||||
static size_t partition(T[] sub, in size_t pivot) pure nothrow
|
||||
in {
|
||||
assert(!sub.empty);
|
||||
assert(pivot < sub.length);
|
||||
} body {
|
||||
auto pivotVal = sub[pivot];
|
||||
sub[pivot].swap(sub.back);
|
||||
size_t storeIndex = 0;
|
||||
foreach (ref si; sub[0 .. $ - 1]) {
|
||||
if (si < pivotVal) {
|
||||
si.swap(sub[storeIndex]);
|
||||
storeIndex++;
|
||||
}
|
||||
}
|
||||
sub.back.swap(sub[storeIndex]);
|
||||
return storeIndex;
|
||||
}
|
||||
|
||||
size_t left = 0;
|
||||
size_t right = arr.length - 1;
|
||||
while (right > left) {
|
||||
assert(left < arr.length);
|
||||
assert(right < arr.length);
|
||||
immutable pivotIndex = left + partition(arr[left .. right + 1],
|
||||
uniform(0U, right - left + 1));
|
||||
if (pivotIndex - left == n) {
|
||||
right = left = pivotIndex;
|
||||
} else if (pivotIndex - left < n) {
|
||||
n -= pivotIndex - left + 1;
|
||||
left = pivotIndex + 1;
|
||||
} else {
|
||||
right = pivotIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return arr[left];
|
||||
}
|
||||
|
||||
void main() {
|
||||
auto a = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
a.length.iota.map!(i => a.quickSelect(i)).writeln;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
program Quickselect_algorithm;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
System.SysUtils;
|
||||
|
||||
function quickselect(list: TArray<Integer>; k: Integer): Integer;
|
||||
|
||||
procedure Swap(i, j: Integer);
|
||||
var
|
||||
tmp: Integer;
|
||||
begin
|
||||
tmp := list[i];
|
||||
list[i] := list[j];
|
||||
list[j] := tmp;
|
||||
end;
|
||||
|
||||
begin
|
||||
repeat
|
||||
var px := length(list) div 2;
|
||||
var pv := list[px];
|
||||
var last := length(list) - 1;
|
||||
|
||||
Swap(px, last);
|
||||
var i := 0;
|
||||
for var j := 0 to last - 1 do
|
||||
if list[j] < pv then
|
||||
begin
|
||||
swap(i, j);
|
||||
inc(i);
|
||||
end;
|
||||
|
||||
if i = k then
|
||||
exit(pv);
|
||||
|
||||
if k < i then
|
||||
delete(list, i, length(list))
|
||||
else
|
||||
begin
|
||||
Swap(i, last);
|
||||
delete(list, 0, i + 1);
|
||||
dec(k, i + 1);
|
||||
end;
|
||||
until false;
|
||||
end;
|
||||
|
||||
begin
|
||||
var i := 0;
|
||||
|
||||
while True do
|
||||
begin
|
||||
var v: TArray<Integer> := [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
if i = length(v) then
|
||||
Break;
|
||||
Writeln(quickselect(v, i));
|
||||
inc(i);
|
||||
end;
|
||||
Readln;
|
||||
end.
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
proc qselect k . list[] res .
|
||||
#
|
||||
subr partition
|
||||
mid = left
|
||||
for i = left + 1 to right
|
||||
if list[i] < list[left]
|
||||
mid += 1
|
||||
swap list[i] list[mid]
|
||||
.
|
||||
.
|
||||
swap list[left] list[mid]
|
||||
.
|
||||
left = 1
|
||||
right = len list[]
|
||||
while left < right
|
||||
call partition
|
||||
if mid < k
|
||||
left = mid + 1
|
||||
elif mid > k
|
||||
right = mid - 1
|
||||
else
|
||||
left = right
|
||||
.
|
||||
.
|
||||
res = list[k]
|
||||
.
|
||||
d[] = [ 9 8 7 6 5 0 1 2 3 4 ]
|
||||
for i = 1 to len d[]
|
||||
call qselect i d[] r
|
||||
print r
|
||||
.
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Quick do
|
||||
def select(k, [x|xs]) do
|
||||
{ys, zs} = Enum.partition(xs, fn e -> e < x end)
|
||||
l = length(ys)
|
||||
cond do
|
||||
k < l -> select(k, ys)
|
||||
k > l -> select(k - l - 1, zs)
|
||||
true -> x
|
||||
end
|
||||
end
|
||||
|
||||
def test do
|
||||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
Enum.map(0..length(v)-1, fn i -> select(i,v) end)
|
||||
|> IO.inspect
|
||||
end
|
||||
end
|
||||
|
||||
Quick.test
|
||||
24
Task/Quickselect-algorithm/Erlang/quickselect-algorithm.erl
Normal file
24
Task/Quickselect-algorithm/Erlang/quickselect-algorithm.erl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-module(quickselect).
|
||||
|
||||
-export([test/0]).
|
||||
|
||||
|
||||
test() ->
|
||||
V = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4],
|
||||
lists:map(
|
||||
fun(I) -> quickselect(I,V) end,
|
||||
lists:seq(0, length(V) - 1)
|
||||
).
|
||||
|
||||
quickselect(K, [X | Xs]) ->
|
||||
{Ys, Zs} =
|
||||
lists:partition(fun(E) -> E < X end, Xs),
|
||||
L = length(Ys),
|
||||
if
|
||||
K < L ->
|
||||
quickselect(K, Ys);
|
||||
K > L ->
|
||||
quickselect(K - L - 1, Zs);
|
||||
true ->
|
||||
X
|
||||
end.
|
||||
17
Task/Quickselect-algorithm/F-Sharp/quickselect-algorithm.fs
Normal file
17
Task/Quickselect-algorithm/F-Sharp/quickselect-algorithm.fs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
let rec quickselect k list =
|
||||
match list with
|
||||
| [] -> failwith "Cannot take largest element of empty list."
|
||||
| [a] -> a
|
||||
| x::xs ->
|
||||
let (ys, zs) = List.partition (fun arg -> arg < x) xs
|
||||
let l = List.length ys
|
||||
if k < l then quickselect k ys
|
||||
elif k > l then quickselect (k-l-1) zs
|
||||
else x
|
||||
//end quickselect
|
||||
|
||||
[<EntryPoint>]
|
||||
let main args =
|
||||
let v = [9; 8; 7; 6; 5; 0; 1; 2; 3; 4]
|
||||
printfn "%A" [for i in 0..(List.length v - 1) -> quickselect i v]
|
||||
0
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
USING: combinators kernel make math locals prettyprint sequences ;
|
||||
IN: rosetta-code.quickselect
|
||||
|
||||
:: quickselect ( k seq -- n )
|
||||
seq unclip :> ( xs x )
|
||||
xs [ x < ] partition :> ( ys zs )
|
||||
ys length :> l
|
||||
{
|
||||
{ [ k l < ] [ k ys quickselect ] }
|
||||
{ [ k l > ] [ k l - 1 - zs quickselect ] }
|
||||
[ x ]
|
||||
} cond ;
|
||||
|
||||
: quickselect-demo ( -- )
|
||||
{ 9 8 7 6 5 0 1 2 3 4 } dup length <iota> swap
|
||||
[ [ quickselect , ] curry each ] { } make . ;
|
||||
|
||||
MAIN: quickselect-demo
|
||||
51
Task/Quickselect-algorithm/Fortran/quickselect-algorithm.f
Normal file
51
Task/Quickselect-algorithm/Fortran/quickselect-algorithm.f
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
INTEGER FUNCTION FINDELEMENT(K,A,N) !I know I can.
|
||||
Chase an order statistic: FindElement(N/2,A,N) leads to the median, with some odd/even caution.
|
||||
Careful! The array is shuffled: for i < K, A(i) <= A(K); for i > K, A(i) >= A(K).
|
||||
Charles Anthony Richard Hoare devised this method, as related to his famous QuickSort.
|
||||
INTEGER K,N !Find the K'th element in order of an array of N elements, not necessarily in order.
|
||||
INTEGER A(N),HOPE,PESTY !The array, and like associates.
|
||||
INTEGER L,R,L2,R2 !Fingers.
|
||||
L = 1 !Here we go.
|
||||
R = N !The bounds of the work area within which the K'th element lurks.
|
||||
DO WHILE (L .LT. R) !So, keep going until it is clamped.
|
||||
HOPE = A(K) !If array A is sorted, this will be rewarded.
|
||||
L2 = L !But it probably isn't sorted.
|
||||
R2 = R !So prepare a scan.
|
||||
DO WHILE (L2 .LE. R2) !Keep squeezing until the inner teeth meet.
|
||||
DO WHILE (A(L2) .LT. HOPE) !Pass elements less than HOPE.
|
||||
L2 = L2 + 1 !Note that at least element A(K) equals HOPE.
|
||||
END DO !Raising the lower jaw.
|
||||
DO WHILE (HOPE .LT. A(R2)) !Elements higher than HOPE
|
||||
R2 = R2 - 1 !Are in the desired place.
|
||||
END DO !And so we speed past them.
|
||||
IF (L2 - R2) 1,2,3 !How have the teeth paused?
|
||||
1 PESTY = A(L2) !On grit. A(L2) > HOPE and A(R2) < HOPE.
|
||||
A(L2) = A(R2) !So swap the two troublemakers.
|
||||
A(R2) = PESTY !To be as if they had been in the desired order all along.
|
||||
2 L2 = L2 + 1 !Advance my teeth.
|
||||
R2 = R2 - 1 !As if they hadn't paused on this pest.
|
||||
3 END DO !And resume the squeeze, hopefully closing in K.
|
||||
IF (R2 .LT. K) L = L2 !The end point gives the order position of value HOPE.
|
||||
IF (K .LT. L2) R = R2 !But we want the value of order position K.
|
||||
END DO !Have my teeth met yet?
|
||||
FINDELEMENT = A(K) !Yes. A(K) now has the K'th element in order.
|
||||
END FUNCTION FINDELEMENT !Remember! Array A has likely had some elements moved!
|
||||
|
||||
PROGRAM POKE
|
||||
INTEGER FINDELEMENT !Not the default type for F.
|
||||
INTEGER N !The number of elements.
|
||||
PARAMETER (N = 10) !Fixed for the test problem.
|
||||
INTEGER A(66) !An array of integers.
|
||||
DATA A(1:N)/9, 8, 7, 6, 5, 0, 1, 2, 3, 4/ !The specified values.
|
||||
|
||||
WRITE (6,1) A(1:N) !Announce, and add a heading.
|
||||
1 FORMAT ("Selection of the i'th element in order from an array.",/
|
||||
1 "The array need not be in order, and may be reordered.",/
|
||||
2 " i Val:Array elements...",/,8X,666I2)
|
||||
|
||||
DO I = 1,N !One by one,
|
||||
WRITE (6,2) I,FINDELEMENT(I,A,N),A(1:N) !Request the i'th element.
|
||||
2 FORMAT (I3,I4,":",666I2) !Match FORMAT 1.
|
||||
END DO !On to the next trial.
|
||||
|
||||
END !That was easy.
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
Dim Shared As Long array(9), pivote
|
||||
|
||||
Function QuickPartition (array() As Long, izda As Long, dcha As Long, pivote As Long) As Long
|
||||
Dim As Long pivotValue = array(pivote)
|
||||
Swap array(pivote), array(dcha)
|
||||
Dim As Long indice = izda
|
||||
For i As Long = izda To dcha-1
|
||||
If array(i) < pivotValue Then
|
||||
Swap array(indice), array(i)
|
||||
indice += 1
|
||||
End If
|
||||
Next i
|
||||
Swap array(dcha), array(indice)
|
||||
Return indice
|
||||
End Function
|
||||
|
||||
Function QuickSelect(array() As Long, izda As Long, dcha As Long, k As Long) As Long
|
||||
Do
|
||||
If izda = dcha Then Return array(izda) : End If
|
||||
pivote = izda
|
||||
pivote = QuickPartition(array(), izda, dcha, pivote)
|
||||
Select Case k
|
||||
Case pivote
|
||||
Return array(k)
|
||||
Case Is < pivote
|
||||
dcha = pivote - 1
|
||||
Case Is > pivote
|
||||
izda = pivote + 1
|
||||
End Select
|
||||
Loop
|
||||
End Function
|
||||
|
||||
Dim As Long a = Lbound(array), b = Ubound(array)
|
||||
Print "Array desordenado: ";
|
||||
For i As Long = a To b
|
||||
Read array(i)
|
||||
Print array(i);
|
||||
Next i
|
||||
Data 9, 8, 7, 6, 5, 0, 1, 2, 3, 4
|
||||
|
||||
Print !"\n\n Array ordenado: ";
|
||||
For i As Long = a To b
|
||||
Print QuickSelect(array(), a, b, i);
|
||||
Next i
|
||||
Sleep
|
||||
41
Task/Quickselect-algorithm/Go/quickselect-algorithm-1.go
Normal file
41
Task/Quickselect-algorithm/Go/quickselect-algorithm-1.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func quickselect(list []int, k int) int {
|
||||
for {
|
||||
// partition
|
||||
px := len(list) / 2
|
||||
pv := list[px]
|
||||
last := len(list) - 1
|
||||
list[px], list[last] = list[last], list[px]
|
||||
i := 0
|
||||
for j := 0; j < last; j++ {
|
||||
if list[j] < pv {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
// select
|
||||
if i == k {
|
||||
return pv
|
||||
}
|
||||
if k < i {
|
||||
list = list[:i]
|
||||
} else {
|
||||
list[i], list[last] = list[last], list[i]
|
||||
list = list[i+1:]
|
||||
k -= i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
for i := 0; ; i++ {
|
||||
v := []int{9, 8, 7, 6, 5, 0, 1, 2, 3, 4}
|
||||
if i == len(v) {
|
||||
return
|
||||
}
|
||||
fmt.Println(quickselect(v, i))
|
||||
}
|
||||
}
|
||||
55
Task/Quickselect-algorithm/Go/quickselect-algorithm-2.go
Normal file
55
Task/Quickselect-algorithm/Go/quickselect-algorithm-2.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func partition(a sort.Interface, first int, last int, pivotIndex int) int {
|
||||
a.Swap(first, pivotIndex) // move it to beginning
|
||||
left := first+1
|
||||
right := last
|
||||
for left <= right {
|
||||
for left <= last && a.Less(left, first) {
|
||||
left++
|
||||
}
|
||||
for right >= first && a.Less(first, right) {
|
||||
right--
|
||||
}
|
||||
if left <= right {
|
||||
a.Swap(left, right)
|
||||
left++
|
||||
right--
|
||||
}
|
||||
}
|
||||
a.Swap(first, right) // swap into right place
|
||||
return right
|
||||
}
|
||||
|
||||
func quickselect(a sort.Interface, n int) int {
|
||||
first := 0
|
||||
last := a.Len()-1
|
||||
for {
|
||||
pivotIndex := partition(a, first, last,
|
||||
rand.Intn(last - first + 1) + first)
|
||||
if n == pivotIndex {
|
||||
return pivotIndex
|
||||
} else if n < pivotIndex {
|
||||
last = pivotIndex-1
|
||||
} else {
|
||||
first = pivotIndex+1
|
||||
}
|
||||
}
|
||||
panic("bad index")
|
||||
}
|
||||
|
||||
func main() {
|
||||
for i := 0; ; i++ {
|
||||
v := []int{9, 8, 7, 6, 5, 0, 1, 2, 3, 4}
|
||||
if i == len(v) {
|
||||
return
|
||||
}
|
||||
fmt.Println(v[quickselect(sort.IntSlice(v), i)])
|
||||
}
|
||||
}
|
||||
18
Task/Quickselect-algorithm/Haskell/quickselect-algorithm.hs
Normal file
18
Task/Quickselect-algorithm/Haskell/quickselect-algorithm.hs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import Data.List (partition)
|
||||
|
||||
quickselect
|
||||
:: Ord a
|
||||
=> [a] -> Int -> a
|
||||
quickselect (x:xs) k
|
||||
| k < l = quickselect ys k
|
||||
| k > l = quickselect zs (k - l - 1)
|
||||
| otherwise = x
|
||||
where
|
||||
(ys, zs) = partition (< x) xs
|
||||
l = length ys
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
print
|
||||
((fmap . quickselect) <*> zipWith const [0 ..] $
|
||||
[9, 8, 7, 6, 5, 0, 1, 2, 3, 4])
|
||||
21
Task/Quickselect-algorithm/Icon/quickselect-algorithm.icon
Normal file
21
Task/Quickselect-algorithm/Icon/quickselect-algorithm.icon
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
procedure main(A)
|
||||
every writes(" ",select(1 to *A, A, 1, *A)|"\n")
|
||||
end
|
||||
|
||||
procedure select(k,A,min,max)
|
||||
repeat {
|
||||
pNI := partition(?(max-min)+min, A, min, max)
|
||||
pD := pNI - min + 1
|
||||
if pD = k then return A[pNI]
|
||||
if k < pD then max := pNI-1
|
||||
else (k -:= pD, min := pNI+1)
|
||||
}
|
||||
end
|
||||
|
||||
procedure partition(pivot,A,min,max)
|
||||
pV := (A[max] :=: A[pivot])
|
||||
sI := min
|
||||
every A[i := min to max-1] <= pV do (A[sI] :=: A[i], sI +:= 1)
|
||||
A[max] :=: A[sI]
|
||||
return sI
|
||||
end
|
||||
14
Task/Quickselect-algorithm/J/quickselect-algorithm-1.j
Normal file
14
Task/Quickselect-algorithm/J/quickselect-algorithm-1.j
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
quickselect=:4 :0
|
||||
if. 0=#y do. _ return. end.
|
||||
n=.?#y
|
||||
m=.n{y
|
||||
if. x < m do.
|
||||
x quickselect (m>y)#y
|
||||
else.
|
||||
if. x > m do.
|
||||
x quickselect (m<y)#y
|
||||
else.
|
||||
m
|
||||
end.
|
||||
end.
|
||||
)
|
||||
2
Task/Quickselect-algorithm/J/quickselect-algorithm-2.j
Normal file
2
Task/Quickselect-algorithm/J/quickselect-algorithm-2.j
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
8 quickselect 9, 8, 7, 6, 5, 0, 1, 2, 3, 4
|
||||
8
|
||||
2
Task/Quickselect-algorithm/J/quickselect-algorithm-3.j
Normal file
2
Task/Quickselect-algorithm/J/quickselect-algorithm-3.j
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
((10 {./:~) quickselect"0 1 ]) 9, 8, 7, 6, 5, 0, 1, 2, 3, 4
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
53
Task/Quickselect-algorithm/Java/quickselect-algorithm.java
Normal file
53
Task/Quickselect-algorithm/Java/quickselect-algorithm.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import java.util.Random;
|
||||
|
||||
public class QuickSelect {
|
||||
|
||||
private static <E extends Comparable<? super E>> int partition(E[] arr, int left, int right, int pivot) {
|
||||
E pivotVal = arr[pivot];
|
||||
swap(arr, pivot, right);
|
||||
int storeIndex = left;
|
||||
for (int i = left; i < right; i++) {
|
||||
if (arr[i].compareTo(pivotVal) < 0) {
|
||||
swap(arr, i, storeIndex);
|
||||
storeIndex++;
|
||||
}
|
||||
}
|
||||
swap(arr, right, storeIndex);
|
||||
return storeIndex;
|
||||
}
|
||||
|
||||
private static <E extends Comparable<? super E>> E select(E[] arr, int n) {
|
||||
int left = 0;
|
||||
int right = arr.length - 1;
|
||||
Random rand = new Random();
|
||||
while (right >= left) {
|
||||
int pivotIndex = partition(arr, left, right, rand.nextInt(right - left + 1) + left);
|
||||
if (pivotIndex == n) {
|
||||
return arr[pivotIndex];
|
||||
} else if (pivotIndex < n) {
|
||||
left = pivotIndex + 1;
|
||||
} else {
|
||||
right = pivotIndex - 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void swap(Object[] arr, int i1, int i2) {
|
||||
if (i1 != i2) {
|
||||
Object temp = arr[i1];
|
||||
arr[i1] = arr[i2];
|
||||
arr[i2] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Integer[] input = {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
|
||||
System.out.print(select(input, i));
|
||||
if (i < 9) System.out.print(", ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// this just helps make partition read better
|
||||
function swap(items, firstIndex, secondIndex) {
|
||||
var temp = items[firstIndex];
|
||||
items[firstIndex] = items[secondIndex];
|
||||
items[secondIndex] = temp;
|
||||
};
|
||||
|
||||
// many algorithms on this page violate
|
||||
// the constraint that partition operates in place
|
||||
function partition(array, from, to) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
var pivotIndex = getRandomInt(from, to),
|
||||
pivot = array[pivotIndex];
|
||||
swap(array, pivotIndex, to);
|
||||
pivotIndex = from;
|
||||
|
||||
for(var i = from; i <= to; i++) {
|
||||
if(array[i] < pivot) {
|
||||
swap(array, pivotIndex, i);
|
||||
pivotIndex++;
|
||||
}
|
||||
};
|
||||
swap(array, pivotIndex, to);
|
||||
|
||||
return pivotIndex;
|
||||
};
|
||||
|
||||
// later versions of JS have TCO so this is safe
|
||||
function quickselectRecursive(array, from, to, statistic) {
|
||||
if(array.length === 0 || statistic > array.length - 1) {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
var pivotIndex = partition(array, from, to);
|
||||
if(pivotIndex === statistic) {
|
||||
return array[pivotIndex];
|
||||
} else if(pivotIndex < statistic) {
|
||||
return quickselectRecursive(array, pivotIndex, to, statistic);
|
||||
} else if(pivotIndex > statistic) {
|
||||
return quickselectRecursive(array, from, pivotIndex, statistic);
|
||||
}
|
||||
};
|
||||
|
||||
function quickselectIterative(array, k) {
|
||||
if(array.length === 0 || k > array.length - 1) {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
var from = 0, to = array.length,
|
||||
pivotIndex = partition(array, from, to);
|
||||
|
||||
while(pivotIndex !== k) {
|
||||
pivotIndex = partition(array, from, to);
|
||||
if(pivotIndex < k) {
|
||||
from = pivotIndex;
|
||||
} else if(pivotIndex > k) {
|
||||
to = pivotIndex;
|
||||
}
|
||||
};
|
||||
|
||||
return array[pivotIndex];
|
||||
};
|
||||
|
||||
KthElement = {
|
||||
find: function(array, element) {
|
||||
var k = element - 1;
|
||||
return quickselectRecursive(array, 0, array.length, k);
|
||||
// you can also try out the Iterative version
|
||||
// return quickselectIterative(array, k);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
var array = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4],
|
||||
ks = Array.apply(null, {length: 10}).map(Number.call, Number);
|
||||
ks.map(k => { KthElement.find(array, k) });
|
||||
|
|
@ -0,0 +1 @@
|
|||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// QUICKSELECT ------------------------------------------------------------
|
||||
|
||||
// quickselect :: Ord a => Int -> [a] -> a
|
||||
const quickSelect = (k, xxs) => {
|
||||
const
|
||||
[x, xs] = uncons(xxs),
|
||||
[ys, zs] = partition(v => v < x, xs),
|
||||
l = length(ys);
|
||||
|
||||
return (k < l) ? (
|
||||
quickSelect(k, ys)
|
||||
) : (k > l) ? (
|
||||
quickSelect(k - l - 1, zs)
|
||||
) : x;
|
||||
};
|
||||
|
||||
|
||||
// GENERIC FUNCTIONS ------------------------------------------------------
|
||||
|
||||
// enumFromTo :: Int -> Int -> [Int]
|
||||
const enumFromTo = (m, n) =>
|
||||
Array.from({
|
||||
length: Math.floor(n - m) + 1
|
||||
}, (_, i) => m + i);
|
||||
|
||||
// length :: [a] -> Int
|
||||
const length = xs => xs.length;
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = (f, xs) => xs.map(f);
|
||||
|
||||
// partition :: Predicate -> List -> (Matches, nonMatches)
|
||||
// partition :: (a -> Bool) -> [a] -> ([a], [a])
|
||||
const partition = (p, xs) =>
|
||||
xs.reduce((a, x) =>
|
||||
p(x) ? [a[0].concat(x), a[1]] : [a[0], a[1].concat(x)], [
|
||||
[],
|
||||
[]
|
||||
]);
|
||||
|
||||
// uncons :: [a] -> Maybe (a, [a])
|
||||
const uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined;
|
||||
|
||||
|
||||
// TEST -------------------------------------------------------------------
|
||||
const v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
|
||||
return map(i => quickSelect(i, v), enumFromTo(0, length(v) - 1));
|
||||
})();
|
||||
|
|
@ -0,0 +1 @@
|
|||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
30
Task/Quickselect-algorithm/Jq/quickselect-algorithm-1.jq
Normal file
30
Task/Quickselect-algorithm/Jq/quickselect-algorithm-1.jq
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Emit the k-th smallest item in the input array,
|
||||
# or nothing if k is too small or too large.
|
||||
# The smallest corresponds to k==1.
|
||||
# The input array may hold arbitrary JSON entities, including null.
|
||||
def quickselect(k):
|
||||
|
||||
def partition(pivot):
|
||||
reduce .[] as $x
|
||||
# state: [less, other]
|
||||
( [ [], [] ]; # two empty arrays:
|
||||
if $x < pivot
|
||||
then .[0] += [$x] # add x to less
|
||||
else .[1] += [$x] # add x to other
|
||||
end
|
||||
);
|
||||
|
||||
# recursive inner function has arity 0 for efficiency
|
||||
def qs: # state: [kn, array] where kn counts from 0
|
||||
.[0] as $kn
|
||||
| .[1] as $a
|
||||
| $a[0] as $pivot
|
||||
| ($a[1:] | partition($pivot)) as $p
|
||||
| $p[0] as $left
|
||||
| ($left|length) as $ll
|
||||
| if $kn == $ll then $pivot
|
||||
elif $kn < $ll then [$kn, $left] | qs
|
||||
else [$kn - $ll - 1, $p[1] ] | qs
|
||||
end;
|
||||
|
||||
if length < k or k <= 0 then empty else [k-1, .] | qs end;
|
||||
3
Task/Quickselect-algorithm/Jq/quickselect-algorithm-2.jq
Normal file
3
Task/Quickselect-algorithm/Jq/quickselect-algorithm-2.jq
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(0, 12, range(1;11)) as $k
|
||||
| [9, 8, 7, 6, 5, 0, 1, 2, 3, 4] | quickselect($k)
|
||||
| "k=\($k) => \(.)"
|
||||
12
Task/Quickselect-algorithm/Jq/quickselect-algorithm-3.jq
Normal file
12
Task/Quickselect-algorithm/Jq/quickselect-algorithm-3.jq
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
$ jq -n -r -f quickselect.jq
|
||||
k=1 => 0
|
||||
k=2 => 1
|
||||
k=3 => 2
|
||||
k=4 => 3
|
||||
k=5 => 4
|
||||
k=6 => 5
|
||||
k=7 => 6
|
||||
k=8 => 7
|
||||
k=9 => 8
|
||||
k=10 => 9
|
||||
$
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
@show v partialsort(v, 1:10)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// version 1.1.2
|
||||
|
||||
const val MAX = Int.MAX_VALUE
|
||||
val rand = java.util.Random()
|
||||
|
||||
fun partition(list:IntArray, left: Int, right:Int, pivotIndex: Int): Int {
|
||||
val pivotValue = list[pivotIndex]
|
||||
list[pivotIndex] = list[right]
|
||||
list[right] = pivotValue
|
||||
var storeIndex = left
|
||||
for (i in left until right) {
|
||||
if (list[i] < pivotValue) {
|
||||
val tmp = list[storeIndex]
|
||||
list[storeIndex] = list[i]
|
||||
list[i] = tmp
|
||||
storeIndex++
|
||||
}
|
||||
}
|
||||
val temp = list[right]
|
||||
list[right] = list[storeIndex]
|
||||
list[storeIndex] = temp
|
||||
return storeIndex
|
||||
}
|
||||
|
||||
tailrec fun quickSelect(list: IntArray, left: Int, right: Int, k: Int): Int {
|
||||
if (left == right) return list[left]
|
||||
var pivotIndex = left + Math.floor((rand.nextInt(MAX) % (right - left + 1)).toDouble()).toInt()
|
||||
pivotIndex = partition(list, left, right, pivotIndex)
|
||||
if (k == pivotIndex)
|
||||
return list[k]
|
||||
else if (k < pivotIndex)
|
||||
return quickSelect(list, left, pivotIndex - 1, k)
|
||||
else
|
||||
return quickSelect(list, pivotIndex + 1, right, k)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val list = intArrayOf(9, 8, 7, 6, 5, 0, 1, 2, 3, 4)
|
||||
val right = list.size - 1
|
||||
for (k in 0..9) {
|
||||
print(quickSelect(list, 0, right, k))
|
||||
if (k < 9) print(", ")
|
||||
}
|
||||
println()
|
||||
}
|
||||
33
Task/Quickselect-algorithm/Lua/quickselect-algorithm.lua
Normal file
33
Task/Quickselect-algorithm/Lua/quickselect-algorithm.lua
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
function partition (list, left, right, pivotIndex)
|
||||
local pivotValue = list[pivotIndex]
|
||||
list[pivotIndex], list[right] = list[right], list[pivotIndex]
|
||||
local storeIndex = left
|
||||
for i = left, right do
|
||||
if list[i] < pivotValue then
|
||||
list[storeIndex], list[i] = list[i], list[storeIndex]
|
||||
storeIndex = storeIndex + 1
|
||||
end
|
||||
end
|
||||
list[right], list[storeIndex] = list[storeIndex], list[right]
|
||||
return storeIndex
|
||||
end
|
||||
|
||||
function quickSelect (list, left, right, n)
|
||||
local pivotIndex
|
||||
while 1 do
|
||||
if left == right then return list[left] end
|
||||
pivotIndex = math.random(left, right)
|
||||
pivotIndex = partition(list, left, right, pivotIndex)
|
||||
if n == pivotIndex then
|
||||
return list[n]
|
||||
elseif n < pivotIndex then
|
||||
right = pivotIndex - 1
|
||||
else
|
||||
left = pivotIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
math.randomseed(os.time())
|
||||
local vec = {9, 8, 7, 6, 5, 0, 1, 2, 3, 4}
|
||||
for i = 1, 10 do print(i, quickSelect(vec, 1, #vec, i) .. " ") end
|
||||
36
Task/Quickselect-algorithm/Maple/quickselect-algorithm.maple
Normal file
36
Task/Quickselect-algorithm/Maple/quickselect-algorithm.maple
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
part := proc(arr, left, right, pivot)
|
||||
local val,safe,i:
|
||||
val := arr[pivot]:
|
||||
arr[pivot], arr[right] := arr[right], arr[pivot]:
|
||||
safe := left:
|
||||
for i from left to right do
|
||||
if arr[i] < val then
|
||||
arr[safe], arr[i] := arr[i], arr[safe]:
|
||||
safe := safe + 1:
|
||||
end if:
|
||||
end do:
|
||||
arr[right], arr[safe] := arr[safe], arr[right]:
|
||||
return safe:
|
||||
end proc:
|
||||
|
||||
quickselect := proc(arr,k)
|
||||
local pivot,left,right:
|
||||
left,right := 1,numelems(arr):
|
||||
while(true)do
|
||||
if left = right then return arr[left]: end if:
|
||||
pivot := trunc((left+right)/2);
|
||||
pivot := part(arr, left, right, pivot):
|
||||
if k = pivot then
|
||||
return arr[k]:
|
||||
elif k < pivot then
|
||||
right := pivot-1:
|
||||
else
|
||||
left := pivot+1:
|
||||
end if:
|
||||
end do:
|
||||
end proc:
|
||||
roll := rand(1..20):
|
||||
demo := Array([seq(roll(), i=1..20)]);
|
||||
map(x->printf("%d ", x), demo):
|
||||
print(quickselect(demo,7)):
|
||||
print(quickselect(demo,14)):
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
Quickselect[ds : DataStructure["DynamicArray", _], k_] := QuickselectWorker[ds, 1, ds["Length"], k];
|
||||
QuickselectWorker[ds_, low0_, high0_, k_] := Module[{pivotIdx, low = low0, high = high0},
|
||||
While[True,
|
||||
If[low === high,
|
||||
Return[ds["Part", low]]
|
||||
];
|
||||
pivotIdx = SelectPartition[ds, low, high];
|
||||
Which[k === pivotIdx,
|
||||
Return[ds["Part", k]],
|
||||
k < pivotIdx,
|
||||
high = pivotIdx - 1,
|
||||
True,
|
||||
low = pivotIdx + 1
|
||||
]
|
||||
]
|
||||
];
|
||||
SelectPartition[ds_, low_, high_] := Module[{pivot = ds["Part", high], i = low, j},
|
||||
Do[
|
||||
If[ds["Part", j] <= pivot,
|
||||
ds["SwapPart", i, j];
|
||||
i = i + 1
|
||||
]
|
||||
,
|
||||
{j, low, high - 1}
|
||||
];
|
||||
ds["SwapPart", i, high];
|
||||
i
|
||||
];
|
||||
ds = CreateDataStructure["DynamicArray", {9, 8, 7, 6, 5, 0, 1, 2, 3, 4}];
|
||||
Quickselect[ds, #] & /@ Range[10]
|
||||
210
Task/Quickselect-algorithm/Mercury/quickselect-algorithm.mercury
Normal file
210
Task/Quickselect-algorithm/Mercury/quickselect-algorithm.mercury
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
|
||||
:- module quickselect_task.
|
||||
|
||||
:- interface.
|
||||
:- import_module io.
|
||||
:- pred main(io, io).
|
||||
:- mode main(di, uo) is det.
|
||||
|
||||
:- implementation.
|
||||
:- import_module array.
|
||||
:- import_module exception.
|
||||
:- import_module int.
|
||||
:- import_module list.
|
||||
:- import_module random.
|
||||
:- import_module random.sfc64.
|
||||
:- import_module string.
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%%
|
||||
%%% Partitioning a subarray into two halves: one with elements less
|
||||
%%% than or equal to a pivot, the other with elements greater than or
|
||||
%%% equal to a pivot.
|
||||
%%%
|
||||
%%% The implementation is tail-recursive.
|
||||
%%%
|
||||
|
||||
:- pred partition(pred(T, T), T, int, int, array(T), array(T), int).
|
||||
:- mode partition(pred(in, in) is semidet, in, in, in,
|
||||
array_di, array_uo, out).
|
||||
partition(Less_than, Pivot, I_first, I_last, Arr0, Arr, I_pivot) :-
|
||||
I = I_first - 1,
|
||||
J = I_last + 1,
|
||||
partition_loop(Less_than, Pivot, I, J, Arr0, Arr, I_pivot).
|
||||
|
||||
:- pred partition_loop(pred(T, T), T, int, int,
|
||||
array(T), array(T), int).
|
||||
:- mode partition_loop(pred(in, in) is semidet, in, in, in,
|
||||
array_di, array_uo, out).
|
||||
partition_loop(Less_than, Pivot, I, J, Arr0, Arr, Pivot_index) :-
|
||||
if (I = J) then (Arr = Arr0,
|
||||
Pivot_index = I)
|
||||
else (I1 = I + 1,
|
||||
I2 = search_right(Less_than, Pivot, I1, J, Arr0),
|
||||
(if (I2 = J) then (Arr = Arr0,
|
||||
Pivot_index = J)
|
||||
else (J1 = J - 1,
|
||||
J2 = search_left(Less_than, Pivot, I2, J1, Arr0),
|
||||
swap(I2, J2, Arr0, Arr1),
|
||||
partition_loop(Less_than, Pivot, I2, J2, Arr1, Arr,
|
||||
Pivot_index)))).
|
||||
|
||||
:- func search_right(pred(T, T), T, int, int, array(T)) = int.
|
||||
:- mode search_right(pred(in, in) is semidet,
|
||||
in, in, in, in) = out is det.
|
||||
search_right(Less_than, Pivot, I, J, Arr0) = K :-
|
||||
if (I = J) then (I = K)
|
||||
else if Less_than(Pivot, Arr0^elem(I)) then (I = K)
|
||||
else (search_right(Less_than, Pivot, I + 1, J, Arr0) = K).
|
||||
|
||||
:- func search_left(pred(T, T), T, int, int, array(T)) = int.
|
||||
:- mode search_left(pred(in, in) is semidet,
|
||||
in, in, in, in) = out is det.
|
||||
search_left(Less_than, Pivot, I, J, Arr0) = K :-
|
||||
if (I = J) then (J = K)
|
||||
else if Less_than(Arr0^elem(J), Pivot) then (J = K)
|
||||
else (search_left(Less_than, Pivot, I, J - 1, Arr0) = K).
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%%
|
||||
%%% Quickselect with a random pivot.
|
||||
%%%
|
||||
%%% The implementation is tail-recursive. One has to pass the routine
|
||||
%%% a random number generator of type M, attached to the IO state.
|
||||
%%%
|
||||
%%% I use a random pivot to get O(n) worst case *expected* running
|
||||
%%% time. Code using a random pivot is easy to write and read, and for
|
||||
%%% most purposes comes close enough to a criterion set by Scheme's
|
||||
%%% SRFI-132: "Runs in O(n) time." (See
|
||||
%%% https://srfi.schemers.org/srfi-132/srfi-132.html)
|
||||
%%%
|
||||
%%% Of course we are not bound here by SRFI-132, but still I respect
|
||||
%%% it as a guide.
|
||||
%%%
|
||||
%%% A "median of medians" pivot gives O(n) running time, but is more
|
||||
%%% complicated. (That is, of course, assuming you are not writing
|
||||
%%% your own random number generator and making it a complicated one.)
|
||||
%%%
|
||||
|
||||
%% quickselect/8 selects the (K+1)th largest element of Arr.
|
||||
:- pred quickselect(pred(T, T)::pred(in, in) is semidet, int::in,
|
||||
array(T)::array_di, array(T)::array_uo,
|
||||
T::out, M::in, io::di, io::uo)
|
||||
is det <= urandom(M, io).
|
||||
quickselect(Less_than, K, Arr0, Arr, Elem, M, !IO) :-
|
||||
bounds(Arr0, I_first, I_last),
|
||||
quickselect(Less_than, I_first, I_last, K, Arr0, Arr, Elem, M, !IO).
|
||||
|
||||
%% quickselect/10 selects the (K+1)th largest element of
|
||||
%% Arr[I_first..I_last].
|
||||
:- pred quickselect(pred(T, T)::pred(in, in) is semidet,
|
||||
int::in, int::in, int::in,
|
||||
array(T)::array_di, array(T)::array_uo,
|
||||
T::out, M::in, io::di, io::uo)
|
||||
is det <= urandom(M, io).
|
||||
quickselect(Less_than, I_first, I_last, K, Arr0, Arr, Elem, M, !IO) :-
|
||||
if (0 =< K, K =< I_last - I_first)
|
||||
then (K_adjusted_for_range = K + I_first,
|
||||
quickselect_loop(Less_than, I_first, I_last,
|
||||
K_adjusted_for_range,
|
||||
Arr0, Arr, Elem, M, !IO))
|
||||
else throw("out of range").
|
||||
|
||||
:- pred quickselect_loop(pred(T, T)::pred(in, in) is semidet,
|
||||
int::in, int::in, int::in,
|
||||
array(T)::array_di, array(T)::array_uo,
|
||||
T::out, M::in, io::di, io::uo)
|
||||
is det <= urandom(M, io).
|
||||
quickselect_loop(Less_than, I_first, I_last, K,
|
||||
Arr0, Arr, Elem, M, !IO) :-
|
||||
if (I_first = I_last) then (Arr = Arr0,
|
||||
Elem = Arr0^elem(I_first))
|
||||
else (uniform_int_in_range(M, I_first, I_last - I_first + 1,
|
||||
I_pivot, !IO),
|
||||
Pivot = Arr0^elem(I_pivot),
|
||||
|
||||
%% Move the last element to where the pivot had been. Perhaps
|
||||
%% the pivot was already the last element, of course. In any
|
||||
%% case, we shall partition only from I_first to I_last - 1.
|
||||
Elem_last = Arr0^elem(I_last),
|
||||
Arr1 = (Arr0^elem(I_pivot) := Elem_last),
|
||||
|
||||
%% Partition the array in the range I_first..I_last - 1,
|
||||
%% leaving out the last element (which now can be considered
|
||||
%% garbage).
|
||||
partition(Less_than, Pivot, I_first, I_last - 1, Arr1, Arr2,
|
||||
I_final),
|
||||
|
||||
%% Now everything that is less than the pivot is to the left
|
||||
%% of I_final.
|
||||
|
||||
%% Put the pivot at I_final, moving the element that had been
|
||||
%% there to the end. If I_final = I_last, then this element is
|
||||
%% actually garbage and will be overwritten with the pivot,
|
||||
%% which turns out to be the greatest element. Otherwise, the
|
||||
%% moved element is not less than the pivot and so the
|
||||
%% partitioning is preserved.
|
||||
Elem_to_move = Arr2^elem(I_final),
|
||||
Arr3 = (Arr2^elem(I_last) := Elem_to_move),
|
||||
Arr4 = (Arr3^elem(I_final) := Pivot),
|
||||
|
||||
%% Compare I_final and K, to see what to do next.
|
||||
(if (I_final < K)
|
||||
then quickselect_loop(Less_than, I_final + 1, I_last, K,
|
||||
Arr4, Arr, Elem, M, !IO)
|
||||
else if (K < I_final)
|
||||
then quickselect_loop(Less_than, I_first, I_final - 1, K,
|
||||
Arr4, Arr, Elem, M, !IO)
|
||||
else (Arr = Arr4,
|
||||
Elem = Arr4^elem(I_final)))).
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
:- func example_numbers = list(int).
|
||||
example_numbers = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4].
|
||||
|
||||
main(!IO) :-
|
||||
(sfc64.init(P, S)),
|
||||
make_io_urandom(P, S, M, !IO),
|
||||
Print_kth_greatest = (pred(K::in, di, uo) is det -->
|
||||
print_kth_greatest(K, example_numbers, M)),
|
||||
Print_kth_least = (pred(K::in, di, uo) is det -->
|
||||
print_kth_least(K, example_numbers, M)),
|
||||
print("With < as order predicate: ", !IO),
|
||||
foldl(Print_kth_least, 1 `..` 10, !IO),
|
||||
print_line("", !IO),
|
||||
print("With > as order predicate: ", !IO),
|
||||
foldl(Print_kth_greatest, 1 `..` 10, !IO),
|
||||
print_line("", !IO).
|
||||
|
||||
:- pred print_kth_least(int::in, list(int)::in,
|
||||
M::in, io::di, io::uo)
|
||||
is det <= urandom(M, io).
|
||||
print_kth_least(K, Numbers_list, M, !IO) :-
|
||||
(array.from_list(Numbers_list, Arr0)),
|
||||
quickselect(<, K - 1, Arr0, _, Elem, M, !IO),
|
||||
print(" ", !IO),
|
||||
print(Elem, !IO).
|
||||
|
||||
:- pred print_kth_greatest(int::in, list(int)::in,
|
||||
M::in, io::di, io::uo)
|
||||
is det <= urandom(M, io).
|
||||
print_kth_greatest(K, Numbers_list, M, !IO) :-
|
||||
(array.from_list(Numbers_list, Arr0)),
|
||||
|
||||
%% Notice that the "Less_than" predicate is actually "greater
|
||||
%% than". :) One can think of this as meaning that a greater number
|
||||
%% has an *ordinal* that is "less than"; that is, it "comes before"
|
||||
%% in the order.
|
||||
quickselect(>, K - 1, Arr0, _, Elem, M, !IO),
|
||||
|
||||
print(" ", !IO),
|
||||
print(Elem, !IO).
|
||||
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% local variables:
|
||||
%%% mode: mercury
|
||||
%%% prolog-indent-width: 2
|
||||
%%% end:
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/* NetRexx */
|
||||
options replace format comments java crossref symbols nobinary
|
||||
/** @see <a href="http://en.wikipedia.org/wiki/Quickselect">http://en.wikipedia.org/wiki/Quickselect</a> */
|
||||
|
||||
runSample(arg)
|
||||
return
|
||||
|
||||
-- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
||||
method qpartition(list, ileft, iright, pivotIndex) private static
|
||||
pivotValue = list[pivotIndex]
|
||||
list = swap(list, pivotIndex, iright) -- Move pivot to end
|
||||
storeIndex = ileft
|
||||
loop i_ = ileft to iright - 1
|
||||
if list[i_] <= pivotValue then do
|
||||
list = swap(list, storeIndex, i_)
|
||||
storeIndex = storeIndex + 1
|
||||
end
|
||||
end i_
|
||||
list = swap(list, iright, storeIndex) -- Move pivot to its final place
|
||||
return storeIndex
|
||||
|
||||
-- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
||||
method qselectInPlace(list, k_, ileft = -1, iright = -1) public static
|
||||
if ileft = -1 then ileft = 1
|
||||
if iright = -1 then iright = list[0]
|
||||
|
||||
loop label inplace forever
|
||||
pivotIndex = Random().nextInt(iright - ileft + 1) + ileft -- select pivotIndex between left and right
|
||||
pivotNewIndex = qpartition(list, ileft, iright, pivotIndex)
|
||||
pivotDist = pivotNewIndex - ileft + 1
|
||||
select
|
||||
when pivotDist = k_ then do
|
||||
returnVal = list[pivotNewIndex]
|
||||
leave inplace
|
||||
end
|
||||
when k_ < pivotDist then
|
||||
iright = pivotNewIndex - 1
|
||||
otherwise do
|
||||
k_ = k_ - pivotDist
|
||||
ileft = pivotNewIndex + 1
|
||||
end
|
||||
end
|
||||
end inplace
|
||||
return returnVal
|
||||
|
||||
-- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
||||
method swap(list, i1, i2) private static
|
||||
if i1 \= i2 then do
|
||||
t1 = list[i1]
|
||||
list[i1] = list[i2]
|
||||
list[i2] = t1
|
||||
end
|
||||
return list
|
||||
|
||||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
method runSample(arg) private static
|
||||
parse arg samplelist
|
||||
if samplelist = '' | samplelist = '.' then samplelist = 9 8 7 6 5 0 1 2 3 4
|
||||
items = samplelist.words
|
||||
say 'Input:'
|
||||
say ' 'samplelist.space(1, ',').changestr(',', ', ')
|
||||
say
|
||||
|
||||
say 'Using in-place version of the algorithm:'
|
||||
iv = ''
|
||||
loop k_ = 1 to items
|
||||
iv = iv qselectInPlace(buildIndexedString(samplelist), k_)
|
||||
end k_
|
||||
say ' 'iv.space(1, ',').changestr(',', ', ')
|
||||
say
|
||||
|
||||
say 'Find the 4 smallest:'
|
||||
iv = ''
|
||||
loop k_ = 1 to 4
|
||||
iv = iv qselectInPlace(buildIndexedString(samplelist), k_)
|
||||
end k_
|
||||
say ' 'iv.space(1, ',').changestr(',', ', ')
|
||||
say
|
||||
|
||||
say 'Find the 3 largest:'
|
||||
iv = ''
|
||||
loop k_ = items - 2 to items
|
||||
iv = iv qselectInPlace(buildIndexedString(samplelist), k_)
|
||||
end k_
|
||||
say ' 'iv.space(1, ',').changestr(',', ', ')
|
||||
say
|
||||
|
||||
return
|
||||
|
||||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
method buildIndexedString(samplelist) private static
|
||||
list = 0
|
||||
list[0] = samplelist.words()
|
||||
loop k_ = 1 to list[0]
|
||||
list[k_] = samplelist.word(k_)
|
||||
end k_
|
||||
return list
|
||||
19
Task/Quickselect-algorithm/Nim/quickselect-algorithm.nim
Normal file
19
Task/Quickselect-algorithm/Nim/quickselect-algorithm.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
proc qselect[T](a: var openarray[T]; k: int, inl = 0, inr = -1): T =
|
||||
var r = if inr >= 0: inr else: a.high
|
||||
var st = 0
|
||||
for i in 0 ..< r:
|
||||
if a[i] > a[r]: continue
|
||||
swap a[i], a[st]
|
||||
inc st
|
||||
|
||||
swap a[r], a[st]
|
||||
|
||||
if k == st: a[st]
|
||||
elif st > k: qselect(a, k, 0, st - 1)
|
||||
else: qselect(a, k, st, inr)
|
||||
|
||||
let x = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
|
||||
for i in 0..9:
|
||||
var y = x
|
||||
echo i, ": ", qselect(y, i)
|
||||
10
Task/Quickselect-algorithm/OCaml/quickselect-algorithm.ocaml
Normal file
10
Task/Quickselect-algorithm/OCaml/quickselect-algorithm.ocaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
let rec quickselect k = function
|
||||
[] -> failwith "empty"
|
||||
| x :: xs -> let ys, zs = List.partition ((>) x) xs in
|
||||
let l = List.length ys in
|
||||
if k < l then
|
||||
quickselect k ys
|
||||
else if k > l then
|
||||
quickselect (k-l-1) zs
|
||||
else
|
||||
x
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
part(list, left, right, pivotIndex)={
|
||||
my(pivotValue=list[pivotIndex],storeIndex=left,t);
|
||||
t=list[pivotIndex];
|
||||
list[pivotIndex]=list[right];
|
||||
list[right]=t;
|
||||
for(i=left,right-1,
|
||||
if(list[i] <= pivotValue,
|
||||
t=list[storeIndex];
|
||||
list[storeIndex]=list[i];
|
||||
list[i]=t;
|
||||
storeIndex++
|
||||
)
|
||||
);
|
||||
t=list[right];
|
||||
list[right]=list[storeIndex];
|
||||
list[storeIndex]=t;
|
||||
storeIndex
|
||||
};
|
||||
quickselect(list, left, right, n)={
|
||||
if(left==right,return(list[left]));
|
||||
my(pivotIndex=part(list, left, right, random(right-left)+left));
|
||||
if(pivotIndex==n,return(list[n]));
|
||||
if(n < pivotIndex,
|
||||
quickselect(list, left, pivotIndex - 1, n)
|
||||
,
|
||||
quickselect(list, pivotIndex + 1, right, n)
|
||||
)
|
||||
};
|
||||
59
Task/Quickselect-algorithm/PL-I/quickselect-algorithm.pli
Normal file
59
Task/Quickselect-algorithm/PL-I/quickselect-algorithm.pli
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
quick: procedure options (main); /* 4 April 2014 */
|
||||
|
||||
partition: procedure (list, left, right, pivot_Index) returns (fixed binary);
|
||||
declare list (*) fixed binary;
|
||||
declare (left, right, pivot_index) fixed binary;
|
||||
declare (store_index, pivot_value) fixed binary;
|
||||
declare I fixed binary;
|
||||
|
||||
pivot_Value = list(pivot_Index);
|
||||
call swap (pivot_Index, right); /* Move pivot to end */
|
||||
store_Index = left;
|
||||
do i = left to right-1;
|
||||
if list(i) < pivot_Value then
|
||||
do;
|
||||
call swap (store_Index, i);
|
||||
store_Index = store_index + 1;
|
||||
end;
|
||||
end;
|
||||
call swap (right, store_Index); /* Move pivot to its final place */
|
||||
return (store_Index);
|
||||
|
||||
swap: procedure (i, j);
|
||||
declare (i, j) fixed binary; declare t fixed binary;
|
||||
|
||||
t = list(i); list(i) = list(j); list(j) = t;
|
||||
end swap;
|
||||
end partition;
|
||||
|
||||
/* Returns the n-th smallest element of list within left..right inclusive */
|
||||
/* (i.e. left <= n <= right). */
|
||||
quick_select: procedure (list, left, right, n) recursive returns (fixed binary);
|
||||
declare list(*) fixed binary;
|
||||
declare (left, right, n) fixed binary;
|
||||
declare pivot_index fixed binary;
|
||||
|
||||
if left = right then /* If the list contains only one element */
|
||||
return ( list(left) ); /* Return that element */
|
||||
pivot_Index = (left+right)/2;
|
||||
/* select a pivot_Index between left and right, */
|
||||
/* e.g. left + Math.floor(Math.random() * (right - left + 1)) */
|
||||
pivot_Index = partition(list, left, right, pivot_Index);
|
||||
/* The pivot is in its final sorted position. */
|
||||
if n = pivot_Index then
|
||||
return ( list(n) );
|
||||
else if n < pivot_Index then
|
||||
return ( quick_select(list, left, pivot_Index - 1, n) );
|
||||
else
|
||||
return ( quick_select(list, pivot_Index + 1, right, n) );
|
||||
|
||||
end quick_select;
|
||||
|
||||
declare a(10) fixed binary static initial (9, 8, 7, 6, 5, 0, 1, 2, 3, 4);
|
||||
declare I fixed binary;
|
||||
|
||||
do i = 1 to 10;
|
||||
put skip edit ('The ', trim(i), '-th element is ', quick_select((a), 1, 10, (i) )) (a);
|
||||
end;
|
||||
|
||||
end quick;
|
||||
19
Task/Quickselect-algorithm/Perl/quickselect-algorithm.pl
Normal file
19
Task/Quickselect-algorithm/Perl/quickselect-algorithm.pl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
my @list = qw(9 8 7 6 5 0 1 2 3 4);
|
||||
print join ' ', map { qselect(\@list, $_) } 1 .. 10 and print "\n";
|
||||
|
||||
sub qselect
|
||||
{
|
||||
my ($list, $k) = @_;
|
||||
my $pivot = @$list[int rand @{ $list } - 1];
|
||||
my @left = grep { $_ < $pivot } @$list;
|
||||
my @right = grep { $_ > $pivot } @$list;
|
||||
if ($k <= @left)
|
||||
{
|
||||
return qselect(\@left, $k);
|
||||
}
|
||||
elsif ($k > @left + 1)
|
||||
{
|
||||
return qselect(\@right, $k - @left - 1);
|
||||
}
|
||||
else { $pivot }
|
||||
}
|
||||
32
Task/Quickselect-algorithm/Phix/quickselect-algorithm.phix
Normal file
32
Task/Quickselect-algorithm/Phix/quickselect-algorithm.phix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">}</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">quick_select</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">left</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">right</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">left</span><span style="color: #0000FF;"><</span><span style="color: #000000;">right</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">object</span> <span style="color: #000000;">pivotv</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">];</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">]}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]}</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">left</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">left</span> <span style="color: #008080;">to</span> <span style="color: #000000;">right</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">pivotv</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">]}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]}</span>
|
||||
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">]}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">]}</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">pos</span><span style="color: #0000FF;">==</span><span style="color: #000000;">k</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">pos</span><span style="color: #0000FF;"><</span><span style="color: #000000;">k</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">left</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">right</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">quick_select</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" %d"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
|
||||
<!--
|
||||
37
Task/Quickselect-algorithm/Picat/quickselect-algorithm.picat
Normal file
37
Task/Quickselect-algorithm/Picat/quickselect-algorithm.picat
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
main =>
|
||||
L = [9,8,7,6,5,0,1,2,3,4],
|
||||
Len = L.len,
|
||||
println([select(L,1,Len,I) : I in 1..Len]),
|
||||
nl.
|
||||
|
||||
select(List, Left, Right, K) = Select =>
|
||||
if Left = Right then
|
||||
Select = List[Left]
|
||||
else
|
||||
PivotIndex = partition(List, Left, Right, random(Left,Right)),
|
||||
if K == PivotIndex then
|
||||
Select = List[K]
|
||||
elseif K < PivotIndex then
|
||||
Select = select(List, Left, PivotIndex-1, K)
|
||||
else
|
||||
Select = select(List, PivotIndex+1, Right, K)
|
||||
end
|
||||
end.
|
||||
|
||||
partition(List, Left, Right, PivotIndex) = StoreIndex =>
|
||||
PivotValue = List[PivotIndex],
|
||||
swap(List,PivotIndex,Right),
|
||||
StoreIndex = Left,
|
||||
foreach(I in Left..Right-1)
|
||||
if List[I] @< PivotValue then
|
||||
swap(List,StoreIndex,I),
|
||||
StoreIndex := StoreIndex+1
|
||||
end
|
||||
end,
|
||||
swap(List,Right,StoreIndex).
|
||||
|
||||
% swap L[I] <=> L[J]
|
||||
swap(L,I,J) =>
|
||||
T = L[I],
|
||||
L[I] := L[J],
|
||||
L[J] := T.
|
||||
30
Task/Quickselect-algorithm/PicoLisp/quickselect-algorithm.l
Normal file
30
Task/Quickselect-algorithm/PicoLisp/quickselect-algorithm.l
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
(seed (in "/dev/urandom" (rd 8)))
|
||||
(de swapL (Lst X Y)
|
||||
(let L (nth Lst Y)
|
||||
(swap
|
||||
L
|
||||
(swap (nth Lst X) (car L)) ) ) )
|
||||
(de partition (Lst L R P)
|
||||
(let V (get Lst P)
|
||||
(swapL Lst R P)
|
||||
(for I (range L R)
|
||||
(and
|
||||
(> V (get Lst I))
|
||||
(swapL Lst L I)
|
||||
(inc 'L) ) )
|
||||
(swapL Lst L R)
|
||||
L ) )
|
||||
(de quick (Lst N L R)
|
||||
(default L (inc N) R (length Lst))
|
||||
(if (= L R)
|
||||
(get Lst L)
|
||||
(let P (partition Lst L R (rand L R))
|
||||
(cond
|
||||
((= N P) (get Lst N))
|
||||
((> P N) (quick Lst N L P))
|
||||
(T (quick Lst N P R)) ) ) ) )
|
||||
(let Lst (9 8 7 6 5 0 1 2 3 4)
|
||||
(println
|
||||
(mapcar
|
||||
'((N) (quick Lst N))
|
||||
(range 0 9) ) ) )
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
function partition($list, $left, $right, $pivotIndex) {
|
||||
$pivotValue = $list[$pivotIndex]
|
||||
$list[$pivotIndex], $list[$right] = $list[$right], $list[$pivotIndex]
|
||||
$storeIndex = $left
|
||||
foreach ($i in $left..($right-1)) {
|
||||
if ($list[$i] -lt $pivotValue) {
|
||||
$list[$storeIndex],$list[$i] = $list[$i], $list[$storeIndex]
|
||||
$storeIndex += 1
|
||||
}
|
||||
}
|
||||
$list[$right],$list[$storeIndex] = $list[$storeIndex], $list[$right]
|
||||
$storeIndex
|
||||
}
|
||||
|
||||
function rank($list, $left, $right, $n) {
|
||||
if ($left -eq $right) {$list[$left]}
|
||||
else {
|
||||
$pivotIndex = Get-Random -Minimum $left -Maximum $right
|
||||
$pivotIndex = partition $list $left $right $pivotIndex
|
||||
if ($n -eq $pivotIndex) {$list[$n]}
|
||||
elseif ($n -lt $pivotIndex) {(rank $list $left ($pivotIndex - 1) $n)}
|
||||
else {(rank $list ($pivotIndex+1) $right $n)}
|
||||
}
|
||||
}
|
||||
|
||||
function quickselect($list) {
|
||||
$right = $list.count-1
|
||||
foreach($left in 0..$right) {rank $list $left $right $left}
|
||||
}
|
||||
$arr = @(9, 8, 7, 6, 5, 0, 1, 2, 3, 4)
|
||||
"$(quickselect $arr)"
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
Procedure QuickPartition (Array L(1), left, right, pivotIndex)
|
||||
pivotValue = L(pivotIndex)
|
||||
Swap L(pivotIndex) , L(right); Move pivot To End
|
||||
storeIndex = left
|
||||
For i=left To right-1
|
||||
If L(i) < pivotValue
|
||||
Swap L(storeIndex),L(i)
|
||||
storeIndex+1
|
||||
EndIf
|
||||
Next i
|
||||
Swap L(right), L(storeIndex) ; Move pivot To its final place
|
||||
ProcedureReturn storeIndex
|
||||
EndProcedure
|
||||
Procedure QuickSelect(Array L(1), left, right, k)
|
||||
Repeat
|
||||
If left = right:ProcedureReturn L(left):EndIf
|
||||
pivotIndex.i= left; Select pivotIndex between left And right
|
||||
pivotIndex= QuickPartition(L(), left, right, pivotIndex)
|
||||
If k = pivotIndex
|
||||
ProcedureReturn L(k)
|
||||
ElseIf k < pivotIndex
|
||||
right= pivotIndex - 1
|
||||
Else
|
||||
left= pivotIndex + 1
|
||||
EndIf
|
||||
ForEver
|
||||
EndProcedure
|
||||
Dim L.i(9)
|
||||
For i=0 To 9
|
||||
Read L(i)
|
||||
Next i
|
||||
DataSection
|
||||
Data.i 9, 8, 7, 6, 5, 0, 1, 2, 3, 4
|
||||
EndDataSection
|
||||
For i=0 To 9
|
||||
Debug QuickSelect(L(),0,9,i)
|
||||
Next i
|
||||
45
Task/Quickselect-algorithm/Python/quickselect-algorithm-1.py
Normal file
45
Task/Quickselect-algorithm/Python/quickselect-algorithm-1.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import random
|
||||
|
||||
def partition(vector, left, right, pivotIndex):
|
||||
pivotValue = vector[pivotIndex]
|
||||
vector[pivotIndex], vector[right] = vector[right], vector[pivotIndex] # Move pivot to end
|
||||
storeIndex = left
|
||||
for i in range(left, right):
|
||||
if vector[i] < pivotValue:
|
||||
vector[storeIndex], vector[i] = vector[i], vector[storeIndex]
|
||||
storeIndex += 1
|
||||
vector[right], vector[storeIndex] = vector[storeIndex], vector[right] # Move pivot to its final place
|
||||
return storeIndex
|
||||
|
||||
def _select(vector, left, right, k):
|
||||
"Returns the k-th smallest, (k >= 0), element of vector within vector[left:right+1] inclusive."
|
||||
while True:
|
||||
pivotIndex = random.randint(left, right) # select pivotIndex between left and right
|
||||
pivotNewIndex = partition(vector, left, right, pivotIndex)
|
||||
pivotDist = pivotNewIndex - left
|
||||
if pivotDist == k:
|
||||
return vector[pivotNewIndex]
|
||||
elif k < pivotDist:
|
||||
right = pivotNewIndex - 1
|
||||
else:
|
||||
k -= pivotDist + 1
|
||||
left = pivotNewIndex + 1
|
||||
|
||||
def select(vector, k, left=None, right=None):
|
||||
"""\
|
||||
Returns the k-th smallest, (k >= 0), element of vector within vector[left:right+1].
|
||||
left, right default to (0, len(vector) - 1) if omitted
|
||||
"""
|
||||
if left is None:
|
||||
left = 0
|
||||
lv1 = len(vector) - 1
|
||||
if right is None:
|
||||
right = lv1
|
||||
assert vector and k >= 0, "Either null vector or k < 0 "
|
||||
assert 0 <= left <= lv1, "left is out of range"
|
||||
assert left <= right <= lv1, "right is out of range"
|
||||
return _select(vector, left, right, k)
|
||||
|
||||
if __name__ == '__main__':
|
||||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
print([select(v, i) for i in range(10)])
|
||||
58
Task/Quickselect-algorithm/Python/quickselect-algorithm-2.py
Normal file
58
Task/Quickselect-algorithm/Python/quickselect-algorithm-2.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
'''Quick select'''
|
||||
|
||||
from functools import reduce
|
||||
|
||||
|
||||
# quickselect :: Ord a => Int -> [a] -> a
|
||||
def quickSelect(k):
|
||||
'''The kth smallest element
|
||||
in the unordered list xs.'''
|
||||
def go(k, xs):
|
||||
x = xs[0]
|
||||
|
||||
def ltx(y):
|
||||
return y < x
|
||||
ys, zs = partition(ltx)(xs[1:])
|
||||
n = len(ys)
|
||||
return go(k, ys) if k < n else (
|
||||
go(k - n - 1, zs) if k > n else x
|
||||
)
|
||||
return lambda xs: go(k, xs) if xs else None
|
||||
|
||||
|
||||
# TEST ----------------------------------------------------
|
||||
# main :: IO ()
|
||||
def main():
|
||||
'''Test'''
|
||||
|
||||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
print(list(map(
|
||||
flip(quickSelect)(v),
|
||||
range(0, len(v))
|
||||
)))
|
||||
|
||||
|
||||
# GENERIC -------------------------------------------------
|
||||
|
||||
|
||||
# flip :: (a -> b -> c) -> b -> a -> c
|
||||
def flip(f):
|
||||
'''The (curried) function f with its
|
||||
arguments reversed.'''
|
||||
return lambda a: lambda b: f(b)(a)
|
||||
|
||||
|
||||
# partition :: (a -> Bool) -> [a] -> ([a], [a])
|
||||
def partition(p):
|
||||
'''The pair of lists of those elements in xs
|
||||
which respectively do, and don't
|
||||
satisfy the predicate p.'''
|
||||
def go(a, x):
|
||||
ts, fs = a
|
||||
return (ts + [x], fs) if p(x) else (ts, fs + [x])
|
||||
return lambda xs: reduce(go, xs, ([], []))
|
||||
|
||||
|
||||
# MAIN ---
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
32
Task/Quickselect-algorithm/REXX/quickselect-algorithm-1.rexx
Normal file
32
Task/Quickselect-algorithm/REXX/quickselect-algorithm-1.rexx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*REXX program sorts a list (which may be numbers) by using the quick select algorithm.*/
|
||||
parse arg list; if list='' then list= 9 8 7 6 5 0 1 2 3 4 /*Not given? Use default.*/
|
||||
say right('list: ', 22) list
|
||||
#= words(list)
|
||||
do i=1 for #; @.i= word(list, i) /*assign all the items ──► @. (array). */
|
||||
end /*i*/ /* [↑] #: number of items in the list.*/
|
||||
say
|
||||
do j=1 for # /*show 1 ──► # items place and value.*/
|
||||
say right('item', 20) right(j, length(#))", value: " qSel(1, #, j)
|
||||
end /*j*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
qPart: procedure expose @.; parse arg L 1 ?,R,X; xVal= @.X
|
||||
parse value @.X @.R with @.R @.X /*swap the two names items (X and R). */
|
||||
do k=L to R-1 /*process the left side of the list. */
|
||||
if @.k>xVal then iterate /*when an item > item #X, then skip it.*/
|
||||
parse value @.? @.k with @.k @.? /*swap the two named items (? and K). */
|
||||
?= ? + 1 /*bump the item number (point to next).*/
|
||||
end /*k*/
|
||||
parse value @.R @.? with @.? @.R /*swap the two named items (R and ?). */
|
||||
return ? /*return the item number to invoker. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
qSel: procedure expose @.; parse arg L,R,z; if L==R then return @.L /*only one item?*/
|
||||
do forever /*keep searching until we're all done. */
|
||||
new= qPart(L, R, (L+R) % 2) /*partition the list into roughly ½. */
|
||||
$= new - L + 1 /*calculate pivot distance less L+1. */
|
||||
if $==z then return @.new /*we're all done with this pivot part. */
|
||||
else if z<$ then R= new-1 /*decrease the right half of the array.*/
|
||||
else do; z= z-$ /*decrease the distance. */
|
||||
L= new+1 /*increase the left half *f the array.*/
|
||||
end
|
||||
end /*forever*/
|
||||
34
Task/Quickselect-algorithm/REXX/quickselect-algorithm-2.rexx
Normal file
34
Task/Quickselect-algorithm/REXX/quickselect-algorithm-2.rexx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*REXX program sorts a list (which may be numbers) by using the quick select algorithm. */
|
||||
parse arg list; if list='' then list= 9 8 7 6 5 0 1 2 3 4 /*Not given? Use default.*/
|
||||
say right('list: ', 22) list
|
||||
#= words(list)
|
||||
do i=1 for #; @.i= word(list, i) /*assign all the items ──► @. (array). */
|
||||
end /*i*/ /* [↑] #: number of items in the list.*/
|
||||
say
|
||||
do j=1 for # /*show 1 ──► # items place and value.*/
|
||||
say right('item', 20) right(j, length(#))", value: " qSel(1, #, j)
|
||||
end /*j*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
qPart: procedure expose @.; parse arg L 1 ?,R,X; xVal= @.X
|
||||
call swap X,R /*swap the two named items (X and R). */
|
||||
do k=L to R-1 /*process the left side of the list. */
|
||||
if @.k>xVal then iterate /*when an item > item #X, then skip it.*/
|
||||
call swap ?,k /*swap the two named items (? and K). */
|
||||
?= ? + 1 /*bump the item number (point to next).*/
|
||||
end /*k*/
|
||||
call swap R,? /*swap the two named items (R and ?). */
|
||||
return ? /*return the item number to invoker. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
qSel: procedure expose @.; parse arg L,R,z; if L==R then return @.L /*only one item?*/
|
||||
do forever /*keep searching until we're all done. */
|
||||
new= qPart(L, R, (L+R) % 2) /*partition the list into roughly ½. */
|
||||
$= new - L + 1 /*calculate the pivot distance less L+1*/
|
||||
if $==z then return @.new /*we're all done with this pivot part. */
|
||||
else if z<$ then R= new-1 /*decrease the right half of the array.*/
|
||||
else do; z= z-$ /*decrease the distance. */
|
||||
L= new+1 /*increase the left half of the array.*/
|
||||
end
|
||||
end /*forever*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
swap: parse arg _1,_2; parse value @._1 @._2 with @._2 @._1; return /*swap 2 items.*/
|
||||
11
Task/Quickselect-algorithm/Racket/quickselect-algorithm.rkt
Normal file
11
Task/Quickselect-algorithm/Racket/quickselect-algorithm.rkt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(define (quickselect A k)
|
||||
(define pivot (list-ref A (random (length A))))
|
||||
(define A1 (filter (curry > pivot) A))
|
||||
(define A2 (filter (curry < pivot) A))
|
||||
(cond
|
||||
[(<= k (length A1)) (quickselect A1 k)]
|
||||
[(> k (- (length A) (length A2))) (quickselect A2 (- k (- (length A) (length A2))))]
|
||||
[else pivot]))
|
||||
|
||||
(define a '(9 8 7 6 5 0 1 2 3 4))
|
||||
(display (string-join (map number->string (for/list ([k 10]) (quickselect a (+ 1 k)))) ", "))
|
||||
42
Task/Quickselect-algorithm/Raku/quickselect-algorithm.raku
Normal file
42
Task/Quickselect-algorithm/Raku/quickselect-algorithm.raku
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
my @v = <9 8 7 6 5 0 1 2 3 4>;
|
||||
say map { select(@v, $_) }, 1 .. 10;
|
||||
|
||||
sub partition(@vector, $left, $right, $pivot-index) {
|
||||
my $pivot-value = @vector[$pivot-index];
|
||||
@vector[$pivot-index, $right] = @vector[$right, $pivot-index];
|
||||
my $store-index = $left;
|
||||
for $left ..^ $right -> $i {
|
||||
if @vector[$i] < $pivot-value {
|
||||
@vector[$store-index, $i] = @vector[$i, $store-index];
|
||||
$store-index++;
|
||||
}
|
||||
}
|
||||
@vector[$right, $store-index] = @vector[$store-index, $right];
|
||||
return $store-index;
|
||||
}
|
||||
|
||||
sub select( @vector,
|
||||
\k where 1 .. @vector,
|
||||
\l where 0 .. @vector = 0,
|
||||
\r where l .. @vector = @vector.end ) {
|
||||
|
||||
my ($k, $left, $right) = k, l, r;
|
||||
|
||||
loop {
|
||||
my $pivot-index = ($left..$right).pick;
|
||||
my $pivot-new-index = partition(@vector, $left, $right, $pivot-index);
|
||||
my $pivot-dist = $pivot-new-index - $left + 1;
|
||||
given $pivot-dist <=> $k {
|
||||
when Same {
|
||||
return @vector[$pivot-new-index];
|
||||
}
|
||||
when More {
|
||||
$right = $pivot-new-index - 1;
|
||||
}
|
||||
when Less {
|
||||
$k -= $pivot-dist;
|
||||
$left = $pivot-new-index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Task/Quickselect-algorithm/Ring/quickselect-algorithm.ring
Normal file
20
Task/Quickselect-algorithm/Ring/quickselect-algorithm.ring
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
aList = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
see partition(aList, 9, 4, 2) + nl
|
||||
|
||||
func partition list, left, right, pivotIndex
|
||||
pivotValue = list[pivotIndex]
|
||||
temp = list[pivotIndex]
|
||||
list[pivotIndex] = list[right]
|
||||
list[right] = temp
|
||||
storeIndex = left
|
||||
for i = left to right-1
|
||||
if list[i] < pivotValue
|
||||
temp = list[storeIndex]
|
||||
list[storeIndex] = list[i]
|
||||
list[i] = temp
|
||||
storeIndex++ ok
|
||||
temp = list[right]
|
||||
list[right] = list[storeIndex]
|
||||
list[storeIndex] = temp
|
||||
next
|
||||
return storeIndex
|
||||
18
Task/Quickselect-algorithm/Ruby/quickselect-algorithm.rb
Normal file
18
Task/Quickselect-algorithm/Ruby/quickselect-algorithm.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
def quickselect(a, k)
|
||||
arr = a.dup # we will be modifying it
|
||||
loop do
|
||||
pivot = arr.delete_at(rand(arr.length))
|
||||
left, right = arr.partition { |x| x < pivot }
|
||||
if k == left.length
|
||||
return pivot
|
||||
elsif k < left.length
|
||||
arr = left
|
||||
else
|
||||
k = k - left.length - 1
|
||||
arr = right
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
p v.each_index.map { |i| quickselect(v, i) }
|
||||
51
Task/Quickselect-algorithm/Rust/quickselect-algorithm.rust
Normal file
51
Task/Quickselect-algorithm/Rust/quickselect-algorithm.rust
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// See https://en.wikipedia.org/wiki/Quickselect
|
||||
|
||||
fn partition<T: PartialOrd>(a: &mut [T], left: usize, right: usize, pivot: usize) -> usize {
|
||||
a.swap(pivot, right);
|
||||
let mut store_index = left;
|
||||
for i in left..right {
|
||||
if a[i] < a[right] {
|
||||
a.swap(store_index, i);
|
||||
store_index += 1;
|
||||
}
|
||||
}
|
||||
a.swap(right, store_index);
|
||||
store_index
|
||||
}
|
||||
|
||||
fn pivot_index(left: usize, right: usize) -> usize {
|
||||
return left + (right - left) / 2;
|
||||
}
|
||||
|
||||
fn select<T: PartialOrd>(a: &mut [T], mut left: usize, mut right: usize, n: usize) {
|
||||
loop {
|
||||
if left == right {
|
||||
break;
|
||||
}
|
||||
let mut pivot = pivot_index(left, right);
|
||||
pivot = partition(a, left, right, pivot);
|
||||
if n == pivot {
|
||||
break;
|
||||
} else if n < pivot {
|
||||
right = pivot - 1;
|
||||
} else {
|
||||
left = pivot + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rearranges the elements of 'a' such that the element at index 'n' is
|
||||
// the same as it would be if the array were sorted, smaller elements are
|
||||
// to the left of it and larger elements are to its right.
|
||||
fn nth_element<T: PartialOrd>(a: &mut [T], n: usize) {
|
||||
select(a, 0, a.len() - 1, n);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = vec![9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
for n in 0..a.len() {
|
||||
let mut b = a.clone();
|
||||
nth_element(&mut b, n);
|
||||
println!("n = {}, nth element = {}", n + 1, b[n]);
|
||||
}
|
||||
}
|
||||
20
Task/Quickselect-algorithm/Scala/quickselect-algorithm.scala
Normal file
20
Task/Quickselect-algorithm/Scala/quickselect-algorithm.scala
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import scala.util.Random
|
||||
|
||||
object QuickSelect {
|
||||
def quickSelect[A <% Ordered[A]](seq: Seq[A], n: Int, rand: Random = new Random): A = {
|
||||
val pivot = rand.nextInt(seq.length);
|
||||
val (left, right) = seq.partition(_ < seq(pivot))
|
||||
if (left.length == n) {
|
||||
seq(pivot)
|
||||
} else if (left.length < n) {
|
||||
quickSelect(right, n - left.length, rand)
|
||||
} else {
|
||||
quickSelect(left, n, rand)
|
||||
}
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val v = Array(9, 8, 7, 6, 5, 0, 1, 2, 3, 4)
|
||||
println((0 until v.length).map(quickSelect(v, _)).mkString(", "))
|
||||
}
|
||||
}
|
||||
134
Task/Quickselect-algorithm/Scheme/quickselect-algorithm.ss
Normal file
134
Task/Quickselect-algorithm/Scheme/quickselect-algorithm.ss
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
;;
|
||||
;; Quickselect with random pivot.
|
||||
;;
|
||||
;; Such a pivot provides O(n) worst-case *expected* time.
|
||||
;;
|
||||
;; One can get true O(n) time by using "median of medians" to choose
|
||||
;; the pivot, but quickselect with a median of medians pivot is a
|
||||
;; complicated algorithm. See
|
||||
;; https://en.wikipedia.org/w/index.php?title=Median_of_medians&oldid=1082505985
|
||||
;;
|
||||
;; Random pivot has the further advantage that it does not require any
|
||||
;; comparisons of array elements.
|
||||
;;
|
||||
;; By the way, SRFI-132 specifies that vector-select! have O(n)
|
||||
;; running time, and yet the reference implementation (as of 21 May
|
||||
;; 2022) uses random pivot. I am pretty sure you cannot count on an
|
||||
;; implementation having "true" O(n) behavior.
|
||||
;;
|
||||
|
||||
(import (scheme base))
|
||||
(import (scheme case-lambda))
|
||||
(import (scheme write))
|
||||
(import (only (scheme process-context) exit))
|
||||
(import (only (srfi 27) random-integer))
|
||||
|
||||
(define (vector-swap! vec i j)
|
||||
(let ((xi (vector-ref vec i))
|
||||
(xj (vector-ref vec j)))
|
||||
(vector-set! vec i xj)
|
||||
(vector-set! vec j xi)))
|
||||
|
||||
(define (search-right <? pivot i j vec)
|
||||
(let loop ((i i))
|
||||
(cond ((= i j) i)
|
||||
((<? pivot (vector-ref vec i)) i)
|
||||
(else (loop (+ i 1))))))
|
||||
|
||||
(define (search-left <? pivot i j vec)
|
||||
(let loop ((j j))
|
||||
(cond ((= i j) j)
|
||||
((<? (vector-ref vec j) pivot) j)
|
||||
(else (loop (- j 1))))))
|
||||
|
||||
(define (partition <? pivot i-first i-last vec)
|
||||
;; Partition a subvector into two halves: one with elements less
|
||||
;; than or equal to a pivot, the other with elements greater than or
|
||||
;; equal to a pivot. Returns an index where anything less than the
|
||||
;; pivot is to the left of the index, and anything greater than the
|
||||
;; pivot is either at the index or to its right. The implementation
|
||||
;; is tail-recursive.
|
||||
(let loop ((i (- i-first 1))
|
||||
(j (+ i-last 1)))
|
||||
(if (= i j)
|
||||
i
|
||||
(let ((i (search-right <? pivot (+ i 1) j vec)))
|
||||
(if (= i j)
|
||||
i
|
||||
(let ((j (search-left <? pivot i (- j 1) vec)))
|
||||
(vector-swap! vec i j)
|
||||
(loop i j)))))))
|
||||
|
||||
(define (partition-around-random-pivot <? i-first i-last vec)
|
||||
(let* ((i-pivot (+ i-first (random-integer (- i-last i-first -1))))
|
||||
(pivot (vector-ref vec i-pivot)))
|
||||
|
||||
;; Move the last element to where the pivot had been. Perhaps the
|
||||
;; pivot was already the last element, of course. In any case, we
|
||||
;; shall partition only from I_first to I_last - 1.
|
||||
(vector-set! vec i-pivot (vector-ref vec i-last))
|
||||
|
||||
;; Partition the array in the range I_first..I_last - 1, leaving
|
||||
;; out the last element (which now can be considered garbage).
|
||||
(let ((i-final (partition <? pivot i-first (- i-last 1) vec)))
|
||||
|
||||
;; Now everything that is less than the pivot is to the left of
|
||||
;; I_final.
|
||||
|
||||
;; Put the pivot at I_final, moving the element that had been
|
||||
;; there to the end. If I_final = I_last, then this element is
|
||||
;; actually garbage and will be overwritten with the pivot,
|
||||
;; which turns out to be the greatest element. Otherwise, the
|
||||
;; moved element is not less than the pivot and so the
|
||||
;; partitioning is preserved.
|
||||
(vector-set! vec i-last (vector-ref vec i-final))
|
||||
(vector-set! vec i-final pivot)
|
||||
|
||||
;; Return i-final, the final position of the pivot element.
|
||||
i-final)))
|
||||
|
||||
(define quickselect!
|
||||
(case-lambda
|
||||
|
||||
((<? vec k)
|
||||
;; Select the (k+1)st least element of vec.
|
||||
(quickselect! <? 0 (- (vector-length vec) 1) vec k))
|
||||
|
||||
((<? i-first i-last vec k)
|
||||
;; Select the (k+1)st least element of vec[i-first..i-last].
|
||||
(unless (and (<= 0 k) (<= k (- i-last i-first)))
|
||||
;; Here you more likely want to raise an exception, but how to
|
||||
;; do so is not specified in R7RS small. (It *is* specified in
|
||||
;; R6RS, but R6RS features are widely unsupported by Schemes.)
|
||||
(display "out of range" (current-error-port))
|
||||
(exit 1))
|
||||
(let ((k (+ k i-first))) ; Adjust k for index range.
|
||||
(let loop ((i-first i-first)
|
||||
(i-last i-last))
|
||||
(if (= i-first i-last)
|
||||
(vector-ref vec i-first)
|
||||
(let ((i-final (partition-around-random-pivot
|
||||
<? i-first i-last vec)))
|
||||
;; Compare i-final and k, to see what to do next.
|
||||
(cond ((< i-final k) (loop (+ i-final 1) i-last))
|
||||
((< k i-final) (loop i-first (- i-final 1)))
|
||||
(else (vector-ref vec i-final))))))))))
|
||||
|
||||
(define (print-kth <? k numbers-vector)
|
||||
(let* ((vec (vector-copy numbers-vector))
|
||||
(elem (quickselect! <? vec (- k 1))))
|
||||
(display " ")
|
||||
(display elem)))
|
||||
|
||||
(define example-numbers #(9 8 7 6 5 0 1 2 3 4))
|
||||
|
||||
(display "With < as order predicate: ")
|
||||
(do ((k 1 (+ k 1)))
|
||||
((= k 11))
|
||||
(print-kth < k example-numbers))
|
||||
(newline)
|
||||
(display "With > as order predicate: ")
|
||||
(do ((k 1 (+ k 1)))
|
||||
((= k 11))
|
||||
(print-kth > k example-numbers))
|
||||
(newline)
|
||||
14
Task/Quickselect-algorithm/Sidef/quickselect-algorithm.sidef
Normal file
14
Task/Quickselect-algorithm/Sidef/quickselect-algorithm.sidef
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
func quickselect(a, k) {
|
||||
var pivot = a.pick;
|
||||
var left = a.grep{|i| i < pivot};
|
||||
var right = a.grep{|i| i > pivot};
|
||||
|
||||
given(var l = left.len) {
|
||||
when (k) { pivot }
|
||||
case (k < l) { __FUNC__(left, k) }
|
||||
default { __FUNC__(right, k - l - 1) }
|
||||
}
|
||||
}
|
||||
|
||||
var v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
say v.range.map{|i| quickselect(v, i)};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fun quickselect (_, _, []) = raise Fail "empty"
|
||||
| quickselect (k, cmp, x :: xs) = let
|
||||
val (ys, zs) = List.partition (fn y => cmp (y, x) = LESS) xs
|
||||
val l = length ys
|
||||
in
|
||||
if k < l then
|
||||
quickselect (k, cmp, ys)
|
||||
else if k > l then
|
||||
quickselect (k-l-1, cmp, zs)
|
||||
else
|
||||
x
|
||||
end
|
||||
20
Task/Quickselect-algorithm/Swift/quickselect-algorithm.swift
Normal file
20
Task/Quickselect-algorithm/Swift/quickselect-algorithm.swift
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
func select<T where T : Comparable>(var elements: [T], n: Int) -> T {
|
||||
var r = indices(elements)
|
||||
while true {
|
||||
let pivotIndex = partition(&elements, r)
|
||||
if n == pivotIndex {
|
||||
return elements[pivotIndex]
|
||||
} else if n < pivotIndex {
|
||||
r.endIndex = pivotIndex
|
||||
} else {
|
||||
r.startIndex = pivotIndex+1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 ..< 10 {
|
||||
let a = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
print(select(a, i))
|
||||
if i < 9 { print(", ") }
|
||||
}
|
||||
println()
|
||||
50
Task/Quickselect-algorithm/Tcl/quickselect-algorithm-1.tcl
Normal file
50
Task/Quickselect-algorithm/Tcl/quickselect-algorithm-1.tcl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Swap the values at two indices of a list
|
||||
proc swap {list i j} {
|
||||
upvar 1 $list l
|
||||
set tmp [lindex $l $i]
|
||||
lset l $i [lindex $l $j]
|
||||
lset l $j $tmp
|
||||
}
|
||||
|
||||
proc quickselect {vector k {left 0} {right ""}} {
|
||||
set last [expr {[llength $vector] - 1}]
|
||||
if {$right eq ""} {
|
||||
set right $last
|
||||
}
|
||||
# Sanity assertions
|
||||
if {![llength $vector] || $k <= 0} {
|
||||
error "Either empty vector, or k <= 0"
|
||||
} elseif {![tcl::mathop::<= 0 $left $last]} {
|
||||
error "left is out of range"
|
||||
} elseif {![tcl::mathop::<= $left $right $last]} {
|
||||
error "right is out of range"
|
||||
}
|
||||
|
||||
# the _select core, inlined
|
||||
while 1 {
|
||||
set pivotIndex [expr {int(rand()*($right-$left))+$left}]
|
||||
|
||||
# the partition core, inlined
|
||||
set pivotValue [lindex $vector $pivotIndex]
|
||||
swap vector $pivotIndex $right
|
||||
set storeIndex $left
|
||||
for {set i $left} {$i <= $right} {incr i} {
|
||||
if {[lindex $vector $i] < $pivotValue} {
|
||||
swap vector $storeIndex $i
|
||||
incr storeIndex
|
||||
}
|
||||
}
|
||||
swap vector $right $storeIndex
|
||||
set pivotNewIndex $storeIndex
|
||||
|
||||
set pivotDist [expr {$pivotNewIndex - $left + 1}]
|
||||
if {$pivotDist == $k} {
|
||||
return [lindex $vector $pivotNewIndex]
|
||||
} elseif {$k < $pivotDist} {
|
||||
set right [expr {$pivotNewIndex - 1}]
|
||||
} else {
|
||||
set k [expr {$k - $pivotDist}]
|
||||
set left [expr {$pivotNewIndex + 1}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
set v {9 8 7 6 5 0 1 2 3 4}
|
||||
foreach i {1 2 3 4 5 6 7 8 9 10} {
|
||||
puts "$i => [quickselect $v $i]"
|
||||
}
|
||||
41
Task/Quickselect-algorithm/VBA/quickselect-algorithm.vba
Normal file
41
Task/Quickselect-algorithm/VBA/quickselect-algorithm.vba
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Dim s As Variant
|
||||
Private Function quick_select(ByRef s As Variant, k As Integer) As Integer
|
||||
Dim left As Integer, right As Integer, pos As Integer
|
||||
Dim pivotValue As Integer, tmp As Integer
|
||||
left = 1: right = UBound(s)
|
||||
Do While left < right
|
||||
pivotValue = s(k)
|
||||
tmp = s(k)
|
||||
s(k) = s(right)
|
||||
s(right) = tmp
|
||||
pos = left
|
||||
For i = left To right
|
||||
If s(i) < pivotValue Then
|
||||
tmp = s(i)
|
||||
s(i) = s(pos)
|
||||
s(pos) = tmp
|
||||
pos = pos + 1
|
||||
End If
|
||||
Next i
|
||||
tmp = s(right)
|
||||
s(right) = s(pos)
|
||||
s(pos) = tmp
|
||||
If pos = k Then
|
||||
Exit Do
|
||||
End If
|
||||
If pos < k Then
|
||||
left = pos + 1
|
||||
Else
|
||||
right = pos - 1
|
||||
End If
|
||||
Loop
|
||||
quick_select = s(k)
|
||||
End Function
|
||||
Public Sub main()
|
||||
Dim r As Integer, i As Integer
|
||||
s = [{9, 8, 7, 6, 5, 0, 1, 2, 3, 4}]
|
||||
For i = 1 To 10
|
||||
r = quick_select(s, i) 's is ByRef parameter
|
||||
Debug.Print IIf(i < 10, r & ", ", "" & r);
|
||||
Next i
|
||||
End Sub
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import "/sort" for Find
|
||||
|
||||
var a = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
|
||||
for (k in 0..9) {
|
||||
System.write(Find.quick(a, k))
|
||||
if (k < 9) System.write(", ")
|
||||
}
|
||||
System.print()
|
||||
34
Task/Quickselect-algorithm/XPL0/quickselect-algorithm.xpl0
Normal file
34
Task/Quickselect-algorithm/XPL0/quickselect-algorithm.xpl0
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
func QuickSelect(List, Len, K);
|
||||
int List, Len, K;
|
||||
int Px, Pv, Last, I, J, T;
|
||||
[loop [\\partition
|
||||
Px:= Len/2;
|
||||
Pv:= List(Px);
|
||||
Last:= Len-1;
|
||||
T:= List(Px); List(Px):= List(Last); List(Last):= T;
|
||||
I:= 0;
|
||||
for J:= 0 to Last-1 do
|
||||
[if List(J) < Pv then
|
||||
[T:= List(I); List(I):= List(J); List(J):= T;
|
||||
I:= I+1;
|
||||
];
|
||||
];
|
||||
\\select
|
||||
if I = K then return Pv;
|
||||
|
||||
if K < I then Len:= I
|
||||
else [T:= List(I); List(I):= List(Last); List(Last):= T;
|
||||
List:= @List(I+1);
|
||||
Len:= Last - I;
|
||||
K:= K - (I+1);
|
||||
];
|
||||
];
|
||||
];
|
||||
|
||||
int V, K;
|
||||
[V:= [9, 8, 7, 6, 5, 0, 1, 2, 3, 4];
|
||||
for K:= 0 to 10-1 do
|
||||
[IntOut(0, QuickSelect(V, 10, K));
|
||||
ChOut(0, ^ );
|
||||
];
|
||||
]
|
||||
23
Task/Quickselect-algorithm/Zkl/quickselect-algorithm-1.zkl
Normal file
23
Task/Quickselect-algorithm/Zkl/quickselect-algorithm-1.zkl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
fcn qselect(list,nth){ // in place quick select
|
||||
fcn(list,left,right,nth){
|
||||
if (left==right) return(list[left]);
|
||||
pivotIndex:=(left+right)/2; // or median of first,middle,last
|
||||
|
||||
// partition
|
||||
pivot:=list[pivotIndex];
|
||||
list.swap(pivotIndex,right); // move pivot to end
|
||||
pivotIndex := left;
|
||||
i:=left; do(right-left){ // foreach i in ([left..right-1])
|
||||
if (list[i] < pivot){
|
||||
list.swap(i,pivotIndex);
|
||||
pivotIndex += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
list.swap(pivotIndex,right); // move pivot to final place
|
||||
|
||||
if (nth==pivotIndex) return(list[nth]);
|
||||
if (nth<pivotIndex) return(self.fcn(list,left,pivotIndex-1,nth));
|
||||
return(self.fcn(list,pivotIndex+1,right,nth));
|
||||
}(list.copy(),0,list.len()-1,nth);
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
list:=T(10, 9, 8, 7, 6, 1, 2, 3, 4, 5);
|
||||
foreach nth in (list.len()){ println(nth,": ",qselect(list,nth)) }
|
||||
Loading…
Add table
Add a link
Reference in a new issue