排序算法: 三大中级排序算法,原理解析及用法
2018-11-24 00:19
92 查看
三大中级算法
- 难度 ★★
- 算法复杂度O(nlogn)
- 一般情况下排序时间: 快速排序< 归并排序 < 堆排序
快速排序
: 缺点极端情况下效率低堆排序
: 缺点在快的排序算法中相对慢归并排序
: 缺点要有额外内存空间
快速排序 ★★
quick Sort
算法复杂度: O(nlogn) <n乘logn>
思路
每趟取第一个元素,让列表被该元素分为两部分,左边的比他小,右边比他大, 重复用每次得来的第一个元素递归
问题1:
递归py有最大深度问题999次!(虽然可以设置)
问题2:
最坏的情况,如果列表本身是一个倒序列表,那么效率相对较低
(解决方案:随机快排,一开始就随机取一个数放在最左边开始排)
def quick_sort(li, left, right): """ 快速排序 """ if left < right: # 至少两个元素 mid = partition(li, left, right) quick_sort(li, left, mid-1) quick_sort(li, mid+1, right) def partition(li, left, right): """ 将下标为0的元素为参照物,左边的放比他小的,右边放比他大的 """ tmp = li[left] # 第一个位置 while left < right: # 一直循环 while left < right and li[right] >= tmp: # 右边开始找比tmp 小的数放到左边的空位 right -= 1 # 往左走一步 li[left] = li[right] # 把右边的值写到左边空位 # 有可能所有数都比自己大 while left < right and li[left] <= tmp: left += 1 li[right] = li[left] # 把左边的值写到右边的空位上 li[left] = tmp # 把tmp归位 return left # 或者返回right都行 li_test = [3, 2, 7, 1, 6, 9, 8, 4] quick_sort(li_test, 0, len(li_test)-1) print(li_test)
堆排序 ★★
算法复杂度: O(nlogn) <n乘logn>
前提
二叉树的知识储备!!
效率:
快排的时间复杂度优于堆排
def sift(li, low, high): """ 调整堆 :param li: 列表 :param low: 堆的根节点 :param high: 堆的最后一个元素位置 :return: """ i = low # i最开始指向的父 j = 2 * i + 1 # 堆顶左孩子 tmp = li[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and li[j + 1] > li[j]: # 如果右还在比较大且右孩子有 j = j + 1 # j指向右孩子 if li[j] > tmp: li[i] = li[j] i = j # 往下一步看 j = 2 * i + 1 else: # tmp更大,把tmp放到i位置上 li[i] = tmp # 把tmp放到某一级领导位置上 break else: li[i] = tmp # 把tmp放到叶子节点上 def heap_sort(li): """ 堆排序 """ n = len(li) for i in range((n-2)//2, -1, -1): # i表示建堆时调整的部分的根下标 sift(li, i, n-1) # 建堆完成了 for i in range(n-1, -1, -1): # i向当前堆最后一个元素 li[0], li[i] = li[i], li[0] sift(li, 0, i-1) # i-1是新的high li_test = [3, 2, 7, 1, 6, 9, 8, 4] heap_sort(li_test) print(li_test)
堆排序py 模块
import heapq # q : queue 优先列队 import random li = list(range(100)) random.shuffle(li) # 打乱 print(li) heapq.heapify(li) # 建堆 n = len(li) for i in range(n): print(heapq.heappop(li), end=',')
堆排序 topk问题 【常用】
问题:比如热搜网,有n个数,取前k打的数(排序好的)
思路
- 取列表前k个元素建立小根堆,堆顶是目前第k大的数
- 依次向后面遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素,反之换为该元素,并进行一次调整
- 遍历素有元素后,倒序弹出堆顶
import random def sift(li, low, high): """ 调整为小根堆 :param li: 列表 :param low: 堆的根节点 :param high: 堆的最后一个元素位置 :return: """ i = low # i最开始指向的父 j = 2 * i + 1 # 堆顶左孩子 tmp = li[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and li[j + 1] < li[j]: # 如果右还在比较大且右孩子有 j = j + 1 # j指向右孩子 if li[j] < tmp: li[i] = li[j] i = j # 往下一步看 j = 2 * i + 1 else: # tmp更大,把tmp放到i位置上 li[i] = tmp # 把tmp放到某一级领导位置上 break else: li[i] = tmp # 把tmp放到叶子节点上 def top_key(li, k): heap = li[0:k] for i in range((k-2)//2, -1, -1): sift(heap, i, k-1) # 1.建堆 for i in range(k, len(li)-1): if li[i] > heap[0]: heap[0] = li[i] sift(heap, 0, k-1) # 2.遍历 for i in range(k-1, -1, -1): heap[0], heap[i] = heap[i], heap[0] sift(heap, 0, i-1) # 3.出数 return heap li = list(range(1000)) random.shuffle(li) print(top_key(li, 10)) # 测试 前10数
归并排序 ★★
算法复杂度: O(nlogn) <n乘logn>
空间复杂度: O(n)
思路
假设两个列表已有序,那么将他们合并在一起,将列表越分越小,直到分为一个元素
def merge(li, low, mid, high): """ :param li: 列表 :param low: 左列表第一个元素 :param mid: 左列表最后一个元素,那么右列表第一个就是mid+1 :param high: 右列表最后一个元素 :return: """ i = low # 第一段第一个元素 j = mid + 1 # 第二段的第一个元素 tmp_list = [] while i <= mid and j <= high: # 必须左右有数 if li[i] < li[j]: tmp_list.append(li[i]) # 移动后箭头必须移动一位,因为已经把小的值提出到临时list中 i += 1 else: tmp_list.append(li[j]) j += 1 # while 执行完,说明有一段执行完了,剩下的接到tmp中即可 # 分别判断一下那个还有数 while i <= mid: tmp_list.append(li[i]) i += 1 while j <= high: tmp_list.append(li[j]) j += 1 li[low:high+1] = tmp_list # 写回去 def merge_sort(li, low, high): if low < high: # 至少有2个元素,递归 mid = (low + high) // 2 # 整除2 merge_sort(li, low, mid) merge_sort(li, mid+1, high) merge(li, low, mid, high) li_test = [3, 2, 7, 1, 6, 9, 8, 4] merge_sort(li_test, 0, len(li_test)-1) print(li_test)阅读更多
相关文章推荐
- 详解关于react-redux中的connect用法介绍及原理解析
- PHP中curl post的用法及原理解析
- C++ STL中map.erase(it++)用法原理解析
- 最常用的 8 个排序算法:从原理到改进,再到代码兑现透彻解析
- JavaScript中的return布尔值的用法和原理解析
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- C++bitset原理与用法解析
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- 四种线程池的用法,原理和解析。
- 四种基本排序算法原理解析
- List详细用法与原理解析
- android ThreadLocal的原理解析和用法
- malloc,calloc,realloc函数用法,原理及不同解析
- 关于react-redux中的connect用法介绍及原理解析
- Android图片加载库:最全面解析Glide用法
- GeoHash核心原理解析
- MySQL limit实际用法的详细解析
- extern "C"的用法解析
- Zookeeper系列(十五)Zookeeper原理解析之数据存储之Zookeeper内存结构