17db96d56Sopenharmony_ci#!/usr/bin/env python3 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ciSorting algorithms visualizer using Tkinter. 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ciThis module is comprised of three ``components'': 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ci- an array visualizer with methods that implement basic sorting 97db96d56Sopenharmony_cioperations (compare, swap) as well as methods for ``annotating'' the 107db96d56Sopenharmony_cisorting algorithm (e.g. to show the pivot element); 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci- a number of sorting algorithms (currently quicksort, insertion sort, 137db96d56Sopenharmony_ciselection sort and bubble sort, as well as a randomization function), 147db96d56Sopenharmony_ciall using the array visualizer for its basic operations and with calls 157db96d56Sopenharmony_cito its annotation methods; 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci- and a ``driver'' class which can be used as a Grail applet or as a 187db96d56Sopenharmony_cistand-alone application. 197db96d56Sopenharmony_ci""" 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_cifrom tkinter import * 227db96d56Sopenharmony_ciimport random 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ciXGRID = 10 257db96d56Sopenharmony_ciYGRID = 10 267db96d56Sopenharmony_ciWIDTH = 6 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ciclass Array: 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci class Cancelled(BaseException): 327db96d56Sopenharmony_ci pass 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci def __init__(self, master, data=None): 357db96d56Sopenharmony_ci self.master = master 367db96d56Sopenharmony_ci self.frame = Frame(self.master) 377db96d56Sopenharmony_ci self.frame.pack(fill=X) 387db96d56Sopenharmony_ci self.label = Label(self.frame) 397db96d56Sopenharmony_ci self.label.pack() 407db96d56Sopenharmony_ci self.canvas = Canvas(self.frame) 417db96d56Sopenharmony_ci self.canvas.pack() 427db96d56Sopenharmony_ci self.report = Label(self.frame) 437db96d56Sopenharmony_ci self.report.pack() 447db96d56Sopenharmony_ci self.left = self.canvas.create_line(0, 0, 0, 0) 457db96d56Sopenharmony_ci self.right = self.canvas.create_line(0, 0, 0, 0) 467db96d56Sopenharmony_ci self.pivot = self.canvas.create_line(0, 0, 0, 0) 477db96d56Sopenharmony_ci self.items = [] 487db96d56Sopenharmony_ci self.size = self.maxvalue = 0 497db96d56Sopenharmony_ci if data: 507db96d56Sopenharmony_ci self.setdata(data) 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci def setdata(self, data): 537db96d56Sopenharmony_ci olditems = self.items 547db96d56Sopenharmony_ci self.items = [] 557db96d56Sopenharmony_ci for item in olditems: 567db96d56Sopenharmony_ci item.delete() 577db96d56Sopenharmony_ci self.size = len(data) 587db96d56Sopenharmony_ci self.maxvalue = max(data) 597db96d56Sopenharmony_ci self.canvas.config(width=(self.size+1)*XGRID, 607db96d56Sopenharmony_ci height=(self.maxvalue+1)*YGRID) 617db96d56Sopenharmony_ci for i in range(self.size): 627db96d56Sopenharmony_ci self.items.append(ArrayItem(self, i, data[i])) 637db96d56Sopenharmony_ci self.reset("Sort demo, size %d" % self.size) 647db96d56Sopenharmony_ci 657db96d56Sopenharmony_ci speed = "normal" 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ci def setspeed(self, speed): 687db96d56Sopenharmony_ci self.speed = speed 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci def destroy(self): 717db96d56Sopenharmony_ci self.frame.destroy() 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci in_mainloop = 0 747db96d56Sopenharmony_ci stop_mainloop = 0 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_ci def cancel(self): 777db96d56Sopenharmony_ci self.stop_mainloop = 1 787db96d56Sopenharmony_ci if self.in_mainloop: 797db96d56Sopenharmony_ci self.master.quit() 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_ci def step(self): 827db96d56Sopenharmony_ci if self.in_mainloop: 837db96d56Sopenharmony_ci self.master.quit() 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci def wait(self, msecs): 867db96d56Sopenharmony_ci if self.speed == "fastest": 877db96d56Sopenharmony_ci msecs = 0 887db96d56Sopenharmony_ci elif self.speed == "fast": 897db96d56Sopenharmony_ci msecs = msecs//10 907db96d56Sopenharmony_ci elif self.speed == "single-step": 917db96d56Sopenharmony_ci msecs = 1000000000 927db96d56Sopenharmony_ci if not self.stop_mainloop: 937db96d56Sopenharmony_ci self.master.update() 947db96d56Sopenharmony_ci id = self.master.after(msecs, self.master.quit) 957db96d56Sopenharmony_ci self.in_mainloop = 1 967db96d56Sopenharmony_ci self.master.mainloop() 977db96d56Sopenharmony_ci self.master.after_cancel(id) 987db96d56Sopenharmony_ci self.in_mainloop = 0 997db96d56Sopenharmony_ci if self.stop_mainloop: 1007db96d56Sopenharmony_ci self.stop_mainloop = 0 1017db96d56Sopenharmony_ci self.message("Cancelled") 1027db96d56Sopenharmony_ci raise Array.Cancelled 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci def getsize(self): 1057db96d56Sopenharmony_ci return self.size 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci def show_partition(self, first, last): 1087db96d56Sopenharmony_ci for i in range(self.size): 1097db96d56Sopenharmony_ci item = self.items[i] 1107db96d56Sopenharmony_ci if first <= i < last: 1117db96d56Sopenharmony_ci self.canvas.itemconfig(item, fill='red') 1127db96d56Sopenharmony_ci else: 1137db96d56Sopenharmony_ci self.canvas.itemconfig(item, fill='orange') 1147db96d56Sopenharmony_ci self.hide_left_right_pivot() 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci def hide_partition(self): 1177db96d56Sopenharmony_ci for i in range(self.size): 1187db96d56Sopenharmony_ci item = self.items[i] 1197db96d56Sopenharmony_ci self.canvas.itemconfig(item, fill='red') 1207db96d56Sopenharmony_ci self.hide_left_right_pivot() 1217db96d56Sopenharmony_ci 1227db96d56Sopenharmony_ci def show_left(self, left): 1237db96d56Sopenharmony_ci if not 0 <= left < self.size: 1247db96d56Sopenharmony_ci self.hide_left() 1257db96d56Sopenharmony_ci return 1267db96d56Sopenharmony_ci x1, y1, x2, y2 = self.items[left].position() 1277db96d56Sopenharmony_ci## top, bot = HIRO 1287db96d56Sopenharmony_ci self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999)) 1297db96d56Sopenharmony_ci self.master.update() 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci def show_right(self, right): 1327db96d56Sopenharmony_ci if not 0 <= right < self.size: 1337db96d56Sopenharmony_ci self.hide_right() 1347db96d56Sopenharmony_ci return 1357db96d56Sopenharmony_ci x1, y1, x2, y2 = self.items[right].position() 1367db96d56Sopenharmony_ci self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999)) 1377db96d56Sopenharmony_ci self.master.update() 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci def hide_left_right_pivot(self): 1407db96d56Sopenharmony_ci self.hide_left() 1417db96d56Sopenharmony_ci self.hide_right() 1427db96d56Sopenharmony_ci self.hide_pivot() 1437db96d56Sopenharmony_ci 1447db96d56Sopenharmony_ci def hide_left(self): 1457db96d56Sopenharmony_ci self.canvas.coords(self.left, (0, 0, 0, 0)) 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci def hide_right(self): 1487db96d56Sopenharmony_ci self.canvas.coords(self.right, (0, 0, 0, 0)) 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci def show_pivot(self, pivot): 1517db96d56Sopenharmony_ci x1, y1, x2, y2 = self.items[pivot].position() 1527db96d56Sopenharmony_ci self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2)) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci def hide_pivot(self): 1557db96d56Sopenharmony_ci self.canvas.coords(self.pivot, (0, 0, 0, 0)) 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci def swap(self, i, j): 1587db96d56Sopenharmony_ci if i == j: return 1597db96d56Sopenharmony_ci self.countswap() 1607db96d56Sopenharmony_ci item = self.items[i] 1617db96d56Sopenharmony_ci other = self.items[j] 1627db96d56Sopenharmony_ci self.items[i], self.items[j] = other, item 1637db96d56Sopenharmony_ci item.swapwith(other) 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci def compare(self, i, j): 1667db96d56Sopenharmony_ci self.countcompare() 1677db96d56Sopenharmony_ci item = self.items[i] 1687db96d56Sopenharmony_ci other = self.items[j] 1697db96d56Sopenharmony_ci return item.compareto(other) 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci def reset(self, msg): 1727db96d56Sopenharmony_ci self.ncompares = 0 1737db96d56Sopenharmony_ci self.nswaps = 0 1747db96d56Sopenharmony_ci self.message(msg) 1757db96d56Sopenharmony_ci self.updatereport() 1767db96d56Sopenharmony_ci self.hide_partition() 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci def message(self, msg): 1797db96d56Sopenharmony_ci self.label.config(text=msg) 1807db96d56Sopenharmony_ci 1817db96d56Sopenharmony_ci def countswap(self): 1827db96d56Sopenharmony_ci self.nswaps = self.nswaps + 1 1837db96d56Sopenharmony_ci self.updatereport() 1847db96d56Sopenharmony_ci 1857db96d56Sopenharmony_ci def countcompare(self): 1867db96d56Sopenharmony_ci self.ncompares = self.ncompares + 1 1877db96d56Sopenharmony_ci self.updatereport() 1887db96d56Sopenharmony_ci 1897db96d56Sopenharmony_ci def updatereport(self): 1907db96d56Sopenharmony_ci text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps) 1917db96d56Sopenharmony_ci self.report.config(text=text) 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ciclass ArrayItem: 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci def __init__(self, array, index, value): 1977db96d56Sopenharmony_ci self.array = array 1987db96d56Sopenharmony_ci self.index = index 1997db96d56Sopenharmony_ci self.value = value 2007db96d56Sopenharmony_ci self.canvas = array.canvas 2017db96d56Sopenharmony_ci x1, y1, x2, y2 = self.position() 2027db96d56Sopenharmony_ci self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2, 2037db96d56Sopenharmony_ci fill='red', outline='black', width=1) 2047db96d56Sopenharmony_ci self.canvas.tag_bind(self.item_id, '<Button-1>', self.mouse_down) 2057db96d56Sopenharmony_ci self.canvas.tag_bind(self.item_id, '<Button1-Motion>', self.mouse_move) 2067db96d56Sopenharmony_ci self.canvas.tag_bind(self.item_id, '<ButtonRelease-1>', self.mouse_up) 2077db96d56Sopenharmony_ci 2087db96d56Sopenharmony_ci def delete(self): 2097db96d56Sopenharmony_ci item_id = self.item_id 2107db96d56Sopenharmony_ci self.array = None 2117db96d56Sopenharmony_ci self.item_id = None 2127db96d56Sopenharmony_ci self.canvas.delete(item_id) 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci def mouse_down(self, event): 2157db96d56Sopenharmony_ci self.lastx = event.x 2167db96d56Sopenharmony_ci self.lasty = event.y 2177db96d56Sopenharmony_ci self.origx = event.x 2187db96d56Sopenharmony_ci self.origy = event.y 2197db96d56Sopenharmony_ci self.canvas.tag_raise(self.item_id) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci def mouse_move(self, event): 2227db96d56Sopenharmony_ci self.canvas.move(self.item_id, 2237db96d56Sopenharmony_ci event.x - self.lastx, event.y - self.lasty) 2247db96d56Sopenharmony_ci self.lastx = event.x 2257db96d56Sopenharmony_ci self.lasty = event.y 2267db96d56Sopenharmony_ci 2277db96d56Sopenharmony_ci def mouse_up(self, event): 2287db96d56Sopenharmony_ci i = self.nearestindex(event.x) 2297db96d56Sopenharmony_ci if i >= self.array.getsize(): 2307db96d56Sopenharmony_ci i = self.array.getsize() - 1 2317db96d56Sopenharmony_ci if i < 0: 2327db96d56Sopenharmony_ci i = 0 2337db96d56Sopenharmony_ci other = self.array.items[i] 2347db96d56Sopenharmony_ci here = self.index 2357db96d56Sopenharmony_ci self.array.items[here], self.array.items[i] = other, self 2367db96d56Sopenharmony_ci self.index = i 2377db96d56Sopenharmony_ci x1, y1, x2, y2 = self.position() 2387db96d56Sopenharmony_ci self.canvas.coords(self.item_id, (x1, y1, x2, y2)) 2397db96d56Sopenharmony_ci other.setindex(here) 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ci def setindex(self, index): 2427db96d56Sopenharmony_ci nsteps = steps(self.index, index) 2437db96d56Sopenharmony_ci if not nsteps: return 2447db96d56Sopenharmony_ci if self.array.speed == "fastest": 2457db96d56Sopenharmony_ci nsteps = 0 2467db96d56Sopenharmony_ci oldpts = self.position() 2477db96d56Sopenharmony_ci self.index = index 2487db96d56Sopenharmony_ci newpts = self.position() 2497db96d56Sopenharmony_ci trajectory = interpolate(oldpts, newpts, nsteps) 2507db96d56Sopenharmony_ci self.canvas.tag_raise(self.item_id) 2517db96d56Sopenharmony_ci for pts in trajectory: 2527db96d56Sopenharmony_ci self.canvas.coords(self.item_id, pts) 2537db96d56Sopenharmony_ci self.array.wait(50) 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci def swapwith(self, other): 2567db96d56Sopenharmony_ci nsteps = steps(self.index, other.index) 2577db96d56Sopenharmony_ci if not nsteps: return 2587db96d56Sopenharmony_ci if self.array.speed == "fastest": 2597db96d56Sopenharmony_ci nsteps = 0 2607db96d56Sopenharmony_ci myoldpts = self.position() 2617db96d56Sopenharmony_ci otheroldpts = other.position() 2627db96d56Sopenharmony_ci self.index, other.index = other.index, self.index 2637db96d56Sopenharmony_ci mynewpts = self.position() 2647db96d56Sopenharmony_ci othernewpts = other.position() 2657db96d56Sopenharmony_ci myfill = self.canvas.itemcget(self.item_id, 'fill') 2667db96d56Sopenharmony_ci otherfill = self.canvas.itemcget(other.item_id, 'fill') 2677db96d56Sopenharmony_ci self.canvas.itemconfig(self.item_id, fill='green') 2687db96d56Sopenharmony_ci self.canvas.itemconfig(other.item_id, fill='yellow') 2697db96d56Sopenharmony_ci self.array.master.update() 2707db96d56Sopenharmony_ci if self.array.speed == "single-step": 2717db96d56Sopenharmony_ci self.canvas.coords(self.item_id, mynewpts) 2727db96d56Sopenharmony_ci self.canvas.coords(other.item_id, othernewpts) 2737db96d56Sopenharmony_ci self.array.master.update() 2747db96d56Sopenharmony_ci self.canvas.itemconfig(self.item_id, fill=myfill) 2757db96d56Sopenharmony_ci self.canvas.itemconfig(other.item_id, fill=otherfill) 2767db96d56Sopenharmony_ci self.array.wait(0) 2777db96d56Sopenharmony_ci return 2787db96d56Sopenharmony_ci mytrajectory = interpolate(myoldpts, mynewpts, nsteps) 2797db96d56Sopenharmony_ci othertrajectory = interpolate(otheroldpts, othernewpts, nsteps) 2807db96d56Sopenharmony_ci if self.value > other.value: 2817db96d56Sopenharmony_ci self.canvas.tag_raise(self.item_id) 2827db96d56Sopenharmony_ci self.canvas.tag_raise(other.item_id) 2837db96d56Sopenharmony_ci else: 2847db96d56Sopenharmony_ci self.canvas.tag_raise(other.item_id) 2857db96d56Sopenharmony_ci self.canvas.tag_raise(self.item_id) 2867db96d56Sopenharmony_ci try: 2877db96d56Sopenharmony_ci for i in range(len(mytrajectory)): 2887db96d56Sopenharmony_ci mypts = mytrajectory[i] 2897db96d56Sopenharmony_ci otherpts = othertrajectory[i] 2907db96d56Sopenharmony_ci self.canvas.coords(self.item_id, mypts) 2917db96d56Sopenharmony_ci self.canvas.coords(other.item_id, otherpts) 2927db96d56Sopenharmony_ci self.array.wait(50) 2937db96d56Sopenharmony_ci finally: 2947db96d56Sopenharmony_ci mypts = mytrajectory[-1] 2957db96d56Sopenharmony_ci otherpts = othertrajectory[-1] 2967db96d56Sopenharmony_ci self.canvas.coords(self.item_id, mypts) 2977db96d56Sopenharmony_ci self.canvas.coords(other.item_id, otherpts) 2987db96d56Sopenharmony_ci self.canvas.itemconfig(self.item_id, fill=myfill) 2997db96d56Sopenharmony_ci self.canvas.itemconfig(other.item_id, fill=otherfill) 3007db96d56Sopenharmony_ci 3017db96d56Sopenharmony_ci def compareto(self, other): 3027db96d56Sopenharmony_ci myfill = self.canvas.itemcget(self.item_id, 'fill') 3037db96d56Sopenharmony_ci otherfill = self.canvas.itemcget(other.item_id, 'fill') 3047db96d56Sopenharmony_ci if self.value < other.value: 3057db96d56Sopenharmony_ci myflash = 'white' 3067db96d56Sopenharmony_ci otherflash = 'black' 3077db96d56Sopenharmony_ci outcome = -1 3087db96d56Sopenharmony_ci elif self.value > other.value: 3097db96d56Sopenharmony_ci myflash = 'black' 3107db96d56Sopenharmony_ci otherflash = 'white' 3117db96d56Sopenharmony_ci outcome = 1 3127db96d56Sopenharmony_ci else: 3137db96d56Sopenharmony_ci myflash = otherflash = 'grey' 3147db96d56Sopenharmony_ci outcome = 0 3157db96d56Sopenharmony_ci try: 3167db96d56Sopenharmony_ci self.canvas.itemconfig(self.item_id, fill=myflash) 3177db96d56Sopenharmony_ci self.canvas.itemconfig(other.item_id, fill=otherflash) 3187db96d56Sopenharmony_ci self.array.wait(500) 3197db96d56Sopenharmony_ci finally: 3207db96d56Sopenharmony_ci self.canvas.itemconfig(self.item_id, fill=myfill) 3217db96d56Sopenharmony_ci self.canvas.itemconfig(other.item_id, fill=otherfill) 3227db96d56Sopenharmony_ci return outcome 3237db96d56Sopenharmony_ci 3247db96d56Sopenharmony_ci def position(self): 3257db96d56Sopenharmony_ci x1 = (self.index+1)*XGRID - WIDTH//2 3267db96d56Sopenharmony_ci x2 = x1+WIDTH 3277db96d56Sopenharmony_ci y2 = (self.array.maxvalue+1)*YGRID 3287db96d56Sopenharmony_ci y1 = y2 - (self.value)*YGRID 3297db96d56Sopenharmony_ci return x1, y1, x2, y2 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci def nearestindex(self, x): 3327db96d56Sopenharmony_ci return int(round(float(x)/XGRID)) - 1 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci 3357db96d56Sopenharmony_ci# Subroutines that don't need an object 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_cidef steps(here, there): 3387db96d56Sopenharmony_ci nsteps = abs(here - there) 3397db96d56Sopenharmony_ci if nsteps <= 3: 3407db96d56Sopenharmony_ci nsteps = nsteps * 3 3417db96d56Sopenharmony_ci elif nsteps <= 5: 3427db96d56Sopenharmony_ci nsteps = nsteps * 2 3437db96d56Sopenharmony_ci elif nsteps > 10: 3447db96d56Sopenharmony_ci nsteps = 10 3457db96d56Sopenharmony_ci return nsteps 3467db96d56Sopenharmony_ci 3477db96d56Sopenharmony_cidef interpolate(oldpts, newpts, n): 3487db96d56Sopenharmony_ci if len(oldpts) != len(newpts): 3497db96d56Sopenharmony_ci raise ValueError("can't interpolate arrays of different length") 3507db96d56Sopenharmony_ci pts = [0]*len(oldpts) 3517db96d56Sopenharmony_ci res = [tuple(oldpts)] 3527db96d56Sopenharmony_ci for i in range(1, n): 3537db96d56Sopenharmony_ci for k in range(len(pts)): 3547db96d56Sopenharmony_ci pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n 3557db96d56Sopenharmony_ci res.append(tuple(pts)) 3567db96d56Sopenharmony_ci res.append(tuple(newpts)) 3577db96d56Sopenharmony_ci return res 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci 3607db96d56Sopenharmony_ci# Various (un)sorting algorithms 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_cidef uniform(array): 3637db96d56Sopenharmony_ci size = array.getsize() 3647db96d56Sopenharmony_ci array.setdata([(size+1)//2] * size) 3657db96d56Sopenharmony_ci array.reset("Uniform data, size %d" % size) 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_cidef distinct(array): 3687db96d56Sopenharmony_ci size = array.getsize() 3697db96d56Sopenharmony_ci array.setdata(range(1, size+1)) 3707db96d56Sopenharmony_ci array.reset("Distinct data, size %d" % size) 3717db96d56Sopenharmony_ci 3727db96d56Sopenharmony_cidef randomize(array): 3737db96d56Sopenharmony_ci array.reset("Randomizing") 3747db96d56Sopenharmony_ci n = array.getsize() 3757db96d56Sopenharmony_ci for i in range(n): 3767db96d56Sopenharmony_ci j = random.randint(0, n-1) 3777db96d56Sopenharmony_ci array.swap(i, j) 3787db96d56Sopenharmony_ci array.message("Randomized") 3797db96d56Sopenharmony_ci 3807db96d56Sopenharmony_cidef insertionsort(array): 3817db96d56Sopenharmony_ci size = array.getsize() 3827db96d56Sopenharmony_ci array.reset("Insertion sort") 3837db96d56Sopenharmony_ci for i in range(1, size): 3847db96d56Sopenharmony_ci j = i-1 3857db96d56Sopenharmony_ci while j >= 0: 3867db96d56Sopenharmony_ci if array.compare(j, j+1) <= 0: 3877db96d56Sopenharmony_ci break 3887db96d56Sopenharmony_ci array.swap(j, j+1) 3897db96d56Sopenharmony_ci j = j-1 3907db96d56Sopenharmony_ci array.message("Sorted") 3917db96d56Sopenharmony_ci 3927db96d56Sopenharmony_cidef selectionsort(array): 3937db96d56Sopenharmony_ci size = array.getsize() 3947db96d56Sopenharmony_ci array.reset("Selection sort") 3957db96d56Sopenharmony_ci try: 3967db96d56Sopenharmony_ci for i in range(size): 3977db96d56Sopenharmony_ci array.show_partition(i, size) 3987db96d56Sopenharmony_ci for j in range(i+1, size): 3997db96d56Sopenharmony_ci if array.compare(i, j) > 0: 4007db96d56Sopenharmony_ci array.swap(i, j) 4017db96d56Sopenharmony_ci array.message("Sorted") 4027db96d56Sopenharmony_ci finally: 4037db96d56Sopenharmony_ci array.hide_partition() 4047db96d56Sopenharmony_ci 4057db96d56Sopenharmony_cidef bubblesort(array): 4067db96d56Sopenharmony_ci size = array.getsize() 4077db96d56Sopenharmony_ci array.reset("Bubble sort") 4087db96d56Sopenharmony_ci for i in range(size): 4097db96d56Sopenharmony_ci for j in range(1, size): 4107db96d56Sopenharmony_ci if array.compare(j-1, j) > 0: 4117db96d56Sopenharmony_ci array.swap(j-1, j) 4127db96d56Sopenharmony_ci array.message("Sorted") 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_cidef quicksort(array): 4157db96d56Sopenharmony_ci size = array.getsize() 4167db96d56Sopenharmony_ci array.reset("Quicksort") 4177db96d56Sopenharmony_ci try: 4187db96d56Sopenharmony_ci stack = [(0, size)] 4197db96d56Sopenharmony_ci while stack: 4207db96d56Sopenharmony_ci first, last = stack[-1] 4217db96d56Sopenharmony_ci del stack[-1] 4227db96d56Sopenharmony_ci array.show_partition(first, last) 4237db96d56Sopenharmony_ci if last-first < 5: 4247db96d56Sopenharmony_ci array.message("Insertion sort") 4257db96d56Sopenharmony_ci for i in range(first+1, last): 4267db96d56Sopenharmony_ci j = i-1 4277db96d56Sopenharmony_ci while j >= first: 4287db96d56Sopenharmony_ci if array.compare(j, j+1) <= 0: 4297db96d56Sopenharmony_ci break 4307db96d56Sopenharmony_ci array.swap(j, j+1) 4317db96d56Sopenharmony_ci j = j-1 4327db96d56Sopenharmony_ci continue 4337db96d56Sopenharmony_ci array.message("Choosing pivot") 4347db96d56Sopenharmony_ci j, i, k = first, (first+last) // 2, last-1 4357db96d56Sopenharmony_ci if array.compare(k, i) < 0: 4367db96d56Sopenharmony_ci array.swap(k, i) 4377db96d56Sopenharmony_ci if array.compare(k, j) < 0: 4387db96d56Sopenharmony_ci array.swap(k, j) 4397db96d56Sopenharmony_ci if array.compare(j, i) < 0: 4407db96d56Sopenharmony_ci array.swap(j, i) 4417db96d56Sopenharmony_ci pivot = j 4427db96d56Sopenharmony_ci array.show_pivot(pivot) 4437db96d56Sopenharmony_ci array.message("Pivot at left of partition") 4447db96d56Sopenharmony_ci array.wait(1000) 4457db96d56Sopenharmony_ci left = first 4467db96d56Sopenharmony_ci right = last 4477db96d56Sopenharmony_ci while True: 4487db96d56Sopenharmony_ci array.message("Sweep right pointer") 4497db96d56Sopenharmony_ci right = right-1 4507db96d56Sopenharmony_ci array.show_right(right) 4517db96d56Sopenharmony_ci while right > first and array.compare(right, pivot) >= 0: 4527db96d56Sopenharmony_ci right = right-1 4537db96d56Sopenharmony_ci array.show_right(right) 4547db96d56Sopenharmony_ci array.message("Sweep left pointer") 4557db96d56Sopenharmony_ci left = left+1 4567db96d56Sopenharmony_ci array.show_left(left) 4577db96d56Sopenharmony_ci while left < last and array.compare(left, pivot) <= 0: 4587db96d56Sopenharmony_ci left = left+1 4597db96d56Sopenharmony_ci array.show_left(left) 4607db96d56Sopenharmony_ci if left > right: 4617db96d56Sopenharmony_ci array.message("End of partition") 4627db96d56Sopenharmony_ci break 4637db96d56Sopenharmony_ci array.message("Swap items") 4647db96d56Sopenharmony_ci array.swap(left, right) 4657db96d56Sopenharmony_ci array.message("Swap pivot back") 4667db96d56Sopenharmony_ci array.swap(pivot, right) 4677db96d56Sopenharmony_ci n1 = right-first 4687db96d56Sopenharmony_ci n2 = last-left 4697db96d56Sopenharmony_ci if n1 > 1: stack.append((first, right)) 4707db96d56Sopenharmony_ci if n2 > 1: stack.append((left, last)) 4717db96d56Sopenharmony_ci array.message("Sorted") 4727db96d56Sopenharmony_ci finally: 4737db96d56Sopenharmony_ci array.hide_partition() 4747db96d56Sopenharmony_ci 4757db96d56Sopenharmony_cidef demosort(array): 4767db96d56Sopenharmony_ci while True: 4777db96d56Sopenharmony_ci for alg in [quicksort, insertionsort, selectionsort, bubblesort]: 4787db96d56Sopenharmony_ci randomize(array) 4797db96d56Sopenharmony_ci alg(array) 4807db96d56Sopenharmony_ci 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci# Sort demo class -- usable as a Grail applet 4837db96d56Sopenharmony_ci 4847db96d56Sopenharmony_ciclass SortDemo: 4857db96d56Sopenharmony_ci 4867db96d56Sopenharmony_ci def __init__(self, master, size=15): 4877db96d56Sopenharmony_ci self.master = master 4887db96d56Sopenharmony_ci self.size = size 4897db96d56Sopenharmony_ci self.busy = 0 4907db96d56Sopenharmony_ci self.array = Array(self.master) 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci self.botframe = Frame(master) 4937db96d56Sopenharmony_ci self.botframe.pack(side=BOTTOM) 4947db96d56Sopenharmony_ci self.botleftframe = Frame(self.botframe) 4957db96d56Sopenharmony_ci self.botleftframe.pack(side=LEFT, fill=Y) 4967db96d56Sopenharmony_ci self.botrightframe = Frame(self.botframe) 4977db96d56Sopenharmony_ci self.botrightframe.pack(side=RIGHT, fill=Y) 4987db96d56Sopenharmony_ci 4997db96d56Sopenharmony_ci self.b_qsort = Button(self.botleftframe, 5007db96d56Sopenharmony_ci text="Quicksort", command=self.c_qsort) 5017db96d56Sopenharmony_ci self.b_qsort.pack(fill=X) 5027db96d56Sopenharmony_ci self.b_isort = Button(self.botleftframe, 5037db96d56Sopenharmony_ci text="Insertion sort", command=self.c_isort) 5047db96d56Sopenharmony_ci self.b_isort.pack(fill=X) 5057db96d56Sopenharmony_ci self.b_ssort = Button(self.botleftframe, 5067db96d56Sopenharmony_ci text="Selection sort", command=self.c_ssort) 5077db96d56Sopenharmony_ci self.b_ssort.pack(fill=X) 5087db96d56Sopenharmony_ci self.b_bsort = Button(self.botleftframe, 5097db96d56Sopenharmony_ci text="Bubble sort", command=self.c_bsort) 5107db96d56Sopenharmony_ci self.b_bsort.pack(fill=X) 5117db96d56Sopenharmony_ci 5127db96d56Sopenharmony_ci # Terrible hack to overcome limitation of OptionMenu... 5137db96d56Sopenharmony_ci class MyIntVar(IntVar): 5147db96d56Sopenharmony_ci def __init__(self, master, demo): 5157db96d56Sopenharmony_ci self.demo = demo 5167db96d56Sopenharmony_ci IntVar.__init__(self, master) 5177db96d56Sopenharmony_ci def set(self, value): 5187db96d56Sopenharmony_ci IntVar.set(self, value) 5197db96d56Sopenharmony_ci if str(value) != '0': 5207db96d56Sopenharmony_ci self.demo.resize(value) 5217db96d56Sopenharmony_ci 5227db96d56Sopenharmony_ci self.v_size = MyIntVar(self.master, self) 5237db96d56Sopenharmony_ci self.v_size.set(size) 5247db96d56Sopenharmony_ci sizes = [1, 2, 3, 4] + list(range(5, 55, 5)) 5257db96d56Sopenharmony_ci if self.size not in sizes: 5267db96d56Sopenharmony_ci sizes.append(self.size) 5277db96d56Sopenharmony_ci sizes.sort() 5287db96d56Sopenharmony_ci self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes) 5297db96d56Sopenharmony_ci self.m_size.pack(fill=X) 5307db96d56Sopenharmony_ci 5317db96d56Sopenharmony_ci self.v_speed = StringVar(self.master) 5327db96d56Sopenharmony_ci self.v_speed.set("normal") 5337db96d56Sopenharmony_ci self.m_speed = OptionMenu(self.botleftframe, self.v_speed, 5347db96d56Sopenharmony_ci "single-step", "normal", "fast", "fastest") 5357db96d56Sopenharmony_ci self.m_speed.pack(fill=X) 5367db96d56Sopenharmony_ci 5377db96d56Sopenharmony_ci self.b_step = Button(self.botleftframe, 5387db96d56Sopenharmony_ci text="Step", command=self.c_step) 5397db96d56Sopenharmony_ci self.b_step.pack(fill=X) 5407db96d56Sopenharmony_ci 5417db96d56Sopenharmony_ci self.b_randomize = Button(self.botrightframe, 5427db96d56Sopenharmony_ci text="Randomize", command=self.c_randomize) 5437db96d56Sopenharmony_ci self.b_randomize.pack(fill=X) 5447db96d56Sopenharmony_ci self.b_uniform = Button(self.botrightframe, 5457db96d56Sopenharmony_ci text="Uniform", command=self.c_uniform) 5467db96d56Sopenharmony_ci self.b_uniform.pack(fill=X) 5477db96d56Sopenharmony_ci self.b_distinct = Button(self.botrightframe, 5487db96d56Sopenharmony_ci text="Distinct", command=self.c_distinct) 5497db96d56Sopenharmony_ci self.b_distinct.pack(fill=X) 5507db96d56Sopenharmony_ci self.b_demo = Button(self.botrightframe, 5517db96d56Sopenharmony_ci text="Demo", command=self.c_demo) 5527db96d56Sopenharmony_ci self.b_demo.pack(fill=X) 5537db96d56Sopenharmony_ci self.b_cancel = Button(self.botrightframe, 5547db96d56Sopenharmony_ci text="Cancel", command=self.c_cancel) 5557db96d56Sopenharmony_ci self.b_cancel.pack(fill=X) 5567db96d56Sopenharmony_ci self.b_cancel.config(state=DISABLED) 5577db96d56Sopenharmony_ci self.b_quit = Button(self.botrightframe, 5587db96d56Sopenharmony_ci text="Quit", command=self.c_quit) 5597db96d56Sopenharmony_ci self.b_quit.pack(fill=X) 5607db96d56Sopenharmony_ci 5617db96d56Sopenharmony_ci def resize(self, newsize): 5627db96d56Sopenharmony_ci if self.busy: 5637db96d56Sopenharmony_ci self.master.bell() 5647db96d56Sopenharmony_ci return 5657db96d56Sopenharmony_ci self.size = newsize 5667db96d56Sopenharmony_ci self.array.setdata(range(1, self.size+1)) 5677db96d56Sopenharmony_ci 5687db96d56Sopenharmony_ci def c_qsort(self): 5697db96d56Sopenharmony_ci self.run(quicksort) 5707db96d56Sopenharmony_ci 5717db96d56Sopenharmony_ci def c_isort(self): 5727db96d56Sopenharmony_ci self.run(insertionsort) 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci def c_ssort(self): 5757db96d56Sopenharmony_ci self.run(selectionsort) 5767db96d56Sopenharmony_ci 5777db96d56Sopenharmony_ci def c_bsort(self): 5787db96d56Sopenharmony_ci self.run(bubblesort) 5797db96d56Sopenharmony_ci 5807db96d56Sopenharmony_ci def c_demo(self): 5817db96d56Sopenharmony_ci self.run(demosort) 5827db96d56Sopenharmony_ci 5837db96d56Sopenharmony_ci def c_randomize(self): 5847db96d56Sopenharmony_ci self.run(randomize) 5857db96d56Sopenharmony_ci 5867db96d56Sopenharmony_ci def c_uniform(self): 5877db96d56Sopenharmony_ci self.run(uniform) 5887db96d56Sopenharmony_ci 5897db96d56Sopenharmony_ci def c_distinct(self): 5907db96d56Sopenharmony_ci self.run(distinct) 5917db96d56Sopenharmony_ci 5927db96d56Sopenharmony_ci def run(self, func): 5937db96d56Sopenharmony_ci if self.busy: 5947db96d56Sopenharmony_ci self.master.bell() 5957db96d56Sopenharmony_ci return 5967db96d56Sopenharmony_ci self.busy = 1 5977db96d56Sopenharmony_ci self.array.setspeed(self.v_speed.get()) 5987db96d56Sopenharmony_ci self.b_cancel.config(state=NORMAL) 5997db96d56Sopenharmony_ci try: 6007db96d56Sopenharmony_ci func(self.array) 6017db96d56Sopenharmony_ci except Array.Cancelled: 6027db96d56Sopenharmony_ci pass 6037db96d56Sopenharmony_ci self.b_cancel.config(state=DISABLED) 6047db96d56Sopenharmony_ci self.busy = 0 6057db96d56Sopenharmony_ci 6067db96d56Sopenharmony_ci def c_cancel(self): 6077db96d56Sopenharmony_ci if not self.busy: 6087db96d56Sopenharmony_ci self.master.bell() 6097db96d56Sopenharmony_ci return 6107db96d56Sopenharmony_ci self.array.cancel() 6117db96d56Sopenharmony_ci 6127db96d56Sopenharmony_ci def c_step(self): 6137db96d56Sopenharmony_ci if not self.busy: 6147db96d56Sopenharmony_ci self.master.bell() 6157db96d56Sopenharmony_ci return 6167db96d56Sopenharmony_ci self.v_speed.set("single-step") 6177db96d56Sopenharmony_ci self.array.setspeed("single-step") 6187db96d56Sopenharmony_ci self.array.step() 6197db96d56Sopenharmony_ci 6207db96d56Sopenharmony_ci def c_quit(self): 6217db96d56Sopenharmony_ci if self.busy: 6227db96d56Sopenharmony_ci self.array.cancel() 6237db96d56Sopenharmony_ci self.master.after_idle(self.master.quit) 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci 6267db96d56Sopenharmony_ci# Main program -- for stand-alone operation outside Grail 6277db96d56Sopenharmony_ci 6287db96d56Sopenharmony_cidef main(): 6297db96d56Sopenharmony_ci root = Tk() 6307db96d56Sopenharmony_ci demo = SortDemo(root) 6317db96d56Sopenharmony_ci root.protocol('WM_DELETE_WINDOW', demo.c_quit) 6327db96d56Sopenharmony_ci root.mainloop() 6337db96d56Sopenharmony_ci 6347db96d56Sopenharmony_ciif __name__ == '__main__': 6357db96d56Sopenharmony_ci main() 636