python排序算法
-
冒泡排序法
def bubble_sort(alist): """冒泡排序""" for j in range((len(alist)-1)): count = 0 for i in range((len(alist)-j-1)): if alist[i] > alist[i+1]: alist[i],alist[i+1] = alist[i+1],alist[i] count += 1 if 0 == count: return # 如果是有序序列 直接结束函数 if __name__ == "__main__": li = [1,4,2,4,56,9,3,12,546,5,7] print(li) bubble_sort(li) print(li) """ 时间复杂度 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。) 最坏时间复杂度:O(n2) 稳定性:稳定 """ # 运行结果 [1, 4, 2, 4, 56, 9, 3, 12, 546, 5, 7] [1, 2, 3, 4, 4, 5, 7, 9, 12, 56, 546]
-
选择排序
def select_sort(alist): """选择排序""" min_index = 0 n = len(alist) for i in range(n-1): # j : n-2 第一个数遍历 到最后第二个 min_index = i for j in range(i+1,n): # 从i+1个下标开始 if alist[min_index] > alist[j]: # 发现后面的数大于前面的数时 min_index = j # 把下标赋值给 min_index alist[i],alist[min_index] = alist[min_index],alist[i] # 交换 当前i下标的值 和 min_index下标的值 if __name__ == "__main__": alist = [2,43,1,14,52,2341,512,21,3413,3123,5,31,65,4,34,2] select_sort(alist) print(alist) """ 时间复杂度 最有时间复杂度:O(n^2) 最坏时间复杂度:O(n^2) 稳定性:不稳定(考虑升序每次选择最大的情况) """ # 运行结果 [1, 2, 2, 4, 5, 14, 21, 31, 34, 43, 52, 65, 512, 2341, 3123, 3413]
-
插入排序
""" def insert_sort(alist): "插入排序" n = len(alist) for j in range(n-1): for i in range(j+1,n): if alist[i] < alist[j]: alist[i],alist[j] = alist[j],alist[i] """ def insert_sort(alist): """插入排序""" n = len(alist) # 从右边的无序列表中取出多少个元素执行这样的过程 for j in range(1,n): # i 代表内存循环的起始位置 i = j # 执行从右边的无序列表中取出第一个元素,即i的位置的元素,然后将其插入到前面的正确位置中 while i > 0: # 可以还成 for i range(j,0,-1) if alist[i] < alist[i-1]: # 这是执行的有序列表 把数插入到 相应的位置 alist[i],alist[i-1] = alist[i-1],alist[i] i -= 1 else: # 第一次的时候 如果i下标的这个元素大于 i-1(有序序列的最大元素) 下标的这个元素 那么不用交换了 直接退出循环 因为前面的本来就是有序的 break """ 时间复杂度 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态) 最坏时间复杂度:O(n2) 稳定性:稳定 """ if __name__ == "__main__": alist = [1,2,4,1,23,12,31,4,12,24,1,245,1251,4,1,3,1,234] insert_sort(alist) print(alist) # 运行结果 [1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 12, 12, 23, 24, 31, 234, 245, 1251]
-
希尔排序
def shell_sort(alist): """希尔排序""" n = len(alist) # gap间隔 # gap = 4 gap = n // 2 # gap变化到0之前,插入算法执行的次数 while gap > 0: # gap 步长包括1 不包括0 # 插入算法,与普通的插入算法的区别就是gap步长 for j in range(gap,n): # j = [gap,gap+1.gap+2,gap+3....n-1] i = j while i > 0: if alist[i] < alist[i-gap]: alist[i],alist[i-gap] = alist[i-gap],alist[i] i -= gap else: break # 缩短gap步长 gap //= 2 """ 时间复杂度 最优时间复杂度:根据步长序列的不同而不同 最坏时间复杂度:O(n2) 稳定性:不稳定 """ if __name__ == "__main__": li = [21,4,1,24,1,1,23,1,4,124,3,41,3,1,3,1,341,2] shell_sort(li) print(li) # 运行结果 [1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 4, 4, 21, 23, 24, 41, 124, 341]
-
快速排序
def quick_sort(alist, first, last): """快速排序""" if first >= last: return mid_value = alist[first] # 这个位置 必须是第一个元素 所以是first low = first high = last while low < high: # high左移 while low < high and alist[high] >= mid_value: high -= 1 alist[low] = alist[high] # low右移 while low < high and alist[low] < mid_value: low += 1 alist[high] = alist[low] # 从循环退出时,low == high alist[low] = mid_value # 对low左边的列表进行快速排序 quick_sort(alist, first, low-1) # 对low右边的列表进行快速排序 quick_sort(alist,low+1, last) """ 最优时间复杂度:O(nlogn) 最坏时间复杂度:O(n2) 稳定性:不稳定 """ if __name__ == "__main__": alist = [12,14,4,1,1,3,1,24,1,41,5,2,5,36,3,6,1,2] print(alist) quick_sort(alist, 0, len(alist)-1) print(alist) # 运行结果 [12, 14, 4, 1, 1, 3, 1, 24, 1, 41, 5, 2, 5, 36, 3, 6, 1, 2] [1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 12, 14, 24, 36, 41]
-
归并排序
def merge_sort(alist): """归并排序""" # 把它的长度求出来 n = len(alist) # 退出递归条件 if n <= 1: return alist # 把它每次分成2份 用到递归 mid = n // 2 # left序列 left_li = merge_sort(alist[:mid]) # 递归把这句话执行完了 在执行下面那句话 # right序列 right_li = merge_sort(alist[mid:]) # 初始化指针 left_pointer, right_pointer = 0, 0 # 分完以后进行排序 result = [] while left_pointer < len(left_li) and right_pointer < len(right_li): # 左边的第一个元素 和 右边的第一个元素 一直这样比下去 if left_li[left_pointer] < right_li[right_pointer]: result.append(left_li[left_pointer]) left_pointer += 1 else: result.append(right_li[right_pointer]) right_pointer += 1 result += left_li[left_pointer:] # 切片就算超了下标不会报错 只会反回空列表 result += right_li[right_pointer:] # 组成一个列表 返回回去 return result """ 时间复杂度 最优时间复杂度:O(nlogn) 最坏时间复杂度:O(nlogn) 稳定性:稳定 """ if __name__ == "__main__": alist = [2,1,4312,2,13,12,3,45,12,4,35,53,6,547,56,34,5,2,1,4] print(alist) sorted_li = merge_sort(alist) print(sorted_li) # 运行结果 [2, 1, 4312, 2, 13, 12, 3, 45, 12, 4, 35, 53, 6, 547, 56, 34, 5, 2, 1, 4] [1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 12, 12, 13, 34, 35, 45, 53, 56, 547, 4312]
-
二分查找法
def binay_search(alist, item): """二分查找法 递归""" n = len(alist) if n > 0: mid = n // 2 if alist[mid] == item: return True elif alist[mid] < item: # 递归只能用新的列表 return binay_search(alist[mid+1:],item) else: return binay_search(alist[:mid],item) return False def binay_search_2(alist,item): """二分查找法 非递归""" # 求列表的长度 n = len(alist) first = 0 last = n-1 while first <= last: mid = (first+last) // 2 # 这个要放在循环里 因为每次都要分 if alist[mid] == item: return True elif alist[mid] > item: # 目标在左边 last = mid-1 else: # 目标在右边 first = mid+1 return False """ 时间复杂度 最优时间复杂度:O(1) 最坏时间复杂度:O(logn) """ if __name__ == "__main__": alist = [1,2,3,4,5,6,7,8,9] print(binay_search(alist,4)) print(binay_search(alist,10)) print(binay_search_2(alist,7)) print(binay_search_2(alist,45)) # 运行结果 True False True False
-
排序算法的稳定性
排序算法的稳定性 稳定性:稳定排序算法会让原本有相等键值的纪录维持相对次序。也就是如果一个排序算法是稳定的,当有两个相等键值的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。 当相等的元素是无法分辨的,比如像是整数,稳定性并不是一个问题。然而,假设以下的数对将要以他们的第一个数字来排序。 (4, 1) (3, 1) (3, 7)(5, 6) 在这个状况下,有可能产生两种不同的结果,一个是让相等键值的纪录维持相对的次序,而另外一个则没有: (3, 1) (3, 7) (4, 1) (5, 6) (维持次序) (3, 7) (3, 1) (4, 1) (5, 6) (次序被改变) 不稳定排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排序算法从来不会如此。不稳定排序算法可以被特别地实现为稳定。作这件事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个对象间之比较,(比如上面的比较中加入第二个标准:第二个键值的大小)就会被决定使用在原先数据次序中的条目,当作一个同分决赛。然而,要记住这种次序通常牵涉到额外的空间负担。