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. HbuilderX 常用快捷键

    最新2019.3.30版本已经添加idea的快捷键,就不需要再额外记住HbuilderX的快捷键啦~ 链接 输入a,按下tab 加粗 ctrl+B 换行 需要换行的那一行后面加2个空格(或者按下tab ...

  2. linux系统mysql主从配置

    一.原理 mysql主从配置的流程大体如图: 1)master会将变动记录到二进制日志里面: 2)master有一个I/O线程将二进制日志发送到slave; 3) slave有一个I/O线程把mast ...

  3. Netty实战三之Netty的组件和设计

    有关Netty,我们可以从两个视角来讨论Netty:类库的视角以及框架的视角,对于使用Netty编写高效的.可重用的和可维护的代码来说,两者缺一不可. Netty解决了两个响应的关注领域,可以大致标志 ...

  4. oracle的Date类型遇到MyBatis产生的坑

    坑描述: 公司的订单表数据量巨大(亿级),在进行查询的时候,发现一个慢查询. 背景: 数据库:oracle 表:T_order 索引字段:create_date  (字段类型 date) 慢查询sql ...

  5. Python3 系列之 基础语法篇

    基础数据类型 整数 python 可以处理任意大小的整数 浮点数 python 可以处理任意大小的浮点数,但是需要注意的一点是:整数运算永远是精确的(除法也是精确的),而浮点数运算则可能会有四舍五入的 ...

  6. EF实现增删改查

    从来没想到过能在这个上面翻车,感慨自学没有培训来得系统啊,废话不多说 ORM:对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一 ...

  7. mysql date_format()函数

    DATE_FORMAT(DATE,FORMAT)函数 占位符 说明 %a 缩写的星期几(Sun.....Sat) %b 缩写的月份(Jan.....Dec)  %c 数字形式的月份(1.......1 ...

  8. hihoCoder编程练习赛69

    题目1 : 偶数长度回文子串 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个小写字母字符串,请判断它是否有长度为偶数的非空连续回文子串 输入 输入包含多组数据. ...

  9. Oracle11g: simple sql script examples

    ---https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8003.htm drop user geovin; drop ...

  10. 一个AI产品经理怎么看AI的发展

    一个AI产品经理怎么看AI的发展 https://www.jianshu.com/p/bed6b22ae837 最近一直在思考这个问题,人工智能接下来的几年会有什么样的发展,是否真的能够在很多工作岗位 ...