堆排序相关的数据结构知识:
- 满二叉树/完全二叉树的区别;
- 二叉堆与满足条件: 完全二叉树+任意父节点都大于/小于他的子节点;
- 大顶堆和小顶堆;
- 二叉树的先序,中序,后序遍历(根的先后顺序)
5.用数组构建二叉堆时, 数组就像是"物理结构的存储位置", 二叉堆则是逻辑结构.
具体在组织上, 知道父节点的位置下标是i, 左右子节点的下标是2i+1和2i+2; 知道了任意子节点下标n, 则父节点下标(n-1)/2----int类型除法
二叉树的三种遍历方法:
public class TreeAndArray {
/**
* 二叉堆,默认数组已经堆化,;
* 1.若i为父节点下标,二子节点:2i+1,2i+2;
* 2.若n为孩子节点,父节点: (n-1)/2 (int类型除法)
* @param arr
* @param index
*/
/*先序遍历*/
public static void preOrder(int[] arr, int index){ //其中,数组表示数据的“物理存储位置”,index是目前节点下标
if(index>=arr.length) //退出条件,index的子节点越界,说明index就是叶子结点
return;
System.out.print(arr[index] +" "); //出栈时的输出位置正好体现了遍历的名称
preOrder(arr,2*index+1);
preOrder(arr,2*index+2);
}
/*中序遍历*/
public static void inOrder(int[] arr, int index){
if(index>=arr.length)
return;
preOrder(arr,2*index+1);
System.out.println(arr[index]);
System.out.print(arr[index] +" ");
}
/*后序遍历*/
public static void laterOrder(int[] arr, int index){
if(index>=arr.length)
return;
preOrder(arr,2*index+1);
preOrder(arr,2*index+2);
System.out.print(arr[index] +" ");
}
public static void main(String[] args) {
int[] arg=new int[8];
for (int i = 0; i < arg.length; i++) {
arg[i]=(int)(Math.random()*20);
}
preOrder(arg,0);
}
}
堆排序代码与步骤----大顶堆
堆排序步骤:
* 1.纵向有序: 数组堆化,变成二叉堆
* 2.横向有序: 排序,每次都调换根节点和未排序范围内最后一个叶子结点(数组的首和尾),大小顶堆转换,数组变得有序
恰好分为三个递进的方法:maxHeapFixdown, maxHeapMaker, maxHeaSort
/**
* 堆排序步骤:
* 1.纵向有序: 数组堆化,变成二叉堆
* 2.横向有序: 排序,每次都调换根节点和未排序范围内最后一个叶子结点(数组的首和尾),大小顶堆转换,数组变得有序
*/
public class MaxHeapSort {
//step0: maxHeapFixdown,某节点的大/小顶堆调整方法(这里是大顶堆),基础
public static void maxHeapFixdown(int[] arr, int index, int range){ //range控制树的数量大小
//找到子树根节点俩子节点
int left = 2*index+1;
int right = 2*index+2;
//1.判断子节点是否越界,结束条件; 2.找到最大子节点;
int max;
if (left>=range)
return;
if (right>=range)
max=left;
else{
if (arr[left]>arr[right]){
max=left;
}else
max=right;
}
//父节点比较是否交换
if (arr[max]<=arr[index])
return;
//若是交换,则递归向下调整交换子节点子树
int temp=arr[index];
arr[index]=arr[max];
arr[max]=temp;
maxHeapFixdown(arr,max,range);
}
/*step1: maxHeapMaker,堆化数组(这里是大顶堆),使得二叉堆成立(纵向有序,横向待定)*/
public static void maxHeapMaker(int[] arr){
//从倒数第二层,一层层地向上调整顶堆
for (int x=arr.length/2-1; x>=0;x--){
maxHeapFixdown(arr, x,arr.length);
}
}
/*step2: maxHeapSort,反转二叉堆(大顶堆<->小顶堆),使得"物理数组"有序*/
public static void maxHeapSort(int[] arr){
//堆化数组
maxHeapMaker(arr);
//对换二叉堆根节点与最后未排序的节点(根节点是最大值/最小值,相当于将最大/小值顶到数组末尾)
for (int i=arr.length-1; i>0; i--){
util.util.swap(arr,i,0);
maxHeapFixdown(arr,0,i-1);
}
//缩小树范围,并调整新根节点的二叉堆(这样不断调换,不断缩小二叉堆,不断向下调整新二叉堆,最终大小顶堆调换,)
}
public static void main(String[] args) {
int[] arg=new int[8];
for (int i = 0; i < arg.length; i++) {
arg[i]=(int)(Math.random()*20);
}
maxHeapSort(arg);
System.out.println(Arrays.toString(arg));
}
}
二叉堆及堆排序的实际应用:top K个数
问题:求一个给定乱序数组中的前k个数据 / 或者是键盘输入n个数,输入-1结束,输出topk个数(不用排序,要的话Arrays.sort() )
应用:排行榜前K个玩家的查找
解决思路:在这k数里,若是下一个数值大于其中的最小值,那么就替换掉它,重新选出新K个数里最小的那个。(这里没要求排序,要的话topk数组Arrays.sort())
* 1.堆排序与二叉堆: 创建一个topK的辅助数组,每次都用小顶堆选出最小值,
只要有新数据大于这个最小值,替换,调整使新的最小值浮上来
* 2. partition+二分: 类似快速排序那样分区(左大右小), 找到mid==k-1后, 输出前K位这里恰好可以联想到“小顶堆”的向下调整maxHeapFixdown方法:每次比较处于根节点处的最小值,大于他了,就替换掉,然后向下调整使其最小值浮上来。
具体步骤:
- 创建topK数组,将前K个数放进去
- 堆化数组
- 遍历,然后和根节点最小值做比较
- 小于,则替换,maxHeapFixdown调整
- 重复3,4步骤
- 结束,输出topK数组
/** 求乱序数组中的前top K个最大数 / 或者是键盘输入n个数,输入-1结束,输出topk个数
* 解题思路:
* 1.堆排序与二叉堆: 创建一个topK的辅助数组,每次都用小顶堆选出最小值,
* 只要有新数据大于这个最小值,替换,调整使新的最小值浮上来
* 2. partition+二分: 分区,找到mid=topk后,若是需要排序,则输出排好序的前K位
*/
public class Heep_topK个数_B站 {
static int[] topK(int[] arr){
//top数组
int[] top= Arrays.copyOfRange(arr,0,10);
//堆化top数组
minHeapMaker(top);
//遍历比较最小值,小就替换掉,并且重新调整小顶堆
for (int i = 10; i < arr.length; i++) {
if (arr[i]>top[0])
top[0]=arr[i];
minHeapFixdown(top,0);
}
return top;
}
public static void minHeapMaker(int[] arr){
//从倒数第二层,一层层地向上调整顶堆
for (int x=arr.length/2-1; x>=0;x--){
minHeapFixdown(arr, x);
}
}
/*知道父节点i求子节点:2i+1,2i+2 */
static void minHeapFixdown(int[] arr,int father){
int left=father*2+1;
int right=father*+2;
int minOfKid;
//左结点过节
if (left>arr.length-1)
return;
//右节点越界
minOfKid=left; //找到小的子节点,这是种节约辅助空间的写法,不用temp了
if (right>arr.length-1)
minOfKid=left;
else if (arr[left]>arr[right])
minOfKid=right;
//比较,若比最小子节点还小,交换,向下调整替换了的子树
if (arr[father]>arr[minOfKid]){
int temp=arr[minOfKid];
arr[minOfKid]=arr[father];
arr[father]=temp;
minHeapFixdown(arr,minOfKid);
}
else return;
}
public static void main(String[] args) {
int[] arg ={-1513,2,3,7,5,6,-12,4,3,9,110,-2,-1,-2,-7};
int[] temp=topK(arg);
System.out.println(Arrays.toString(temp));
int[] arg02=new int[20];
for (int i = 0; i < arg.length; i++) {
arg02[i]=(int)(Math.random()*50);
}
System.out.println(Arrays.toString(topK(arg02)));
}