三、排序
1. 冒泡排序
- 思想:每次都是相邻元素进行比较,当后面的元素小于前面元素时,就进行交换位置 。
- 时间复杂度:O(N^2) 空间复杂度:O(1)
- 稳定性:稳定
def bubble_sort_mod(array): for i in range(len(array)): is_sorted = True for j in range(1, len(array) - i): if (array[j] < array[j - 1]): array[j], array[j - 1] = array[j - 1], array[j] is_sorted = False if (is_sorted): break return array
2. 选择排序
- 思想:是对冒泡排序的改进,每一轮仅进行一次交换,把最大值换到最后面即可。
- 时间复杂度:O(N^2) 空间复杂度:O(1)
- 稳定性:不稳定
# 这里是每一轮换最大值,把最大值换到数组最后面去 def selection_sort(nums): for i in range(len(nums)): pos_max = 0 for j in range(1, len(nums) - i): if nums[j] > nums[pos_max]: pos_max = j nums[len(nums)-i-1], nums[pos_max] = nums[pos_max], nums[len(nums)-i-1] return nums
3. 插入排序
- 思想:类似于打牌的时候人们插牌的方式,来一张新牌就把它与前面排好的牌进行比对,找到合适的插入位置。
- 时间复杂度:O(N^2) 空间复杂度:O(1)
- 稳定性:稳定
def insert_sort(nums): for i in range(1, len(nums)): current_value = nums[i] position = i while position > 0 and nums[position-1] > current_value: # while 循环实现 nums[position] = nums[position-1] # 移动操作仅一次赋值,是交换操作的三分之一,此时性能会好一些 position -= 1 nums[position] = current_value # 插入 return nums
4. 希尔排序
- 思想:希尔排序就是再插入排序的基础上多了个gap而已。
- 时间复杂度:O(N^1.3) 空间复杂度:O(1)
- 稳定性:不稳定
def shell_sort(nums): sublistcount = len(nums) // 2 while sublistcount > 0: for startposition in range(sublistcount): gapInsertionSort(nums, startposition, sublistcount) print("After increments of size", sublistcount, "The list is", nums) sublistcount = sublistcount // 2 return nums def gapInsertionSort(nums, start, gap): #插入排序 for i in range(start+gap, len(nums), gap): currentvalue = nums[i] position = i while position >= gap and nums[position-gap] > currentvalue: nums[position] = nums[position-gap] position -= gap nums[position] = currentvalue
5. 计数排序
- 思想:首先找到数组的最大值和最小值,根据这两个值制造一定长度的抽屉。其次要把数字一个个的放到抽屉里面,然后再按顺序拿出来。
- 时间复杂度:O(N) 空间复杂度:O(K), K表示最大值与最小值之差
- 稳定性:稳定
def count_sort(items): mmax, mmin = max(items), min(items) nums = mmax - mmin + 1 counts = [0] * nums for i in range(len(items)): counts[items[i]-mmin] = counts[items[i] - mmin] + 1 pos = 0 for i range(nums): # 只是从抽屉里把所有的数都拿出来,O(n)复杂度 for j in range(counts[i]): items[pos] = i + mmin pos += 1 return items
6. 归并排序
- 思想:将数组持续分为两半,分别对两半运用双指针的办法进行归并排序。是一种递归的方法
- 时间复杂度:O(N) 空间复杂度:O(1)
- 稳定性:稳定
# 更python的写法 def merge_sort(nums): if len(nums) <= 1: # base情况 也就是递归的结束条件 return nums # 分解问题,并递归调用 middle = len(nums) // 2 left = merg_sort(nums[:middle]) # 左半部 right = merg_sort(nums[middle:]) # 右半部 # 合并左右半步,完成排序 merged = [] while left and right: if left[0] <= right[0]: merged.append(left.pop(0)) else: merged.append(right.pop(0)) merged.extend(right if right else left) return merged
7. 快速排序
- 思想:依据一个“中值”数据项把数组分为两半:小于中值的一半和大于中值的一半。然后分别对两半进行快速排序。
- 时间复杂度:O(NlgN) 空间复杂度: 首先就地快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据;
- 稳定性:不稳定
def quickSort(nums): quickSortHelper(nums, 0, len(nums)-1) def quickSortHelper(nums, first, last): if first < last: splitpoint = partition(nums, first, last) # 先找到中点 quickSortHelper(nums, first, splitpoint-1) quickSortHelper(nums, splitpoint+1, last) def partition(nums, first, last): pivotvalue = nums[first] leftmark = first + 1 rightmark = last done = False while not done: while leftmark <= rightmark and nums[leftmark] <= pivotvalue: leftmark += 1 while leftmark <= rightmark and nums[rightmark] >= pivotvalue: rightmark -= 1 if rightmark < leftmark: done = True else: nums[leftmark], nums[rightmark] = nums[rightmark], nums[leftmark] nums[first], nums[rightmark] = nums[rightmark], nums[first] return rightmark