sort.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. # Natural Language Toolkit: List Sorting
  2. #
  3. # Copyright (C) 2001-2020 NLTK Project
  4. # Author: Steven Bird <stevenbird1@gmail.com>
  5. # URL: <http://nltk.org/>
  6. # For license information, see LICENSE.TXT
  7. """
  8. This module provides a variety of list sorting algorithms, to
  9. illustrate the many different algorithms (recipes) for solving a
  10. problem, and how to analyze algorithms experimentally.
  11. """
  12. # These algorithms are taken from:
  13. # Levitin (2004) The Design and Analysis of Algorithms
  14. ##################################################################
  15. # Selection Sort
  16. ##################################################################
  17. def selection(a):
  18. """
  19. Selection Sort: scan the list to find its smallest element, then
  20. swap it with the first element. The remainder of the list is one
  21. element smaller; apply the same method to this list, and so on.
  22. """
  23. count = 0
  24. for i in range(len(a) - 1):
  25. min = i
  26. for j in range(i + 1, len(a)):
  27. if a[j] < a[min]:
  28. min = j
  29. count += 1
  30. a[min], a[i] = a[i], a[min]
  31. return count
  32. ##################################################################
  33. # Bubble Sort
  34. ##################################################################
  35. def bubble(a):
  36. """
  37. Bubble Sort: compare adjacent elements of the list left-to-right,
  38. and swap them if they are out of order. After one pass through
  39. the list swapping adjacent items, the largest item will be in
  40. the rightmost position. The remainder is one element smaller;
  41. apply the same method to this list, and so on.
  42. """
  43. count = 0
  44. for i in range(len(a) - 1):
  45. for j in range(len(a) - i - 1):
  46. if a[j + 1] < a[j]:
  47. a[j], a[j + 1] = a[j + 1], a[j]
  48. count += 1
  49. return count
  50. ##################################################################
  51. # Merge Sort
  52. ##################################################################
  53. def _merge_lists(b, c):
  54. count = 0
  55. i = j = 0
  56. a = []
  57. while i < len(b) and j < len(c):
  58. count += 1
  59. if b[i] <= c[j]:
  60. a.append(b[i])
  61. i += 1
  62. else:
  63. a.append(c[j])
  64. j += 1
  65. if i == len(b):
  66. a += c[j:]
  67. else:
  68. a += b[i:]
  69. return a, count
  70. def merge(a):
  71. """
  72. Merge Sort: split the list in half, and sort each half, then
  73. combine the sorted halves.
  74. """
  75. count = 0
  76. if len(a) > 1:
  77. midpoint = len(a) // 2
  78. b = a[:midpoint]
  79. c = a[midpoint:]
  80. count_b = merge(b)
  81. count_c = merge(c)
  82. result, count_a = _merge_lists(b, c)
  83. a[:] = result # copy the result back into a.
  84. count = count_a + count_b + count_c
  85. return count
  86. ##################################################################
  87. # Quick Sort
  88. ##################################################################
  89. def _partition(a, l, r):
  90. p = a[l]
  91. i = l
  92. j = r + 1
  93. count = 0
  94. while True:
  95. while i < r:
  96. i += 1
  97. if a[i] >= p:
  98. break
  99. while j > l:
  100. j -= 1
  101. if j < l or a[j] <= p:
  102. break
  103. a[i], a[j] = a[j], a[i] # swap
  104. count += 1
  105. if i >= j:
  106. break
  107. a[i], a[j] = a[j], a[i] # undo last swap
  108. a[l], a[j] = a[j], a[l]
  109. return j, count
  110. def _quick(a, l, r):
  111. count = 0
  112. if l < r:
  113. s, count = _partition(a, l, r)
  114. count += _quick(a, l, s - 1)
  115. count += _quick(a, s + 1, r)
  116. return count
  117. def quick(a):
  118. return _quick(a, 0, len(a) - 1)
  119. ##################################################################
  120. # Demonstration
  121. ##################################################################
  122. def demo():
  123. from random import shuffle
  124. for size in (10, 20, 50, 100, 200, 500, 1000):
  125. a = list(range(size))
  126. # various sort methods
  127. shuffle(a)
  128. count_selection = selection(a)
  129. shuffle(a)
  130. count_bubble = bubble(a)
  131. shuffle(a)
  132. count_merge = merge(a)
  133. shuffle(a)
  134. count_quick = quick(a)
  135. print(
  136. (
  137. ("size=%5d: selection=%8d, bubble=%8d, " "merge=%6d, quick=%6d")
  138. % (size, count_selection, count_bubble, count_merge, count_quick)
  139. )
  140. )
  141. if __name__ == "__main__":
  142. demo()