详解桶排序以及排序内容大总结2

一、堆结构(重要):

1、堆结构就是用数组实现的完全二叉树结构

2、完全二叉树中如果每棵子树的最大值都在顶部就是大根堆

3、完全二叉树中如果每棵子树的最小值都在顶部就是小根堆

4、堆结构的heapinsert与heapify操作

5、堆结构的增大和减少

6、优先级队列结构,就是堆结构

二、变成堆结构的两个重要的过程

1、heapInsert过程

    //index表示当前节点,或者是插入的结点位置
    public static void heapInsert(int[] arr,int index){
        //如果子节点的数大于父节点的数,则进行交换位置,变成大根堆
        while(arr[index]>arr[(index-1)/2]){
            //交换位置
            swap(arr,index,(index-1)/2);
            //将当前节点变为index,继续比较
            index = (index-1)/2;
        }
    }

2、heapify过程

    public static void heapIfy(int[] arr,int index,int heapSize){
        //左孩子的下标
        int left = index * 2+1;

        while(left<heapSize){//当左孩子的结点下标小于堆的最大空间,因为左孩子的下标小于右孩子,所以说明该结点有孩子
            //两个孩子中,谁的值大,把下标给largest,left+1表示右孩子的下标
            //left+1 < heapSize:表示有右孩子 arr[left+1] > arr[left]:表示右孩子的数大于左结点的数
            //成立的话,将父节点的下标给largest,不成立的话说明左孩子的数大,将左孩子的下标数给largest
            int largest = left+1 < heapSize && arr[left+1] > arr[left] ? left +1:left;

            //上面是比较两个子节点那个数大,接下来比较父节点的数和上面获取到的最大的数
            largest = arr[index] > arr[largest] ? index : largest;

            //如果此时的结点就是父节点,并不用交换,退出循环
            if(largest == index){
                break;
            }
            //否则,交换最大值的位置和父节点的位置,也就是将最大值的交换到父节点
            swap(arr,largest,index);
            //将当前父节点index变为largest
            index = largest;
            //将左孩子的下标变为当前父节点的左孩子下标
            left = index*2;
        }
    }

三、堆排序,HeapSort过程

public class code_HeapSort{
public static void heapSort(int arr[]){
//首先判断数组长度为0或者为1的时候,就不用进行堆排序
if(arr == null || arr.length<2){
return;
}
//经过上面的判断,可以进行heapInsert过程
for(int i=arr.length;i>=0;i--){
HeapInsert.heapInsert(arr,i,arr.length);
}
int heapSize = arr.length;
HeapIfy.swap(arr,0,heapSize);
while(heapSize > 0){
//判断,循环条件是此堆里面还有数
HeapIfy.heapIfy(arr,0,--heapSize);
}
}
}

四、堆排序扩展题目

将前k的数字放入小根堆,此时小根堆的0位置一定是最小的,因为几乎有序指的是,如果排好序,每一个位置上的数的移动距离一定不会超过k,所以前k个找出的最小值,一定是最小值,k+1位置及以后的数,如果是最小的话,违背了上面规则

优先级队列就是堆结构:以下就是题目解法:

public void sortedArrDistanceLessK(int[] arr,int k){
//首先创建一个优先队列(Java里面的小根堆)
PriorityQueue heap1 = new PriorityQueue<>();
//将要排序的数组的前k个数放进小根堆
//定义一个index,表示当前数组下标
int index1 = 0;
//此时使用数学Math中的min为了防止捣乱,给出的k很大,本身数组很小的情况
for(;index1<Math.min(arr.length,k);index++){
//将前k个数放进优先队列
heap1.add(arr[index]);
}
//定义一个下标,用于从数组0位置将排好序的数放进去
int j = 0;
//每次从优先队列中取出1个数,就添加进去一个数
for(;j<arr.length;j++,index++){
//将优先队列中的根节点取出放在此数组的0位置,一定是最小的
arr[j] = heap1.poll();
//在数组中取出一个数放进优先级队列
heap1.add(arr[index]);
}
//当数组中没有数,将此时优先级队列中的所有的数放进数组
while (!heap.isEmpty()){
arr[j++] = heap.poll();
}
}

时间复杂度:

每次扩容的时间复杂度:O(logN)

每次的时间复杂度:O(N)

java中的堆结构叫优先级队列对象,这叫做黑盒堆

java中的堆结构不支持修改一个数,让它在变成堆结构,此时的时间复杂度很高,所以有的时候需要进行手写堆结构进行最大效率(非常重要)

如果只是简单的给他一个数字,弹出一个数字,使用java中的堆结构就好,不许要手写堆

如果有些形成堆的东西需要自己去调,就需要手写堆,为了提高效率

五、算法中比较器的使用

1、比较器的实质就是重载比较运算符

2、比较器可以很好的应用在特殊标准的排序上

3、比较器可以很好的应用在根据特殊标准排序的结构上

使用方法:
public static void main(String[] args){
//此时的new ACom();表示自定义的一个比较器,直接当参数传入即可做到大根堆转化成小根堆
PriorityQueue heap= new PriorityQueue<>(new ACom());
}

posted @ 2022-01-15 13:37  刘小呆  阅读(39)  评论(0编辑  收藏  举报