(Java)算法基础3:堆排序/比较器/桶排序排序总结

堆结构(重点)——一种特殊完全二叉树

O(logN)
在这里插入图片描述

完全二叉树:或者是满的,在不满的最后一层也是从左往右依次变满的。

堆逻辑上就是完全二叉树

实现完全二叉树方法:把数组必须从零出发的连续一段可以对应成完全二叉树

size:从零出发的连续一段。
size=7表示要把数组从0到7七个数作为数组对应

在这里插入图片描述

所以根据这样,就可以把从零出发连续的一段,脑补成一段完全二叉树。

所以:怎么把数组连续出发的一段,实现成一个堆?

如下图,当6插入,它要找5比较大小(即和其父节点比较大小),找到父节点的方法在上图(i-1)/2

和父节点比较后,如果比父节点大,要与其交换。产生结果如下二图

在这里插入图片描述在这里插入图片描述

同理,继续插入7,不断地往上换,和父节点比较。通过这样的调整方式,我可以数组每插入一个数,就将数组调整为大根堆。

在这里插入图片描述

这个过程叫heapInsert过程,code如下

在这里插入图片描述

public static void heapInsert(int[] arr,int index)
{
   
	while(arr[index] > arr[(index-)/2])
	{
   
		swap(arr,index,(index-1)/2);
		index = (index-1)/2;
	}
}

index = (index-1)/2index也要指向父节点位置。

现在已经可以保证插入数据,依旧保持堆结构了,现在用户需要返回最大值,并且保证剩下的数字仍然是堆结构。最大值毫无疑问是第一个数字,但是把,第一个数字返回以后arr[0]就空缺了,后面也无法组成大根堆。

这个时候操作是将最后一个数字copy到空位上,然后heapsize–(相当于有效区间缩小,最后一个数字就被抹除了,参考下图)

在这里插入图片描述

这个时候整个数组还不是堆,从头结点开始调整。和其左右孩子的最大值比较,头结点小就交换

heapify(堆化,非常重要的方法,从一个位置出发往下动保证堆结构):

public static void heapify(int[] arr,int index,int size)
{
   
	int left = 2*index + 1;
	while(left < size)//;eft+1代表右孩子
	{
   
		int largest = left + 1 < size && arr[left] < arr[left+1] ? left+1:left;//选出左右孩子大的那个
		largest = arr[index] < arr[largest] ? largest:index;//选出父节点和子节点中最大那个。

		//找出父节点和左右孩子节点中最大的数的下标

		//如果父节点最大,不用交换
		if(largest == index) break;//?

		//子节点大,交换子节点和父节点
		swap(arr,index,largest);
		//当前指向父节点的index指向信道最大的子节点
		index = largest;
		//新的左孩子继续比较
		left = 2*index+1;
		
	}
}

堆排序:相当于选择排序,找最大值。时间复杂度O(N*logN)

在这里插入图片描述

在这里插入图片描述

堆结构远远比堆排序重要,优先级队列就是堆,只是换了一个称呼。

堆排序代码

	public static void heapSort(int[] arr)
	{
   
		if(arr == null || arr.length < 2)
		return;

		for(int i = 0; i < arr.length;i ++)
		heapInsert(arr,i);

		int heapSize = arr.length;
		swap(arr,0,--heapSize);//交换第一个与最后一个的value,因为第一个是最大值,然后heapsize-1才指向最后一个数字,所以要先--
		while(heapSize > 0{
   
			heapify(arr,0,heapSize);//将剩下的数据堆化,找到最大那个与其交换
			swap(arr,0,--heapSize);
		}
	}

## 标题

在这里插入图片描述

O(N*logk)

注意:系统给你提供的堆结构==>黑盒方法。沟通方式就是add添加,poll弹出,如下图。

但是黑盒方法不支持已经形成堆的东西,自己人为给 它变完之后,用很轻的代价重新调整为堆结构,不支持。自己手写的堆结构是支持的。有相应的需求,要自己手写堆来高效。非常重要!
在这里插入图片描述

在这里插入图片描述

package class02;

import java.util.PriorityQueue;

public class Code04_SortArrayDistanceLessK {
   

	public void sortedArrDistanceLessK(int[] arr, int k) {
   
//优先级队列,底层就是堆,默认整型小根堆,直接调用  
		PriorityQueue<Integer> heap = new PriorityQueue<>();//生成一个小根堆
		int index = 0;
		for (; index <= Math.min(arr.length, k); index++) {
   //把前k+1个数字放到小根堆里面去
			heap.add(arr[index]);
		}
		int i = 0;
		for (; index < arr.length; i++, index++) {
   
			heap.add(arr[index]);//新加一个数字放到小根堆里去
			arr[i] = heap.poll();//每次弹一个数放到i位置
		}
		while (!heap.isEmpty()) {
   //最后没有数字了,就把堆里的数一个个弹出放到位置上去
			arr[i++] = heap.poll();
		}
	}
}

堆排序+堆排序扩展题目全code

package class02;
import java.util.Arrays;
import java.util.PriorityQueue;

public class Code09_All_HeapSorted
{
   
	public static void heapsort(int[] arr)
	{
   
		if(arr == null || arr.length < 2) 
		return;
		int heapsize = arr.length;
		for(int i = 0; i < arr.length;i ++)
		{
   
			heapInsert(arr,i);
		}
		swap(arr,0,--heapsize);
	    while(heapsize > 0)
	    {
   
	  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值