桶排序和排序总结

堆排序

  1. 堆结构就是用数组实现的完全二叉树结构
  2. 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
  3. 反之为小根堆
  4. 堆结构的heapinsert与heapify操作
    • heapinsert:新进入的元素都要去跟自己的父元素比较,如果大,就交换。时间复杂度和高度一致,O(logN)
    • heapify:取出最大值时,将最后一个元素放到根节点,然后将heapSize-1,将父节点与左右孩子比较,大的放在父节点,然后周而复始。时间复杂度和高度一致,O(logN)
    • 如果改变了堆中的一个值,先heapinsert然后heapify无脑完事
  5. 堆结构的增大与减小
  6. 优先级队列结构就是堆结构

堆结构的位置如何找?

名称 计算方法
左孩子 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();
        }
    }

}

比较器

  1. 比较器的实质就是重载比较运算符
  2. 比较器可以很好的应用在特殊标准的排序上
  3. 比较器可以很好的应用在根据特殊标准排序的结构上

便利上的代码优化,让代码变短

  • 返回负数,认为第一个参数应该排在前面
  • 返回正数,认为第二个参数应该排在前面
  • 返回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】,然后准备十个容器(数组,队列。。。。,可统称为“桶”。所需的桶可通过所出现的数字进行划分,先根据个位数进行

image-20230803190802270

然后从左往右挨个从桶里倒出,先进先出【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;
    }
}

(ps:参考了杀戒之声的笔记
杀戒之声
左神的课

posted @   无聊的飞熊  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示