时间复杂度 O(N*logN):
归并排序,堆排序(大根堆,小根堆,heapInsert/heapify),快速排序(荷兰国旗问题)。

  1. 归并排序
    L — Mid — R
    先让 左有序,右有序。
    归并 谁小copy谁
def mergeSort(data):def mergeSortFunc(data, L, R):if L==R:return mid = L+(R-L)//2mergeSortFunc(data, L, mid) //左部分 merge sortmergeSortFunc(data, mid+1, R)//右部分 merge sortmerge(data, L, R, mid) // 左右 mergedef merge(data, L, R, M):help_arr = []p1 = Lp2 = M+1while p1<=M and p2<=R:if data[p1] <= data[p2]:help_arr.append(data[p1])p1++else:help_arr.append(data[p2])p2++while p1<=M:help_arr.extend(data[p1:M+1])while p2<R:help_arr.extend(data[p2:R+1])data[L:R+1] = help_arrif len(data) < 2:returnmergeSortFunc(data, 0, len(data)-1)

T(N) = 2T(N/2) +O(N) 所以 时间复杂度就是 O(N*logN), 额外空间复杂度是 O(N)

题目:小和问题 和 逆序对问题

小和问题:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和,求一个数组的小和。

//解法: 暴利查询  每个数查询左侧比他小的值 并且求和, 时间复杂度O(N^2)//解法2: 归并。
一个数a 左边比他小的数加和 产生小和  与 右边有多少个比他大产生 n*a 小和 等价.
'''
例:  1 3 4 2 5
划分左右  1 3 4      2 5
划分左右 1 3    4   2    5
merge 时 右侧比 左侧大的时候 产生小和。1 3 merge:1<3 , 右侧有1个比1 大。所以 1* 1
13  4 merge: 1<4,右侧有1个比1大, 产生1*1,  3和4比较, 3<4,右侧有1个比3大,产生1*3.
得到 1 3 4 2 5 merge: 2 < 5, 右侧有1个比2大,所以产生1*2
得到2 5134 25 merge:
--> 1 < 2: 右侧有2个比1大, 产生2*1.  新的数组得到 1. 原数组为 34  25
--> 3 > 2: 不产生小和。新的数组为 1 2,原数组为 34 5
--> 3 < 5: 右侧有1个比3大, 产生1*3. 新数组得到 1 2 3, 原数组为4 5
--> 4 < 5: 右侧有1个比4大, 产生1*4. 新数组为 1 2 3 4 5. 最后产生的小和: 1*1 + 1*1 + 1*3 + 1*2 + 2*1 + 1*3 + 1*4 = 16merge 实质:让左侧的数 依次碰到每一个右侧的数。 每一次搞定的左侧 不需要重复求,并且计算右侧有多少个比当前数大的时候 可以通过下标直接计算得到 不需要一个个数,因为左侧和右侧都是有序的,当左侧小于右侧的时候 产生小和。
merge sort 好的地方在于 每次比较结果都是变成有序序列。后续比较 只需要左组 和右组进行比较,不需要组内比较, 只需要跨组比较。暴利查询:1: 左侧小于1的 无。  3: 左侧小于3的 1, 4: 左侧小于4的1,3,2: 左侧小于2的15: 左侧小于5的1,2,3,4 加和: 1+1+3+1+1+2+3+4 = 16
'''
def leastSum(data):def mergeSort(data, L, R):if L==R:return 0mid = L+(R-L)//2return mergeSort(data, L, mid) + mergeSort(data, mid+1, R) + mergeAndSum(data, L, R, mid)def mergeAndSum(data, L, R, Mid):p1 = Lp2 = Mid+1help_arr = []ret = 0while p1 <= Mid and p2 <= R:if data[p1]< data[p2]:help_arr.append(data[p1])ret += (R-p2+1)*data[p1]p1++else data[p1]>=data[p2]://相等的时候 copy 右部分。help_arr.append(data[p2])p2++while p1<=Mid:help_arr.extend(data[p1:Mid+1])while p2<=R:help_arr.extend(data[p2:R+1])data[L:R+1] = help_arrreturn ret//leastSum func             if len(data)<2:returnreturn mergeSort(data, 0, len(data)-1, ret)

逆序对:在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,请打印所有的逆序对。(即求每个数 左边多少个比它大的数)

def reverseData(data):if len(data)< 2:returndef mergeSort
  1. 堆:用数组实现的完全二叉树结构(默认下标从0开始)
    0 1 2 3 4 5 6 7
    –> 0
    1 2
    3 4 5 6
    完全二叉树: 结点i, 父节点 (i-1)/2 左孩子: 2i +1, 右孩子: 2i+2

    大根堆:对于每颗子树的最大值 就是 父节点
    小根堆:对于每颗子树的最小值 就是父节点

    heapsize 是堆的一个重要参数。

    任何一个数组 都可以按照大根堆的方式进行排序。 时间复杂度为O(Log_2 N)

def heapInsert(data, index): //数字 来到了 index 位置,如何往上移动while data[index] > data[(index-1)//2]:data[index], data[(index-1)//2] = data[(index-1)//2],data[index]index = (index-1)//2// 即包含了index在0位置 没有父节点的时候  也包含 index在其他位置 有父节点的时候// index = 0 时, (index-1)//2  也等于0

如果用户跟我要数的时候,比如要大根堆的堆顶,但是剩下的还是希望是大根堆结构。如何做?
用最后一个位置填堆顶,heapsize 减1,相当于把最后一个位置在堆里面移除。此时需要调整为大根堆,也就是把堆顶往下调整。

时间复杂度为O(Log_2 N)

def  heapify(data, index, heapSize):left = index * 2 + 1 //左孩子下标while left < heapSize: //下方还有孩子的时候if left+1 < heapSize and data[left+1] > data[left]:largest = left+1else:largest = leftif data[largest] < data[index]:largest = indexbreakdata[largest], data[index] = data[index], data[largest]index = largestleft = index*2 + 1

如果某个位置的值发生了变化,则可以heapInsert 和heapify 各来一遍,最多只可能发生一个函数操作。

  1. 堆排序

    给定一个数组,先把数组整体变成大根堆,此时heapsize=N。

    比如: 9 8 3 7 6 2 1
    step-1: 建立大根堆
    step-2:把堆顶 和最后一个位置交换。把最后一个位置去掉。heapSize-1
    step-3: 调整当前的数组为大根堆。

    如果数组放那边,调整成大根堆 可以自顶往上(时间复杂度为O(logN)),也可以自底往上(时间复杂度度O(N))。
    自底往上把数组调整成大根堆。一开始认为数组为一个完全二叉树,从最后一个数开始 调整为大根堆(看他是否比每一个子孩子大,如果是的话 就往下走)heapify

    堆排序:时间复杂度为O(NlogN), 额外空间复杂度O(1)

//从顶往下
def heapSort(data):if len(data)<2:returnfor i in range(0, len(data)):heapInsert(data[i],i)heapSize = len(data)-1data[0],data[heapSize] = data[heapSize],data[0]while heapSize>0:heapify(data,0,heapSize)data[0],data[heapSize] = data[heapSize],data[0]
  1. 堆扩展
    已知一个几乎有序的数组,几乎有序是指的是 如果把数组排好顺序的话,每个元素一定的距离可以不超过K, 并且K相对于数组来说比较小。请选择一个合适的排序算法针对这个数组排序。
    答: 使用堆。 为什么?

    如何用?
    先把0-(K+1)个数 设置为小根堆,也就是0位置放最小的。
    然后再把1-(K+2)个数 设置为小根堆,得到1的位置。
    。。。
    时间复杂度O(N * log K) (小根堆调整是log K 级别的)

  2. 快速排序

    5-1:快排的partition的思想

    问题1: 给定一个数a,和数组A,请先做到 把小于等于a的放到左边,大于a的放到右边。要求时间复杂度O(N),额外空间复杂度O(1)。
    方法:
    设一个小于等于 区域。最开始为空。
    当前数 <= a, 当前数和小于等于区域下一个数 交换,然后小于等于区域阔一个位置,当前数跳到下一个。
    当前数 >a, 当前数直接跳下一个。
    需要有的参数:小于等于区域指针,当前数指针。

    问题1拓展:荷兰国旗问题。小于a的放到左边,等于a放中间,大于a的放右边。
    方法:
    当前数=划分值, 当前数跳到下一个
    当前数<划分值,当前数 与小于区域 下一个数 交换,小于区域 往后扩一个,当前数跳到下一个
    当前数>划分值,当前数与大于区域 前一个数 交换,大于区域往前扩一个,当前不变。
    当前数与大于区域撞上时,停止。

    小于划分值区域 等于区域 当前数 …(待定区域) 大于区域

def NetherLandsFlag(data,p):def partition(data, L, R, p):// p是划分值,要把L-R区间调整less = L-1 //小于区域的右边界more = R + 1//大于区域的左边界while L< more: // L是当前数下标if data[L] < p://小于划分值data[L], data[less+1] = data[less+1], data[L]//交换less++L++else if data[L]> p:data[L], data[more-1] = data[more-1], data[L]more--else:L++return [less+1, more-1] //等于区域的下标if len(data)<1:returnpartition(data, 0, len(data)-1, p)

5-2:快排
不改进的快速排序:
1) 把数组范围中的最后一个数作为划分值,然后把数组通过荷兰国旗问题分成3个部分:左侧<划分值,中间==划分值,右侧>划分值。
2)对左侧范围和右侧范围,递归执行。

分析:
1)划分值越靠近两侧,复杂度越高,划分值越靠近中间,复杂度越低.
2)可以轻而易举地举出最差的例子,所以不改进的快排时间复杂度是O(N^2) (比如:1,2,3,4,5,6 划分值是6)。最好的情况是partition 的位置几乎在中点,时间复杂度O(NlogN)。
3)为了防止每次都是最差的情况出现,则通过L-R上随机选择一个数和N-1位置交换,这样降低复杂度。 (因为随机选择一个数,所以各种情况都是均等的,最后平均复杂度为O(N
logN))

经典快排:
(L-R上随机选一个数字和N-1位置上的数进行交换)X 在N-1位置上,对0-N-2上的数进行partition <=x, >x (<=x 左侧,>x 右侧,然后把x和>x区域的第一个数交换),保证小于等于区域最后一个数是x.这样对于<=区域继续递归,然后对>x区域递归。 Base case: 区域只有一个值时 不需要排序。
(最差的情况 时间复杂度O(N^2),空间复杂的O(N),最好的情况是时间复杂度O(N*logN),空间复杂度O(logN))

改进的快排:
(L-R上随机选一个数字和N-1位置上的数进行交换)X是N-1上的划分值,在0 - (N-2)上进行荷兰国旗加速 <x, =x, >x(得到3个区域),然后把X和大于区域第一个值交换,并且大于区域往后移一位。然后在<x 和>x 区域分别做递归.

改进VS 经典快排:
改进的快排是每次排序 可以把所有等于x的都搞定 ,而经典的快排是每次都只能搞定一个数(也就是只有最后那个划分值 放到正确的位置)

def quickSort(data):def partition(data, L, R)://less = L-1more = R // 最后一个作为划分值while L < more:if data[L] < data[R]:data[L], data[less+1] = data[less+1],data[L]L++less++else if data[L] > data[R]:data[L], data[more-1] = data[more-1],data[L]more-- else:L++   data[more-1], data[R] = data[R],data[more-1]return (less+1, more)def q_sort(data, L, R)://排好L-R之间的数if L<R:index = random(L, R)data[R], data[index] = data[index], data[R]p = partition(data, L, R)q_sort(data, L, p[0]-1)q_sort(data, p[1]+1, R)if len(data)<2:returnq_sort(data, 0, len(data)-1)

基础算法-2: 时间复杂度为O(N*logN)的排序算法相关推荐

  1. php常用算法的时间复杂度,php的几个经典排序算法及时间复杂度和耗时​

    $arr = []; for ($i=0; $i 测试结果:排序用时(秒):5.2821290493011 php排序里的经典算法首先想到的就是冒泡排序法, 排序思想:两两交换小数上浮大数下沉每轮浮出 ...

  2. O(N*logN)的排序算法

    时间复杂度为:O(N*logN)的排序算法 注:图来自于网络 归并排序(Merge Sort) 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide ...

  3. <<算法很美>>——(三)十大排序算法(上)

    目录 前言 冒泡排序 图解冒泡 代码实现 冒泡优化 选择排序 图解选排​ 代码实现 插入排序 图解插入 ​代码实现 希尔排序 图解希尔 ​代码实现: 归并排序 图解归并 ​代码实现 快速排序 图解快排 ...

  4. 【数据结构与算法】之深入解析十大常用排序算法的原理分析和算法实现

    一.十大排序算法的对比 排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 排序方式 稳定性 冒泡排序 O(n2) O(n) O(n2) O(1) In-place 稳定 选择排序 O(n2) ...

  5. 【轻松学排序算法】眼睛直观感受几种常用排序算法(转)

    1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通 ...

  6. 算法学习02:认识O(logN)的排序

    01归并排序 归并排序就是先将一个数组的左侧与右侧都有序,然后用两个指针分别比较两个数组元素的大小,将比较结果复制到辅助数组中. 整体采用递归方法,确定递归基是需要排序的序列只有一个数的时候.其余情况 ...

  7. 计数排序:时间复杂度仅为 O(n) 的排序算法

    一.简介 计算排序假设 n 个输入元素都是 0 到 k 区间内的一个整数,其中 k 为某个整数. 基本原理: 创建一个长度为 k+1 的数组 count[],它的 count[i] 的值对应输入数组中 ...

  8. 算法设计与分析 自创O(n)排序算法 适用于任何有理数

    受桶排序思想的启发,想到了这个算法.不同之处在于,桶排序是对于每个bucket各自排序,而本算法桶内部不需要排序. 功能 本算法可以在有限空间内,将任意有理数排序,平均时间复杂度为O(n) 输入:需要 ...

  9. <<算法很美>>——(三)十大排序算法(下)

    目录 1. 奇数在左偶数在右 2. 最快效率求出乱序数组中第k小的数 3. 数组中有一个数字出现次数超过数组长度一半 4. 合并两个有序数组 5. 数组中的逆序对 6. 排序数组中两个数字之和 7. ...

最新文章

  1. Google 公司的 Java 语言编写规范
  2. 央行:货币政策稳健并不意味着一成不变
  3. 单脉冲雷达的相干干扰的研究文章_什么是量子纠缠和量子退相干?这个比喻太绝了!...
  4. Servlet课程0425(五) sendRedirect实现不同页面共享数据
  5. boost::hana::make_range用法的测试程序
  6. Android Library projetcts cannot be exported.
  7. php for循环 循环奇数,php – Foreach,每个n项的特殊处理(奇数,甚至例如)
  8. Mentor PADS 9.5下载安装及破解指南
  9. 【无码专区12】子集和(背包dp)
  10. 调整 Windows系统参数网址
  11. iphone最新款手机_苹果用户不换安卓手机的8点原因,最后一点最关键
  12. 湖人签阿泰是双赢之举 防罗伊打压火箭是两大关键
  13. python文字转图片_技能:如何使用Python将文本转为图片
  14. 网易回应暴力裁员事件并道歉了!连发两声明:当事人绩效确不合格...刘强东说了这句话,意外上热搜...
  15. log4j2关闭debug日志
  16. 从零開始搭建微信硬件开发环境全过程——1小时掌握微信硬件开发流程
  17. ps图层高级扩展知识
  18. Android笔记:多开/分身检测
  19. 熬夜总结的2022java面试题
  20. 区块链智能合约----Solidity状态修饰符view、pure

热门文章

  1. php mysql安装包_apache php mysql集成开发环境
  2. 看齐iOS砍掉祖传功能,Android 16G内存也危险了
  3. python中x+=y和x=x+y的区别
  4. android布局置顶_[置顶] Android系统五大布局详解Layout
  5. 局域网ip冲突的时候,释放ip重新获取
  6. 《安富莱嵌入式周报》第317期:开源60W小型UPS电源,0.1Hz - 200MHz 频率计,纯C实现的SokolGFX渲染库, FreeRTOS Trace
  7. git 警告: LF will be replaced by CRLF in 解决办法
  8. android和ios适配_针对iOS和Android设计时“并非总是”情况的8个UX设计技巧
  9. Linux网络-IP协议
  10. 漏洞扫描以及常用扫描工具总结