Skip to content

Commit d9949eb

Browse files
authored
Add Quick Sort in Tcl (#5075)
1 parent ee07443 commit d9949eb

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

archive/t/tcl/quick-sort.tcl

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
proc usage {} {
2+
puts stderr {Usage: please provide a list of at least two integers to sort in the format "1, 2, 3, 4, 5"}
3+
exit 1
4+
}
5+
6+
proc parseList {s} {
7+
set tokens [split [string trim $s] ","]
8+
if {[llength $tokens] < 2} { usage }
9+
10+
set result {}
11+
foreach token $tokens {
12+
set t [string trim $token]
13+
if {$t eq "" || [catch {expr {int($t)}} val]} usage
14+
lappend result $val
15+
}
16+
return $result
17+
}
18+
19+
proc swap {varName i j} {
20+
upvar 1 $varName lst
21+
if {$i == $j} return
22+
set tmp [lindex $lst $i]
23+
lset lst $i [lindex $lst $j]
24+
lset lst $j $tmp
25+
}
26+
27+
proc medianOfThree {varName a b c} {
28+
upvar 1 $varName lst
29+
set va [lindex $lst $a]
30+
set vb [lindex $lst $b]
31+
set vc [lindex $lst $c]
32+
if {$va <= $vb} {
33+
if {$vb <= $vc} {
34+
return $b
35+
} elseif {$va <= $vc} {
36+
return $c
37+
} else {
38+
return $a
39+
}
40+
} else {
41+
if {$va <= $vc} {
42+
return $a
43+
} elseif {$vb <= $vc} {
44+
return $c
45+
} else {
46+
return $b
47+
}
48+
}
49+
}
50+
51+
proc medianOfNine {varName left right} {
52+
upvar 1 $varName lst
53+
set n [expr {$right - $left}]
54+
if {$n < 8} {
55+
set mid [expr {$left + $n / 2}]
56+
return [medianOfThree lst $left $mid $right]
57+
}
58+
set step [expr {$n / 8}]
59+
set mid [expr {$left + $n / 2}]
60+
set m1 [medianOfThree lst $left [expr {$left+$step}] [expr {$left+2*$step}]]
61+
set m2 [medianOfThree lst [expr {$mid-$step}] $mid [expr {$mid+$step}]]
62+
set m3 [medianOfThree lst [expr {$right-2*$step}] [expr {$right-$step}] $right]
63+
return [medianOfThree lst $m1 $m2 $m3]
64+
}
65+
66+
proc quicksortInPlace {varName left right} {
67+
upvar 1 $varName lst
68+
69+
while {$left < $right} {
70+
# median-of-nine pivot
71+
set pivotIndex [medianOfNine lst $left $right]
72+
set pivotValue [lindex $lst $pivotIndex]
73+
swap lst $pivotIndex $right
74+
75+
# three-way partition
76+
set i $left
77+
set j $right
78+
set k $left
79+
while {$k <= $j} {
80+
set val [lindex $lst $k]
81+
if {$val < $pivotValue} {
82+
swap lst $k $i
83+
incr i
84+
incr k
85+
} elseif {$val > $pivotValue} {
86+
swap lst $k $j
87+
incr j -1
88+
} else {
89+
incr k
90+
}
91+
}
92+
93+
# recurse on smaller side first (tail recursion elimination)
94+
set leftEnd [expr {$i - 1}]
95+
set rightStart [expr {$j + 1}]
96+
if {[expr {$leftEnd - $left}] < [expr {$right - $rightStart}]} {
97+
if {$left < $leftEnd} {
98+
quicksortInPlace lst $left $leftEnd
99+
}
100+
set left $rightStart
101+
} else {
102+
if {$rightStart < $right} {
103+
quicksortInPlace lst $rightStart $right
104+
}
105+
set right $leftEnd
106+
}
107+
}
108+
}
109+
110+
proc quicksort {lst} {
111+
set n [llength $lst]
112+
if {$n <= 1} { return $lst }
113+
quicksortInPlace lst 0 [expr {$n - 1}]
114+
return $lst
115+
}
116+
117+
proc formatList {lst} { return [join $lst ", "] }
118+
119+
if {$argc != 1} { usage }
120+
121+
set numbers [parseList [lindex $argv 0]]
122+
puts [formatList [quicksort $numbers]]
123+

0 commit comments

Comments
 (0)