Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
category:
- Sorting
from: http://rosettacode.org/wiki/Quickselect_algorithm
note: Sorting Algorithms

View 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>

View 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)))

View file

@ -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

View 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
(*------------------------------------------------------------------*)

View file

@ -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

View 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;
----------------------------------------------------------------------

View file

@ -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

View file

@ -0,0 +1 @@
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

View file

@ -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

View file

@ -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

View file

@ -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
}

View 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;
}

View 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;
}

View 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
}
}

View 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;
}

View 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

View 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.

View file

@ -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)))

View 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.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

View 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], " ");
}
}

View 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;
}

View file

@ -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.

View file

@ -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
.

View file

@ -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

View 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.

View 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

View file

@ -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

View 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.

View file

@ -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

View 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))
}
}

View 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)])
}
}

View 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])

View 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

View 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.
)

View file

@ -0,0 +1,2 @@
8 quickselect 9, 8, 7, 6, 5, 0, 1, 2, 3, 4
8

View 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

View 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();
}
}

View file

@ -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);
}
}

View file

@ -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) });

View file

@ -0,0 +1 @@
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

View file

@ -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));
})();

View file

@ -0,0 +1 @@
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

View 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;

View 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) => \(.)"

View 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
$

View file

@ -0,0 +1,2 @@
v = [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
@show v partialsort(v, 1:10)

View file

@ -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()
}

View 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

View 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)):

View file

@ -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]

View 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:

View file

@ -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

View 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)

View 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

View file

@ -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)
)
};

View 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;

View 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 }
}

View 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>
<!--

View 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.

View 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) ) ) )

View file

@ -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)"

View file

@ -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

View 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)])

View 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()

View 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*/

View 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.*/

View 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)))) ", "))

View 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;
}
}
}
}

View 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

View 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) }

View 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]);
}
}

View 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(", "))
}
}

View 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)

View 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)};

View file

@ -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

View 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()

View 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}]
}
}
}

View file

@ -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]"
}

View 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

View file

@ -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()

View 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, ^ );
];
]

View 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);
}

View file

@ -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)) }