7.堆排序:
堆排序思想—>完全二叉树
1)满二叉树
2)若不是满二叉树,最下面一层从左至右一次补齐。
堆积性质:子结点的键值或索引总是小于(或大于)它的父节点。
堆排序物理结构:数组
逻辑结构:完全二叉树
已知数组元素下标为i,那么这个元素对应的左孩子下标为2i+1,右孩子下标为2i+2,父节点为(i-1)/2。
数组模拟举栗子:
大根堆、小根堆
大根堆:完全二叉树中,任何一颗子树的最大值均为子树的根节点。
小根堆:完全二叉树中,任何一颗子树的最小值,均为子树的根节点。
例如刚刚上面例子,既不是大根堆也不是小根堆,数个普通树。
建立大根堆:通过交换一直保证根节点最大,一旦发现即将放入的数字比根节点要大,令其与根节点交换,只要不符合大根堆定义就一层一层往上换,一直比到此树的总根。
堆排序基本思想:
将待排序列构造成大顶堆,这时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复进行,便能得到一个有序序列。
堆排序应用例题:
现有输出流,每次输出一个正整数,计算某一时刻当前的中位数。
思路:
建立大小根堆,大根堆放较小的n/2个数,小根堆放较大的n/2个数,以达到随时取当前中位数的目的。
要平衡两个堆中的数据数量,数量差大于1时,从多的堆的堆顶取出放另一个堆,按照堆的规则进行调整。
弹出堆顶:堆顶元素与最后一个元素交换,然后让堆的大小-1.之后对堆进行调整。
8.计数排序:
非比较类排序,开一个数组,数组大小由待排序列大小决定,遍历待排序列元素在新数组内标记。输出标记的元素即可。
9.桶排序:
计数排序的升级,假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(可以使用别的排序算法或者以递归的方式继续桶排序)。
1)确定申请桶的数量,设置定量长度。
2)遍历输入数据,并且把数据一个个放到对应的桶里。
3)对每个不是空的桶进行排序。
4)从不是空的桶里把排好序的数据拼起来。
桶内n个元素,m个桶
时间复杂度O(n+C)
额外空间复杂度O(n+m)
10.基数排序:
整几个基准数,对应所属的基准数往里放,再依次打印。
按照低位先排序,然后收集;再按照高位排序,然后再收集,以此类推一直到最高位。有时候有些属性是有优先级的,先低优先级,再高优先级。
1)取得数组中的最大数,并取得位数;
2)arr为原始数组,从最低位开始取每个位组成基数数组;
3)对基数进行计数排序(利用计数排序适用于小范围数的特点)
时间复杂度O(n*w)
n位输入数组的长度,w为输入数字中最长数字的长度。
空间复杂度:O(n)
排序的稳定性
序列中出现了相同的值,若能保证排序后相同的值在原始序列中相对次序保持不变,则排序具有稳定性。
最后、
sort函数真香!!!!
枚举
一一列举!!
1.通过遍历所有的候选答案以找到正确的解。
2.不重不漏。
引入
形如a^3=bbb+ccc+ddd的等式被称为完美立方等式。求对以一个正整数N(N<=100),寻找所有的四元组abcd,abcd大于1小于等于N,b<=c<=d.
思路:四重循环枚举abcd,a在最外面,d在最里面,每一层都是从小到大枚举。
a【2,N】
b【2,a-1】
c【b,a-1】
d【c,a-1】
优化枚举,减少枚举次数
1.选择合适的枚举对象
2.选择合适的枚举方向-----方便排除非法和不是最优的情况
3.选择合适的数据维护方法-------转化问题
例题1
一个数列,有q次询问,每次询问数列的第li个元素到第ri个元素的和。
思路:
用前缀和,把前缀和算出来放入sum数组。用整体的和减去部分的和,剩下所求部分的和。
单次查询的时间复杂度为O(1),总时间复杂度为O(N+Q)
而暴力的话为O(N*Q)
类似于前缀和思想的还有前缀最大值、最小值,前缀异或值等。
例题2
数列修改问题
数列an N属于1到1e5,进行Q次修改,每次把数列从第li个元素到第ri个元素中的每个元素加上ki,求所有修改操作结束后的数列an。
思路:
1.暴力遍历
2.把对区间的修改优化成对区间端点的修改。头端点差值增加了k,尾端点差值减少了k。