python显示排名排序_(转)一个显示排序过程的Python脚本

2009-05-08 11:16

之前向大家介绍过《一个排序算法比较的网站》,那个网站用动画演示了各种排序算法,并分析了各种排序算法。这里,要向大家推荐一个Python脚本,其可以把排序的过程给显示出来。

下图是“冒泡排序”的一个示例,其中:折线表示了各个元素的位置变化。

折线的深浅表示了元素的大小。越深则越大。

c2c95529be41a4965bdd2a34aac7048d.png

同样,还有其它一些排序算法的图片:

堆排序(Heap Sort)

5aca6e5ee661f8b144bbe909f03f3ba1.png

选择排序(Selection)

795f41b5455602cb36c1275bd941d1a3.png

快速排序(Quick)

3484f1da77df2865dd7efe7cec1c50e8.png

Shell排序

b002c734b32d2e7fdd1058a6f31ff2b1.png

插入排序(Insertion)

622f7d2a359ad7fc95f0345b855b0f60.png

你可以使用如下的Python代码来制作这些图片:(需要 Cairo图片库支持)

这个脚本参数如下:-a 表示使用什么样的算法,取值为"quick", "heap", "selection", "insertion", "bubble", "shell"。

-n 表示要排序的数据个数。

-f 表示输入文件。

-p 表示文件前缀。

-d 表示输出顺序。

-x 图片宽度。

-y 图片高度。

-l 所有线的宽度。

-b 边界宽度。

使用示例如下:

./visualise.py -l 6 -x 700 -y 300 -n 15

#!/usr/bin/env python

"""

Some of these algorithms are all rather literally from Knuth - as a

consequence they're not very Pythonic, and not terribly readable.

In some cases I've modified the algorithm to make sure that all items are

present once and only once in the array of sortables every time we

memoizePath (i.e. that the algorithm is in-place).

Page numbers refer to The Art of Computer Programming vol. 3.

This code is in the public domain - do whatever you like with it.

"""

import random, math, sys

from optparse import OptionParser

import cairo

def intRGB(r, g, b):

return (r/255.0, g/255.0, b/255.0)

HIGHLIGHT=intRGB(0xff, 0x72, 0x72)

class NiceCtx(cairo.Context):

defaultBorderColour = intRGB(0x7d, 0x7d, 0x7d)

def stroke_border(self, border):

src = self.get_source()

width = self.get_line_width()

self.set_source_rgba(*self.defaultBorderColour)

self.stroke_preserve()

self.set_source(src)

self.set_line_width(width - (border * 2))

self.stroke()

class Canvas:

def __init__(self, width, height):

self.width, self.height = width, height

self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)

self.background(1, 1, 1)

def ctx(self):

return NiceCtx(self.surface)

def background(self, r, g, b):

c = self.ctx()

c.set_source_rgb(r, g, b)

c.rectangle(0, 0, self.width, self.height)

c.fill()

c.stroke()

def save(self, fname):

self.surface.write_to_png(fname)

class Sortable:

def __init__(self, i):

self.i = i

self.path = []

def __cmp__(self, other):

return cmp(self.i, other.i)

def __repr__(self):

return str(self.i)

class TrackList:

def __init__(self, itms):

self.lst = [Sortable(i) for i in itms]

def __getattr__(self, attr):

return getattr(self.lst, attr)

def memoizePath(self):

for i, v in enumerate(self):

v.path.append(i)

class PathDrawer:

def __init__(self, width, height, line, border, highlights, prefix):

self.width, self.height = width, height

self.line, self.border = line, border

self.highlights, self.prefix = highlights, prefix

def _lineCoords(self, elem, l):

init = 0.02 # Proportional initial length

lst = []

xscale = (1.0-init)/len(elem.path)

yscale = 1.0/l

lst.append((0, yscale/2 + (yscale * elem.path[0])))

lst.append((init, yscale/2 + (yscale * elem.path[0])))

for i, v in enumerate(elem.path):

lst.append(((xscale * i) + init, yscale/2 + (yscale * v)))

lst.append((1, lst[-1][1]))

return lst

def draw(self, algo):

c = Canvas(self.width, self.height)

# Clearer when drawn in this order

l = reversed(algo.lst)

ctx = c.ctx()

for elem in l:

for i in self._lineCoords(elem, len(algo.lst)):

ctx.line_to(self.width * i[0], self.height * i[1])

ctx.set_line_cap(cairo.LINE_CAP_BUTT)

ctx.set_line_join(cairo.LINE_JOIN_ROUND)

if elem.i in self.highlights:

ctx.set_source_rgb(*HIGHLIGHT)

else:

x = 1 - (float(elem.i)/len(algo.lst)*0.7)

ctx.set_source_rgb(x, x, x)

ctx.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

ctx.set_line_width(self.line)

ctx.stroke_border(self.border)

c.save("%s%s.png"%(self.prefix, algo.name))

class Algorithm:

def __init__(self, entries):

self.name = self.__class__.__name__

self.lst = TrackList(entries)

self.lst.memoizePath()

self.sort(self.lst)

class Bubble(Algorithm):

def sort(self, lst):

bound = len(lst)-1

while 1:

t = 0

for j in range(bound):

if lst[j] > lst[j+1]:

lst[j], lst[j+1] = lst[j+1], lst[j]

lst.memoizePath()

t = j

if t == 0:

break

bound = t

class ListInsertion(Algorithm):

"""

Broadly based on the list insertion sort on p 97.

"""

def sort(self, lst):

for i in range(1, len(lst)):

for j in range(i):

if lst[i] < lst[j]:

x = lst.pop(i)

lst.insert(j, x)

lst.memoizePath()

class Shell(Algorithm):

"""

Shell's method, p. 84

"""

def sort(self, lst):

t = [5, 3, 1]

for h in t:

for j in range(h, len(lst)):

i = j - h

r = lst[j]

flag = 0

while i > -1:

if r < lst[i]:

flag = 1

lst[i+h], lst[i] = lst[i], lst[i+h]

i -= h

lst.memoizePath()

else:

break

lst[i+h] = r

class Selection(Algorithm):

"""

Selection Sort, p. 139

"""

def sort(self, lst):

for j in range(len(lst)-1, 0, -1):

m = lst.index(max(lst[:j])) # No, this is not efficient ;)

lst[m], lst[j] = lst[j], lst[m]

lst.memoizePath()

class Heap(Algorithm):

"""

Algorithm from http://en.wikipedia.org/wiki/Heapsort

"""

def sift(self, lst, start, count):

root = start

while (root * 2) + 1 < count:

child = (root * 2) + 1

if child < (count-1) and lst[child] < lst[child+1]:

child += 1

if lst[root] < lst[child]:

lst[root], lst[child] = lst[child], lst[root]

lst.memoizePath()

root = child

else:

return

def sort(self, lst):

start = (len(lst)/2)-1

end = len(lst)-1

while start >= 0:

self.sift(lst, start, len(lst))

start -= 1

while end > 0:

lst[end], lst[0] = lst[0], lst[end]

lst.memoizePath()

self.sift(lst, 0, end)

end -= 1

class Quick(Algorithm):

"""

http://www.cs.indiana.edu/classes/a348-dger/lectures/tsort/1.0.2/QSortAlgorithm.java

"""

def sort(self, lst, left=0, right=None):

if right is None:

right = len(lst) - 1

l = left

r = right

if l <= r:

mid = lst[(left+right)/2]

while l <= r:

while l <= right and lst[l] < mid:

l += 1

while r > left and lst[r] > mid:

r -= 1

if l <= r:

lst[l], lst[r] = lst[r], lst[l]

lst.memoizePath()

l+=1

r-=1

if left < r:

self.sort(lst, left, r)

if l < right:

self.sort(lst, l, right)

def main():

usage = "usage: %prog [options]"

parser = OptionParser(usage)

parser.add_option(

"-a",

dest="algorithm",

default=False,

type="choice",

choices=["quick", "heap", "selection", "insertion", "bubble", "shell"],

help="Draw only a named algorithm."

)

parser.add_option(

"-n",

dest="numelements",

default="20",

type="int",

help="Generate a random sorting sequence of length n"

)

parser.add_option(

"-f",

dest="readfile",

help="Read data from file"

)

parser.add_option(

"-p",

dest="prefix",

help="File name prefix.",

default=""

)

parser.add_option(

"-d",

dest="dump",

default=False,

action="store_true",

help="Dump sequence"

)

parser.add_option(

"-x",

dest="width",

type="int",

default=700,

help="Image width"

)

parser.add_option(

"-y",

dest="height",

type="int",

default=300,

help="Image height"

)

parser.add_option(

"-l",

dest="line",

type="int",

default=6,

help="Total line width"

)

parser.add_option(

"-b",

dest="border",

type="int",

default=1,

help="Border width"

)

parser.add_option(

"-i",

dest="highlight",

type="int",

default=[],

action="append",

help="Highlight digit N (0-based). Can be passed muiltiple times."

)

options, args = parser.parse_args()

if args:

parser.error("Script takes no arguments.")

if options.readfile:

txt = file(options.readfile).read().split()

lst = [int(i) for i in txt]

else:

lst = range(options.numelements)

random.shuffle(lst)

if options.highlight:

if max(options.highlight) > (len(lst)-1):

parser.error("Highlight element > than list length.")

if options.dump:

for i in lst:

print i,

ldrawer = PathDrawer(

options.width,

options.height,

options.line,

options.border,

options.highlight,

options.prefix

)

for i in [Quick, Heap, Selection, ListInsertion, Bubble, Shell]:

name = i.__name__

if options.algorithm:

if not options.algorithm.lower() == name.lower():

continue

print >> sys.stderr, name

a = i(lst)

ldrawer.draw(a)

if __name__ == "__main__":

main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值