堆排序
- 堆结构就是用数组实现的完全二叉树结构
- 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
- 反之为小根堆
- 堆结构的heapinsert与heapify操作
- heapinsert:新进入的元素都要去跟自己的父元素比较,如果大,就交换。时间复杂度和高度一致,O(logN)
- heapify:取出最大值时,将最后一个元素放到根节点,然后将heapSize-1,将父节点与左右孩子比较,大的放在父节点,然后周而复始。时间复杂度和高度一致,O(logN)
- 如果改变了堆中的一个值,先heapinsert然后heapify无脑完事
- 堆结构的增大与减小
- 优先级队列结构就是堆结构
堆结构的位置如何找?
名称 | 计算方法 |
---|---|
左孩子 | 2*i+1 |
右孩子 | 2*i+2 |
父节点 | (i-1)*2 |
堆排序扩展题目
题目描述:已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素的移动距离可以不超过k,并且k相对于整个数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
思路:搞一个大小为k的小根堆,heapify完后将0位置上的元素放入数组的第一个,因为每个元素排序不可能超过k,因此数组的第一个元素即最小值一定在这个小根堆里。然后放入第k+1个元素,heapify,取出第一个放入第二个位置,以此类推。当数组中剩余位置正好为小根堆大小时,将小根堆中的数从小到大排入即可,因此时间复杂度为O(N*logK),k足够小时甚至可以认为是O(N)。
代码:堆排序扩展题目代码
package p5桶排序和排序内容总结;
import java.util.PriorityQueue;
public class duip1 {
public static void sortedArrDistanceLessK(int[] arr,int k){
//默认是小根堆
PriorityQueue<Integer> heap = new PriorityQueue<>();
//index表示堆尾端数字在数组中的脚标
int index=0;
for (; index <= k; index++) {
heap.add(arr[index]);
}
//i代表小根堆中要放入数组时对应数组的脚标
int i=0;
for(;index<arr.length;i++,index++){
arr[i] = heap.poll();
heap.add(arr[index]);
}
while (!heap.isEmpty()){
arr[i++] = heap.poll();
}
}
}
比较器
- 比较器的实质就是重载比较运算符
- 比较器可以很好的应用在特殊标准的排序上
- 比较器可以很好的应用在根据特殊标准排序的结构上
便利上的代码优化,让代码变短
- 返回负数,认为第一个参数应该排在前面
- 返回正数,认为第二个参数应该排在前面
- 返回0,认为谁放在前面都行
public static class AComp implements Comparator<Interger>{
public int compare(Interger arg0, Interger arg1){
return arg1-arg0;
/*也可写为
if(o1.id < o2.id){
return -1;
}
if(o2.id < o1.id){
return 1;
}
if(o2.id == o1.id){
return 0;
}
因为上述,相减大于为正数,小于为负数,相等为0,所以直接使用return arg1-arg0;最简洁高效
*/
}
}
不基于比较的排序(根据数据状况进行的排序,需要根据不同情况进行定制)
基数排序
对【17,13,25,100,72】进行排序,对不到三位数的数字左边进行补0【017,013,025,100,071】,然后准备十个容器(数组,队列。。。。,可统称为“桶”。所需的桶可通过所出现的数字进行划分,先根据个位数进行
然后从左往右挨个从桶里倒出,先进先出【100,072,013,025,017】
再根据十位数进行,再百数位进行,再分别从左到右出桶。
十位出桶【100,013,017,025,072】,百位出桶【013,017,025,072,100】。
基数排序代码
package p5桶排序和排序内容总结;
import java.util.Arrays;
public class radix_sort {
public static void main(String[] args) {
int[] arr = {6,900,4000,32,11,312,328,91,10};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void radixSort(int[] arr){
if(arr==null||arr.length<2){
return;
}
radixSort(arr,0,arr.length-1,maxbits(arr));
}
//桶排序
public static void radixSort(int[] arr,int L,int R,int digit){
final int radix = 10;//桶是0-9,这个永远不会变,十进制只有10个数
int i = 0,j = 0;
int[] bucket = new int[R-L+1];//有多少个数就创建多少的辅助空间
for(int d=0;d<digit;d++){//有多少位就要进出几次
int[] count = new int[radix];//代表,该位上的数字数量的累加和 length=10
for(i=L;i<=R;i++){
j=getDigit(arr[i],d); //返回i元素第d位上的数字
count[j]++; //记录d位上位j的元素数量 等价于初始的桶排序版本
}
for ( i = 1; i < radix; i++) {
count[i] = count[i]+count[i-1]; //优化后,计算count累加和
}
for(i=R;i>=L;i--){ //相当于一次出桶操作
j=getDigit(arr[i],d);
bucket[count[j]-1] = arr[i]; //从右往左开始,判断该元素d位置数字,将其放到辅助数组中
count[j]--; //位置为count数组中,以该元素d位置数字为脚标的元素-1
}
for(i=L,j=0;i<=R;i++,j++){
arr[i] = bucket[j]; //将辅助数组赋值到arr中对应位置上
}
}
}
//用于返回第d位上的数字
public static int getDigit(int x,int d){
return ((x / ((int) Math.pow(10,d)))%10); //pow() 方法用于返回第一个参数的第二个参数次方。
}
//这个数组中最大值有多少位
public static int maxbits(int[] arr){
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max,arr[i]);
}
int res = 0;
while (max!=0){
max/= 10;
res++;
}
return res;
}
}
标签:总结,arr,int,元素,数组,排序,public
From: https://www.cnblogs.com/benfang/p/17604560.html