快速排序 O(n logn) 堆排序 O(n logn) 归并排序 O(n logn)
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)的更多相关文章
- 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)
如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...
- 有k个list列表, 各个list列表的元素是有序的,将这k个列表元素进行排序( 基于堆排序的K路归并排序)
解题思路: 排序方法:多路归并排序 每次将n个list的头元素取出来,进行排序(堆排序),最小元素从堆中取出后,将其所在list的下一个元素 放入堆中,调整堆序列. 函数实现原型: void list ...
- 整理C++面试题for非CS程序猿——更新至【48】
结合网上的C++面试题+自己的面经,进行整理记录,for我这种非CS的程序猿.(不定期更新,加入了自己的理解,如有不对,请指出) [1] new/delete和malloc/free的区别和联系? 1 ...
- 寻找最大(小)的K个数
<<编程之美>>一书中提到了寻找最大的K个数的问题,问题可以简单描述为:在长度为N的数组中,寻找第K(K<N)个最大的数.问题的解法涉及到了很多排序算法,对我们理解和运用 ...
- 数据结构 - 归并排序(merging sort)
归并排序(merging sort): 包含2-路归并排序, 把数组拆分成两段, 使用递归, 将两个有序表合成一个新的有序表. 归并排序(merge sort)的时间复杂度是O(nlogn), 实际效 ...
- postgresql-分页数据重复问题探索
postgresql-分页数据重复探索 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. 如何处理? 这个问题出现的原因是因为选择的排序字 ...
- postgresql-分页重复数据探索
# postgresql-分页重复数据探索 ## 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. ### 如何处理? 这个问题出现的原因 ...
- 常见算法的python实现
提到排序算法,常见的有如下几种:冒泡排序.选择排序.插入排序.快速排序.堆排序.归并排序.希尔排序:查找算法最常见二分查找.这些算法的时间复杂度如下: 算法名称 时间复杂度(一般情况) 冒泡排序 O( ...
- go实现堆排序、快速排序、桶排序算法
一. 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法.以大堆为例利用堆顶记录的是最大关键字这一特性,每一轮取堆顶元素放入有序区,就类似选择排序每一轮选择一个最大值放入有序区,可以把堆排序看成是 ...
随机推荐
- 从零开始学安全(十四)●Windows Server 2012 R2 本地搭建FTP服务器
打开仪表盘添加角色和功能向导 下一步 等待安装完成 打开iis 新建站点 点击 选一个目录作为 ftp文件服务器的存储路径 后面就和iis 创建站点一样了 匿名就不需要密码 就可以访问基本需要特定的账 ...
- [android] 服务的生命周期(混合方式)
绑定服务:可以调用服务里面的方法, 如果调用者activity销毁了,服务也会跟着销毁 单独解除绑定的时候,服务也会被销毁 开启服务:不可以调用服务里面的方法 如果调用者activity退出了,服务还 ...
- Java中的匿名内部类及内部类的二三事
匿名内部类适合创建那些只需要使用一次的类,它的语法有些奇怪,创建匿名内部类会立即创建一个该类的实例,这个类定义立即消失,且不能重复使用. 定义匿名类的格式如下: new 实现接口() |父类构造器(实 ...
- eclipse编写js代码没有提示
安装插件 点击Help,选择Eclipse Marketplace... 搜索js,安装AngularJS Eclipse 重启eclipse,右键项目,选择Configure(配置),选择Conve ...
- 04-HTML-图片标签
<html> <head> <title>图片标签学习</title> <meta charset="utf-8"/> ...
- vue单页应用添加百度统计
前言 申请百度统计后,会得到一段JS代码,需要插入到每个网页中去,在Vue.js项目首先想到的可能就是,把统计代码插入到index.html入口文件中,这样就全局插入,每个页面就都有了;这样做就涉及到 ...
- JS之console.log详解以及兄弟姐们邻居方法扩展
console.log() 基本用法 console.log,前端常用它来调试分析代码,你可以在任何的js代码中调用console.log(),然后你就可以在浏览器控制台看到你刚才打印的常量,变量,数 ...
- 洛谷P3209 [HNOI2010]PLANAR(2-SAT)
题目描述 若能将无向图G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称G是平面图.判定一个图是否为平面图的问题是图论中的一个重要问题.现在假设你要判定的是一类特殊的图,图中存在一个包含所 ...
- BZOJ2199: [Usaco2011 Jan]奶牛议会(2-SAT)
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 559 Solved: 360[Submit][Status][Discuss] Descriptio ...
- python实现简单的计算器功能
如想实现一个计算器的功能,输入格式为字符串,不能运用python里面的内置方法,出去简单的加减乘除,设计一个相对高级的计算器: a = '1 - 2 * ( ( 6 0 -3 0 +(-40/5) * ...