NB三人组

快速排序

  • 思路"

    • 取一个元素P (第一个元素), 使元素归位
    • 列表被P 分成两部分,左边都比P小,右边比P大;
    • 递归完成排序.
  • 问题 如果是已经排序好的 倒叙 列表 则会 递归深度越界
    • 每次
# 时间复杂度: O(n*logn)
import sys
import random
from cal_time import cal_time
# 设置递归深度
sys.setrecursionlimit(10000) def _quick_sort(li, left, right):
if left < right: # 递归区域至少有两个元素
# 归位 [left, right] --> [left, mid-1] [mid+1, right]
mid = partition(li, left, right)
_quick_sort(li, left, mid-1)
_quick_sort(li, mid+1, right) @cal_time
def quick_sort(li):
_quick_sort(li, 0, len(li)-1) def partition(li, left, right):
# 解决最坏情况
# i = random.randint(left, right)
# li[i], li[left] = li[left], li[i]
tmp = li[left]
while left < right:
while left < right and li[right] >= tmp:
right -= 1
li[left] = li[right]
while left < right and li[left] <= tmp:
left += 1
li[right] = li[left]
li[left] = tmp # 此时 left = right
return left def gogogo2(li, left, right):
# 区域1:[left, i] 区域2:[i+1, j-1]
i = left - 1 # 初识区域1和区域2都空
for j in range(left, right):
if li[j] < li[right]: # 归到区域1
i += 1
li[j], li[i] = li[i], li[j]
li[right], li[i+1] = li[i+1], li[right]
return i+1 @cal_time
def quick_sort2(li):
return _quick_sort2(li) def _quick_sort2(li):
if len(li) < 2:
return li
x = li[0]
left = [li[i] for i in range(1, len(li)) if li[i] <= x]
right = [li[i] for i in range(1, len(li)) if li[i] > x]
_quick_sort2(left)
_quick_sort2(right)
return left + [x] + right # @cal_time
# def sys_sort(li):
# li.sort() import copy li = list(range(10000))
random.shuffle(li)
li2 = copy.copy(li) quick_sort(li)
quick_sort2(li2) # sys_sort(li) # 另类写法 def my_partition(li, l, r):
a = li[l]
i = l + 1
while i <= r:
if li[i] >= a:
li[r], li[i] = li[i], li[r]
r -= 1
else:
i += 1
li[i - 1], li[l] = li[l], li[i - 1]
return i def quick_sort(li, left, right):
if left < right:
tmp = my_partition(li, left, right)
quick_sort(li, left, tmp -1)
quick_sort(li, tmp, right) @cal_time
def _quick_sort(li):
quick_sort(li, 0, len(li) - 1)

堆排序

  • 前传: (树与二叉树简介)

    • 树是一种数据结构 比如目录结构
    • 树是一种可以递归定义的数据结构
    • 树是由N个节点组成的集合
      • 如果n=0,那么是一颗空树:
      • 如果n>0,那么在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树.
    • 概念:
      • 根节点,叶子节点
      • 树的深度(高度)
      • 树的度
      • 孩子节点/父节点
      • 子树
  • 时间复杂度 O(n log n)
import random
from cal_time import cal_time def sift(li, low, high):
# low 表示堆顶下标, high表示堆中最后一个元素下标
tmp = li[low]
i = low
j = 2 * i + 1
while j <= high: # 第二种循环退出情况,没有孩子和tmp竞争i这个位置
if j+1 <= high and li[j+1] > li[j]: # 如果右孩子存在并且比左孩子大 j指向右孩子
j += 1
if li[j] > tmp: # 判断 证明 孩子比父亲大 交换
li[i] = li[j]
i = j # 从新赋值堆顶
j = 2 * i + 1 # 重新赋值孩子
else:
break # 第一种循环退出情况,tmp比目前两个孩子都大
# 将取出的 tmp 从新赋值回空出的位置
li[i] = tmp @cal_time
def heap_sort(li):
# 1. 从列表构造堆 low的值和high的值
n = len(li)
for low in range(n//2-1, -1, -1):
sift(li, low, n-1)
# 2. 挨个出数 利用原来的空间存储下来的值,但是这些值不属于堆
for high in range(n-1, -1, -1): # range(n-1,0,-1)
li[high], li[0] = li[0], li[high] # 1.退休 2.棋子
sift(li, 0, high-1) # 3.调整 li = list(range(100000))
random.shuffle(li)
heap_sort(li)

内置模块做堆

import heapq
import random
# heap queue
# priority queue 优先队列 li = [9,5,8,4,7,6,3,2,1]
heapq.heapify(li) # 小顶堆
print(li)
heapq.heappush(li, 1) # 给堆里添加值
print(li)
ele = heapq.heappop(li) # 从堆顶取值
print(ele)
print(li)
# ele = heapq.heappop(li)
# print(ele)
# print(li) # 做堆排序
heapq.heapify(li) # 建堆
res = []
while li:
res.append(heapq.heappop(li))
print(res)

归并排序

  • 假设现在的列表分两段有序,如何将其合成为一个有序列表
import random
from cal_time import cal_time def merge(li, low, mid, high):
i = low # 左边的指针
j = mid + 1 # 右边的指针
li_tmp = []
while i <= mid and j <= high: # 两边都有数
if li[i] <= li[j]:
li_tmp.append(li[i])
i += 1
else:
li_tmp.append(li[j])
j += 1
# i<=mid 和 j<=high 两个条件 只能有一个满足
while i <= mid:
li_tmp.append(li[i])
i += 1
while j <= high:
li_tmp.append(li[j])
j += 1
# li_tmp 0~high-low 复制回li low~high
for i in range(len(li_tmp)):
li[low+i] = li_tmp[i] def _merge_sort(li, low, high):
if low < high: # 至少两个元素
# print(li[low:high+1], '->', end=' ')
mid = (low + high) // 2 # 分解
# print(li[low:mid+1], li[mid+1: high+1])
_merge_sort(li, low, mid) # 递归排序左边
_merge_sort(li, mid+1, high) # 递归排序右边
# print(li[low:mid+1], li[mid+1: high+1], '->', end=' ')
merge(li, low, mid, high) # 一次归并 合并
# print(li[low:high+1]) @cal_time
def merge_sort(li):
_merge_sort(li, 0, len(li)-1) # li = [10,4,6,3,8,2,5,7]
# merge_sort(li, 0, len(li)-1)
# # print(li) # li = list(range(100000))
# random.shuffle(li)
# merge_sort(li) # li.sort() li = [
{'age': 22, 'name':'abc'},
{'age': 18, 'name':'qwe'},
{'age': 22, 'name':'asd'},
{'age': 26, 'name':'zxc'},
{'age': 22, 'name':'tyu'},
]
li.sort(key=lambda x:x['age'])
print(li)

NB三人组-小结

  • 三种排序算法的时间复杂度都是

    • O(n log n)
  • 一般情况下,就运行时间而言:

    • 快速排序 < 归并排序 < 堆排序
  • 三种排序算法的缺点:

    • 快速排序:极端情况下排序效率低
    • 归并排序:需要额外的内存开销
    • 堆排序:在快的排序算法中相对较慢
排序方法 时间复杂度 空间复杂度 稳定性 代码复杂度
最坏情况 平均情况 最好情况
冒泡排序 O(n2) O(n2) O(n) O(1) 稳定 简单
直接选择排序 O(n2) O(n2) O(n2) O(1) 不稳定 简单
直接插入排序 O(n2) O(n2) O(n2) O(1) 稳定 简单
快速排序 O(n2) O(nlogn) O(nlogn) 平均情况O(logn); 最坏情况O(n) 不稳定 较复杂
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 复杂
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 较复杂

快速排序 O(n logn) 堆排序 O(n logn) 归并排序 O(n logn)的更多相关文章

  1. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

  2. 有k个list列表, 各个list列表的元素是有序的,将这k个列表元素进行排序( 基于堆排序的K路归并排序)

    解题思路: 排序方法:多路归并排序 每次将n个list的头元素取出来,进行排序(堆排序),最小元素从堆中取出后,将其所在list的下一个元素 放入堆中,调整堆序列. 函数实现原型: void list ...

  3. 整理C++面试题for非CS程序猿——更新至【48】

    结合网上的C++面试题+自己的面经,进行整理记录,for我这种非CS的程序猿.(不定期更新,加入了自己的理解,如有不对,请指出) [1] new/delete和malloc/free的区别和联系? 1 ...

  4. 寻找最大(小)的K个数

    <<编程之美>>一书中提到了寻找最大的K个数的问题,问题可以简单描述为:在长度为N的数组中,寻找第K(K<N)个最大的数.问题的解法涉及到了很多排序算法,对我们理解和运用 ...

  5. 数据结构 - 归并排序(merging sort)

    归并排序(merging sort): 包含2-路归并排序, 把数组拆分成两段, 使用递归, 将两个有序表合成一个新的有序表. 归并排序(merge sort)的时间复杂度是O(nlogn), 实际效 ...

  6. postgresql-分页数据重复问题探索

    postgresql-分页数据重复探索 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. 如何处理? 这个问题出现的原因是因为选择的排序字 ...

  7. postgresql-分页重复数据探索

    # postgresql-分页重复数据探索 ## 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. ### 如何处理? 这个问题出现的原因 ...

  8. 常见算法的python实现

    提到排序算法,常见的有如下几种:冒泡排序.选择排序.插入排序.快速排序.堆排序.归并排序.希尔排序:查找算法最常见二分查找.这些算法的时间复杂度如下: 算法名称 时间复杂度(一般情况) 冒泡排序 O( ...

  9. go实现堆排序、快速排序、桶排序算法

    一. 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法.以大堆为例利用堆顶记录的是最大关键字这一特性,每一轮取堆顶元素放入有序区,就类似选择排序每一轮选择一个最大值放入有序区,可以把堆排序看成是 ...

随机推荐

  1. CIL中间语言浅谈

    CIL中间语言 通用中间语言(Common Intermediate Language,简称CIL)(曾经被称为微软中间语言或MSIL)是一种属于通用语言架构和.NET框架的低阶(lowest-lev ...

  2. devDependencies与dependencies (转载)

    简单整理: 一.关键词解释 devDependencies用于本地环境开发 dependencies用户发布环境 devDependencies是只会在开发环境下依赖的模块,生产环境不会被打入包内.通 ...

  3. webpack4 系列教程(十四):Clean Plugin and Watch Mode

    作者按:因为教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<webpack4 系列教程(十四):Clean Plugin and Watch Mode>原文地址.更欢迎 ...

  4. tomcat中 server.xml

    tomcat服务器, 配置文件server.xml中的各项配置的意义 <?xml version="1.0" encoding="UTF-8"?> ...

  5. 学会JavaScript函数式编程(第1部分)

    摘要: JS函数式编程入门. 原文:学会使用函数式编程的程序员(第1部分) 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 在这篇由多部分组成的文章中,接下来将介绍函数式编程的一些概念 ...

  6. js 位运算符

    MDN定义:位运算符将它的操作数视为32位元的二进制串(0和1组成)而非十进制八进制或十六进制数. 例如:十进制数字9用二进制表示为1001,位运算符就是在这个二进制表示上执行运算,但是返回结果是标准 ...

  7. 文件权限解释rwx

    linux文件权限 r 读w 写x (execute)执行 rwxrw-r-- 解释:rwx文件所有者对该文件有读写执行的权限:rw- 组内用户对该文件有读写的权限:r-- 其他非本组用户对该文件具有 ...

  8. jsp引入本地图片

    jsp引入本地图片 通用解决方法: 在tomcat的server.xml配置文件中,在<host></host>标签中间添上一句 <!-- docBase : 磁盘绝对路 ...

  9. C# SqlBulkCopy类批量导入 测试

    一.功能说明 1.可以选择,只导入部分列,或者导入全部列. 2.导入速度的确比一般sql要快. 3.不用写sql语句 ----------------------------------------- ...

  10. 洛谷P4593 [TJOI2018]教科书般的亵渎(拉格朗日插值)

    题意 题目链接 Sol 打出暴力不难发现时间复杂度的瓶颈在于求\(\sum_{i = 1}^n i^k\) 老祖宗告诉我们,这东西是个\(k\)次多项式,插一插就行了 上面的是\(O(Tk^2)\)的 ...