Dropsort, navržený Davidem Morganem-Marem, je rychlý řadící algoritmus s jedním průchodem, vhodný pro různá nasazení.
Popis algoritmu
Dropsort se spouští na řazení seznamu čísel, které prozkoumává v sekvenci, počínaje druhým číslem ze seznamu. Pokud je číslo menší než předcházející, pak jej ze seznamu odstraní. V opačném případě je ve správném pořadí, takže jej ponechá. Pak se přesune na další číslo. Po jednom průchodu algoritmem obsahuje seznam pouze čísla, která jsou alespoň tak velká jako předchozí číslo v seznamu. Jinými slovy, seznam bude setříděn!
Analýza
Dropsort vyžaduje přesně n-1 porovnání k seřazení sezanmu o délce n, což z něj dělá algoritmus O(n), tedy lepší než typické algoritmy O(n logn), standardně používané pro seřazení.
Dropsort je algoritmus, známý jako ztrátový algoritmus. Vytváří rychlé výsledky, které jsou správné, ale s velkou pravděpodobností ztrácí vstupní data. I když se může zdát, že v počítačových vědách je ztrátový algoritmus nežádoucí, přesto jsou ztrátové algoritmy velmi přijatelnou částí počítačových věd. Příkladem může být populární kompresní obrazový formát JPEG, těšící se velké popularitě. Stejně tak si i dropsort nárokuje své místo na slunci v podobě třídění dat na poli finančnictví, záznamů dat pro vládu a výzkum vesmíru.
Zdroje
Jeremy Kent implementoval Dropsort! Tedy, ne zcela. Dle jeho vlastních slov:
Toto je implementace třídícího algoritmu s využitím DropSort. Volám Dropsort, ovšem nechávám si odstraněné hodnoty, pak seznam těchto hodnot převrátím a opět rekurzivně volám DropSort. (Protože cokoliv, co nebylo seřazeno od nejmenšího po největší musí být logicky seřazeno od největšího po nejmenší).
Jeremy KentNíže uvádíme jak Kentův kód v Pythonu, tak i nejkratší implemetace DropSortu v jiných jazycích.
Kód
01.
## DropSort algorithm
02.
## O(n log n) -- good constants
for
data with some ordering;
03.
## bad
for
randomly-distributed data
04.
##
05.
## (c)
2009
Jeremiah Kent
06.
## ibiwan
@gmail
.com
07.
##
08.
## inspired by David Morgan-Mar's Dropsort algorithm,
09.
## found at http:
//www.dangermouse.net/esoteric/dropsort.html
10.
11.
class
stats:
12.
def __init__(self):
13.
self.comparisons =
0
; self.copies =
0
; self.merges =
0
14.
def __str__(self):
15.
return
(str(self.comparisons) +
" comparisons; "
+
16.
str(self.copies) +
" copies; "
+
17.
str(self.merges) +
" merges"
)
18.
19.
_ =
"bookkeeping lines"
20.
21.
def merge(amy, ben, stats):
22.
_ ;stats.merges +=
1
23.
Carrington = []; a =
0
; b =
0
#init
24.
lena = len(amy); lenb = len(ben) #memoize
25.
while
(a < lena and b < lenb): #merge
26.
_ ;stats.comparisons +=
1
27.
if
(amy[a] <= ben[b]):
28.
_ ;stats.copies +=
1
29.
Carrington.append(amy[a]); a +=
1
30.
else
:
31.
_ ;stats.copies +=
1
32.
Carrington.append(ben[b]); b +=
1
33.
_ ;stats.copies +=
1
34.
#leftovers (O(
1
) with linked lists)
35.
Carrington.extend(amy[a:lena])
36.
Carrington.extend(ben[b:lenb])
37.
return
Carrington
38.
39.
def dropsort(lst, stats):
40.
if
(len(lst)<
2
):
return
lst #base
case
41.
up = []; dn = []; prev = None #init
42.
for
i in lst:
43.
_ ;stats.comparisons +=
1
44.
if
(prev is None or i >= prev):
45.
_ ;stats.copies +=
1
46.
up.append(i); prev = i
47.
else
:
48.
_ ;stats.copies +=
1
49.
#prepend (O(
1
) with linked lists)
50.
dn.insert(
0
, i)
51.
return
merge(up, dropsort(dn, stats), stats)
52.
53.
#implemented
for
comparison
54.
def mergesort(lst, stats):
55.
if
(len(lst)<
2
):
return
lst
56.
mid = len(lst)/
2
57.
return
merge(mergesort(lst[:mid], stats),
58.
mergesort(lst[mid:], stats), stats)
59.
60.
#use drop sort
for
the first two recursion levels in
case
there's already ordered data, then merge remainder
61.
def hybrid(lst, stats, stage =
0
):
62.
if
(len(lst)<
2
):
return
lst #base
case
63.
if
(stage >
1
):
return
mergesort(lst, stats)
64.
up = []; dn = []; prev = None #init
65.
for
i in lst:
66.
_ ;stats.comparisons +=
1
67.
if
(prev is None or i >= prev):
68.
_ ;stats.copies +=
1
69.
up.append(i); prev = i
70.
else
:
71.
_ ;stats.copies +=
1
72.
#prepend (O(
1
) with linked lists)
73.
dn.insert(
0
, i)
74.
return
merge(up, hybrid(dn, stats, stage +
1
), stats)
75.
76.
#assumes values in range [
0
,
1
)
77.
def printsort(lst, name = None):
78.
if
(not name is None): print name
79.
for
i in lst: print
" "
*
int
(i*
80
), i
80.
print
01.
Testovací příklad:
02.
03.
Input Output
04.
1
2
5
4
3
7
1
2
5
7
05.
10
-
1
12
10
12
06.
-
7
-
8
-
5
0
-
1
1
-
7
-
5
0
1
07.
9
8
7
6
5
9
08.
10
13
17
21
10
13
17
21
09.
10
10
10
9
10
10
10
10
10
1.
f=lambda a:a and f(a[:-
1
])+a[-
1
:]*(a[-
1
]==max(a))
01.
//Abusing of the standard type conversion in javascript, array to number:
02.
//
03.
// array of just 1 number => that number
04.
//
05.
// any other array => NaN
06.
//--------------------------------------------------------
07.
d=l=>l.filter(v=>l>v?
0
:[l=v])
08.
09.
// TEST
10.
console.log=x=>O.innerHTML+=x+
'\n'
11.
12.
;[
13.
[[
1
,
2
,
5
,
4
,
3
,
7
], [
1
,
2
,
5
,
7
]]
14.
, [[
10
,-
1
,
12
], [
10
,
12
]]
15.
, [[-
7
,-
8
,-
5
,
0
,-
1
,
1
], [-
7
,-
5
,
0
,
1
]]
16.
, [[
9
,
8
,
7
,
6
,
5
], [
9
]]
17.
, [[
10
,
13
,
17
,
21
], [
10
,
13
,
17
,
21
]]
18.
, [[
10
,
10
,
10
,
9
,
10
], [
10
,
10
,
10
,
10
]]
19.
].forEach(t=>( i=t[
0
],r=d(i),x=t[
1
],
20.
console.log(
'Test '
+i+
' -> '
+r+(r+
''
==x+
''
?
' OK'
:
' Fail (expected '
+x+
')'
)))
21.
)
1.
void
f(
int
[]a){
int
m=a[
0
];
for
(
int
n:a){System.out.print(m>n?
""
:n+
" "
);m=n>m?n:m;}}
2.
3.
//Here's a simple output loop. It just keeps the max in m and compares each element.
1.
$p=$_;s/\S+ ?/$&>=$p&&($p=$&)/ge
2.
3.
//If additional spaces are acceptable in the output, can be 31 bytes by removing and ?. Accepts a string (or number of newline separated) strings via STDIN:
4.
5.
perl -pe
'$p=$_;s/\S+ ?/$&>=$p&&($p=$&)/ge'
<<<
'-7 -8 -5 0 -1 1'
6.
-
7
-
5
0
1
7.
perl -pe
'$p=$_;s/\S+ ?/$&>=$p&&($p=$&)/ge'
<<<
'10 10 10 9 10'
8.
10
10
10
10
1.
int
i,j;i=j=INT_MIN;
while
(scanf(
"%d"
,&j)!=EOF)
if
(j>=i)printf(
"%d"
,j),i=j;