Repository where I mostly put random python scripts.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

439 lines
10 KiB

  1. # coding: utf-8
  2. # # 1 Best cases
  3. # **1.1** Bubble sort
  4. # The short version of Bubble sort is given in the online book:
  5. # https://runestone.academy/runestone/static/FIT5211/SortSearch/TheBubbleSort.html
  6. # At every iteration, it detects whether an exchange has been made, and only continues iteration if that is the case. Given a sorted list, the first iteration will make no exchange, thus no other iteration will be performed, and only the inner loop will actually iterate over the entire list. The running time in that case is thus $O(n)$.
  7. # **1.2** Selection sort
  8. # After every pass of selection sort, the only thing we know is that one more item is now in place. The algorithm has no way of knowing and thus using the fact that the list is already sorted. The algorithm will thus perform the whole $O(n^2)$ operations, as in the worst case.
  9. # **1.3** Merge sort
  10. # Merge splits the input list into two, without looking at its contents. the contents are only looked at upon merging, after every item in the list has been split into a sublist of size 1. At this point, all merging operations still need to happen. In this case, the running time is thus also $O(n \log{n})$.
  11. # # 2 Merge sort without slicing
  12. # In[1]:
  13. #start is the index of the first item
  14. #end is the index past the the last item
  15. def indexMergeSort(alist, start = None, end = None):
  16. if start == None:
  17. start = 0
  18. if end == None:
  19. end = len(alist)
  20. #note that the print operations still use slicing for convenience
  21. #print("Input: ",alist[start:end])
  22. length = end - start
  23. if length > 1:
  24. #print("Splitting ",alist[start:end])
  25. mid = start + length//2
  26. indexMergeSort(alist, start, mid)
  27. indexMergeSort(alist, mid, end)
  28. i=start # index for the left part of the list
  29. j=mid # index for the right part of the list
  30. #we use a temporary list
  31. templist = [None] * (length)
  32. k = 0 #index for the temp list
  33. while i < mid and j < end:
  34. if alist[i] < alist[j]:
  35. templist[k] = alist[i]
  36. i=i+1
  37. else:
  38. #we swap
  39. templist[k] = alist[j]
  40. j=j+1
  41. k=k+1
  42. while i < mid:
  43. templist[k] = alist[i]
  44. i=i+1
  45. k=k+1
  46. while j < end:
  47. templist[k]=alist[j]
  48. j=j+1
  49. k=k+1
  50. #we copy the results
  51. for k in range(length):
  52. alist[start+k] = templist[k]
  53. #print("Merging ",alist[start:mid], alist[mid:end])
  54. alist = [54,26,93,17,77,31,44,55,20]
  55. indexMergeSort(alist)
  56. print(alist)
  57. # # 3 Benchmarking sorting algorithms
  58. # In[2]:
  59. import random
  60. def generatelist(n, lower = 0, upper = 1000, seed = 0):
  61. #https://docs.python.org/3/library/random.html
  62. random.seed(seed)
  63. l = [None] * n
  64. for i in range(0,n):
  65. l[i] = random.randrange(lower, upper)
  66. return l
  67. # In[3]:
  68. print(generatelist(10))
  69. # Below we have copied the sorting functions from the online book:
  70. # In[4]:
  71. def bubbleSort(alist):
  72. for passnum in range(len(alist)-1,0,-1):
  73. for i in range(passnum):
  74. if alist[i]>alist[i+1]:
  75. temp = alist[i]
  76. alist[i] = alist[i+1]
  77. alist[i+1] = temp
  78. # In[5]:
  79. def shortBubbleSort(alist):
  80. exchanges = True
  81. passnum = len(alist)-1
  82. while passnum > 0 and exchanges:
  83. exchanges = False
  84. for i in range(passnum):
  85. if alist[i]>alist[i+1]:
  86. exchanges = True
  87. temp = alist[i]
  88. alist[i] = alist[i+1]
  89. alist[i+1] = temp
  90. passnum = passnum-1
  91. # In[6]:
  92. def selectionSort(alist):
  93. for fillslot in range(len(alist)-1,0,-1):
  94. positionOfMax=0
  95. for location in range(1,fillslot+1):
  96. if alist[location]>alist[positionOfMax]:
  97. positionOfMax = location
  98. temp = alist[fillslot]
  99. alist[fillslot] = alist[positionOfMax]
  100. alist[positionOfMax] = temp
  101. # In[7]:
  102. def insertionSort(alist):
  103. for index in range(1,len(alist)):
  104. currentvalue = alist[index]
  105. position = index
  106. while position>0 and alist[position-1]>currentvalue:
  107. alist[position]=alist[position-1]
  108. position = position-1
  109. alist[position]=currentvalue
  110. # In[8]:
  111. def shellSort(alist):
  112. sublistcount = len(alist)//2
  113. while sublistcount > 0:
  114. for startposition in range(sublistcount):
  115. gapInsertionSort(alist,startposition,sublistcount)
  116. #print("After increments of size",sublistcount,
  117. # "The list is",alist)
  118. sublistcount = sublistcount // 2
  119. def gapInsertionSort(alist,start,gap):
  120. for i in range(start+gap,len(alist),gap):
  121. currentvalue = alist[i]
  122. position = i
  123. while position>=gap and alist[position-gap]>currentvalue:
  124. alist[position]=alist[position-gap]
  125. position = position-gap
  126. alist[position]=currentvalue
  127. # In[9]:
  128. def mergeSort(alist):
  129. #print("Splitting ",alist)
  130. if len(alist)>1:
  131. mid = len(alist)//2
  132. lefthalf = alist[:mid]
  133. righthalf = alist[mid:]
  134. mergeSort(lefthalf)
  135. mergeSort(righthalf)
  136. i=0
  137. j=0
  138. k=0
  139. while i < len(lefthalf) and j < len(righthalf):
  140. if lefthalf[i] < righthalf[j]:
  141. alist[k]=lefthalf[i]
  142. i=i+1
  143. else:
  144. alist[k]=righthalf[j]
  145. j=j+1
  146. k=k+1
  147. while i < len(lefthalf):
  148. alist[k]=lefthalf[i]
  149. i=i+1
  150. k=k+1
  151. while j < len(righthalf):
  152. alist[k]=righthalf[j]
  153. j=j+1
  154. k=k+1
  155. #print("Merging ",alist)
  156. # In[10]:
  157. def quickSort(alist):
  158. quickSortHelper(alist,0,len(alist)-1)
  159. def quickSortHelper(alist,first,last):
  160. if first<last:
  161. splitpoint = partition(alist,first,last)
  162. quickSortHelper(alist,first,splitpoint-1)
  163. quickSortHelper(alist,splitpoint+1,last)
  164. def partition(alist,first,last):
  165. pivotvalue = alist[first]
  166. leftmark = first+1
  167. rightmark = last
  168. done = False
  169. while not done:
  170. while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
  171. leftmark = leftmark + 1
  172. while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
  173. rightmark = rightmark -1
  174. if rightmark < leftmark:
  175. done = True
  176. else:
  177. temp = alist[leftmark]
  178. alist[leftmark] = alist[rightmark]
  179. alist[rightmark] = temp
  180. temp = alist[first]
  181. alist[first] = alist[rightmark]
  182. alist[rightmark] = temp
  183. return rightmark
  184. # Now we benchmark them:
  185. # In[11]:
  186. sorting_algorithms = [bubbleSort, shortBubbleSort, selectionSort, insertionSort, shellSort, mergeSort, indexMergeSort, quickSort]
  187. #matplotlib.org/gallery/lines_bars_and_markers/line_styles_reference.html
  188. styles = {}
  189. styles[bubbleSort] = "r-"
  190. styles[shortBubbleSort] = "r:"
  191. styles[selectionSort] = "y-"
  192. styles[insertionSort] = "g-"
  193. styles[shellSort] = "g:"
  194. styles[mergeSort] = "b--"
  195. styles[indexMergeSort] = "b:"
  196. styles[quickSort] = "y--"
  197. # In[19]:
  198. from timeit import default_timer as timer
  199. import datetime
  200. # matplotlib may need to be installed separately
  201. import matplotlib.pyplot as plt
  202. def computeandplot(sorting_algorithms):
  203. step = 100
  204. nsamples = 100
  205. samples = range(0, nsamples)
  206. timelimit = 0.05 #seconds, per run
  207. totaltime = 0
  208. print("Maximum computing time:", str(datetime.timedelta(seconds= timelimit*nsamples*len(sorting_algorithms))))
  209. for sortalgo in sorting_algorithms:
  210. attimelimit = False
  211. times = [timelimit for _ in samples]
  212. for i in samples:
  213. if i == 0:
  214. times[i] = 0
  215. continue
  216. n = step * i
  217. if attimelimit == False:
  218. l = generatelist(n)
  219. start = timer()
  220. sortalgo(l)
  221. end = timer()
  222. times[i] = end - start
  223. totaltime += times[i]
  224. if times[i] > timelimit:
  225. times[i] = timelimit
  226. attimelimit = True
  227. plt.plot(samples, times, styles[sortalgo], label=sortalgo.__name__)
  228. print("Actual computing time:", str(datetime.timedelta(seconds=int(totaltime))))
  229. plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
  230. plt.xlabel("list size / {}".format(step))
  231. plt.ylabel("time in seconds")
  232. plt.show()
  233. computeandplot(sorting_algorithms)
  234. # # 4 Sorting small integers
  235. # **4.1**
  236. # In[13]:
  237. def countsort(alist):
  238. maxv = max(alist)
  239. l = [0]*(maxv+1)
  240. for i in alist:
  241. l[i] += 1
  242. k = 0
  243. for i in range(0, len(alist)):
  244. while l[k] == 0:
  245. k += 1 # we count the number of values = k in alist
  246. alist[i] = k
  247. l[k] -= 1
  248. # In[14]:
  249. alist = [54,26,93,17,77,31,44,55,20]
  250. countsort(alist)
  251. print(alist)
  252. # **4.2**
  253. # In[15]:
  254. import math
  255. DEFAULT_BUCKET_SIZE = 5
  256. def bucketsort(array=alist, bucketSize=DEFAULT_BUCKET_SIZE):
  257. if len(array) == 0:
  258. return array
  259. # Determine minimum and maximum values
  260. minValue = array[0]
  261. maxValue = array[0]
  262. for i in range(1, len(array)):
  263. if array[i] < minValue:
  264. minValue = array[i]
  265. elif array[i] > maxValue:
  266. maxValue = array[i]
  267. # Initialize buckets
  268. bucketCount = math.floor((maxValue - minValue) / bucketSize) + 1
  269. buckets = []
  270. for i in range(0, bucketCount):
  271. buckets.append([])
  272. # Distribute input array values into buckets
  273. for i in range(0, len(array)):
  274. buckets[math.floor((array[i] - minValue) / bucketSize)].append(array[i])
  275. # Sort buckets and place back into input array
  276. array = []
  277. for i in range(0, len(buckets)):
  278. insertion_sort(buckets[i])
  279. for j in range(0, len(buckets[i])):
  280. array.append(buckets[i][j])
  281. return array
  282. # In[16]:
  283. def default_compare(a, b):
  284. if a < b:
  285. return -1
  286. elif a > b:
  287. return 1
  288. return 0
  289. # In[17]:
  290. def insertion_sort(array):
  291. for i in range(1, len(array)):
  292. item = array[i]
  293. indexHole = i
  294. while indexHole > 0 and default_compare(array[indexHole - 1], item) > 0:
  295. array[indexHole] = array[indexHole - 1]
  296. indexHole -= 1
  297. array[indexHole] = item
  298. return array
  299. # In[18]:
  300. new_sorting_algorithms = [bucketsort, indexMergeSort, quickSort]
  301. styles[bucketsort] = "g--"
  302. computeandplot(new_sorting_algorithms)