Advertisement
CleverCode

Sorting Algorithms Matplotlib

Mar 24th, 2020
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.47 KB | None | 0 0
  1. import random
  2. import time
  3. import matplotlib.pyplot as plt
  4. import matplotlib.animation as animation
  5.  
  6. # NOTE: Python version >=3.3 is required, due to "yield from" feature.
  7.  
  8. def swap(A, i, j):
  9.     """Helper function to swap elements i and j of list A."""
  10.  
  11.     if i != j:
  12.         A[i], A[j] = A[j], A[i]
  13.  
  14. def bubblesort(A):
  15.     """In-place bubble sort."""
  16.  
  17.     if len(A) == 1:
  18.         return
  19.  
  20.     swapped = True
  21.     for i in range(len(A) - 1):
  22.         if not swapped:
  23.             break
  24.         swapped = False
  25.         for j in range(len(A) - 1 - i):
  26.             if A[j] > A[j + 1]:
  27.                 swap(A, j, j + 1)
  28.                 swapped = True
  29.             yield A
  30.  
  31. def insertionsort(A):
  32.     """In-place insertion sort."""
  33.  
  34.     for i in range(1, len(A)):
  35.         j = i
  36.         while j > 0 and A[j] < A[j - 1]:
  37.             swap(A, j, j - 1)
  38.             j -= 1
  39.             yield A
  40.  
  41. def mergesort(A, start, end):
  42.     """Merge sort."""
  43.  
  44.     if end <= start:
  45.         return
  46.  
  47.     mid = start + ((end - start + 1) // 2) - 1
  48.     yield from mergesort(A, start, mid)
  49.     yield from mergesort(A, mid + 1, end)
  50.     yield from merge(A, start, mid, end)
  51.     yield A
  52.  
  53. def merge(A, start, mid, end):
  54.     """Helper function for merge sort."""
  55.    
  56.     merged = []
  57.     leftIdx = start
  58.     rightIdx = mid + 1
  59.  
  60.     while leftIdx <= mid and rightIdx <= end:
  61.         if A[leftIdx] < A[rightIdx]:
  62.             merged.append(A[leftIdx])
  63.             leftIdx += 1
  64.         else:
  65.             merged.append(A[rightIdx])
  66.             rightIdx += 1
  67.  
  68.     while leftIdx <= mid:
  69.         merged.append(A[leftIdx])
  70.         leftIdx += 1
  71.  
  72.     while rightIdx <= end:
  73.         merged.append(A[rightIdx])
  74.         rightIdx += 1
  75.  
  76.     for i, sorted_val in enumerate(merged):
  77.         A[start + i] = sorted_val
  78.         yield A
  79.  
  80. def quicksort(A, start, end):
  81.     """In-place quicksort."""
  82.  
  83.     if start >= end:
  84.         return
  85.  
  86.     pivot = A[end]
  87.     pivotIdx = start
  88.  
  89.     for i in range(start, end):
  90.         if A[i] < pivot:
  91.             swap(A, i, pivotIdx)
  92.             pivotIdx += 1
  93.         yield A
  94.     swap(A, end, pivotIdx)
  95.     yield A
  96.  
  97.     yield from quicksort(A, start, pivotIdx - 1)
  98.     yield from quicksort(A, pivotIdx + 1, end)
  99.  
  100. def selectionsort(A):
  101.     """In-place selection sort."""
  102.     if len(A) == 1:
  103.         return
  104.  
  105.     for i in range(len(A)):
  106.         # Find minimum unsorted value.
  107.         minVal = A[i]
  108.         minIdx = i
  109.         for j in range(i, len(A)):
  110.             if A[j] < minVal:
  111.                 minVal = A[j]
  112.                 minIdx = j
  113.             yield A
  114.         swap(A, i, minIdx)
  115.         yield A
  116.  
  117. if __name__ == "__main__":
  118.     # Get user input to determine range of integers (1 to N) and desired
  119.     # sorting method (algorithm).
  120.     N = int(input("Enter number of integers: "))
  121.     method_msg = "Enter sorting method:\n(b)ubble\n(i)nsertion\n(m)erge \
  122.        \n(q)uick\n(s)election\n"
  123.     method = input(method_msg)
  124.  
  125.     # Build and randomly shuffle list of integers.
  126.     A = [x + 1 for x in range(N)]
  127.     random.seed(time.time())
  128.     random.shuffle(A)
  129.  
  130.     # Get appropriate generator to supply to matplotlib FuncAnimation method.
  131.     if method == "b":
  132.         title = "Bubble sort"
  133.         generator = bubblesort(A)
  134.     elif method == "i":
  135.         title = "Insertion sort"
  136.         generator = insertionsort(A)
  137.     elif method == "m":
  138.         title = "Merge sort"
  139.         generator = mergesort(A, 0, N - 1)
  140.     elif method == "q":
  141.         title = "Quicksort"
  142.         generator = quicksort(A, 0, N - 1)
  143.     else:
  144.         title = "Selection sort"
  145.         generator = selectionsort(A)
  146.  
  147.     # Initialize figure and axis.
  148.     fig, ax = plt.subplots()
  149.     ax.set_title(title)
  150.  
  151.     # Initialize a bar plot. Note that matplotlib.pyplot.bar() returns a
  152.     # list of rectangles (with each bar in the bar plot corresponding
  153.     # to one rectangle), which we store in bar_rects.
  154.     bar_rects = ax.bar(range(len(A)), A, align="edge")
  155.  
  156.     # Set axis limits. Set y axis upper limit high enough that the tops of
  157.     # the bars won't overlap with the text label.
  158.     ax.set_xlim(0, N)
  159.     ax.set_ylim(0, int(1.07 * N))
  160.  
  161.     # Place a text label in the upper-left corner of the plot to display
  162.     # number of operations performed by the sorting algorithm (each "yield"
  163.     # is treated as 1 operation).
  164.     text = ax.text(0.02, 0.95, "", transform=ax.transAxes)
  165.  
  166.     # Define function update_fig() for use with matplotlib.pyplot.FuncAnimation().
  167.     # To track the number of operations, i.e., iterations through which the
  168.     # animation has gone, define a variable "iteration". This variable will
  169.     # be passed to update_fig() to update the text label, and will also be
  170.     # incremented in update_fig(). For this increment to be reflected outside
  171.     # the function, we make "iteration" a list of 1 element, since lists (and
  172.     # other mutable objects) are passed by reference (but an integer would be
  173.     # passed by value).
  174.     # NOTE: Alternatively, iteration could be re-declared within update_fig()
  175.     # with the "global" keyword (or "nonlocal" keyword).
  176.     iteration = [0]
  177.     def update_fig(A, rects, iteration):
  178.         for rect, val in zip(rects, A):
  179.             rect.set_height(val)
  180.         iteration[0] += 1
  181.         text.set_text("# of operations: {}".format(iteration[0]))
  182.  
  183.     anim = animation.FuncAnimation(fig, func=update_fig,
  184.         fargs=(bar_rects, iteration), frames=generator, interval=1,
  185.         repeat=False)
  186.     plt.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement