详解桶排序以及排序内容大总结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
//将要排序的数组的前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
}