死磕算法之堆排序

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/80851024 学习更多算法系列请参考文章:死磕算法之汇总篇堆排序主要是运用了二叉树的性质来进行的排序。
版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/80851024


学习更多算法系列请参考文章:死磕算法之汇总篇


堆排序主要是运用了二叉树的性质来进行的排序。

在进行堆排序之前我们先了解一下二叉树的几个性质:

1.在排序使用二叉树的时候我们要排序的数组的第0个位置其实是不可以用的,这个时候如果我们要排序的数组为[3,1,0,2,8,4,2]时,我们首先要把它变为[0,3,1,0,2,8,4,2],我们把他转换为二叉树的时候是这样的

2.观察此二叉树我们可以发现几个公式:

  • 父节点个数:(数组长度-1)/2
  • 父节点索引为1到父节点个数
  • 子节点的索引:左儿子为父节点索引*2,右儿子为左儿子索引+1

3.我们进行堆排序的时候一般先从最后的节点开始,先比较最后的子节点,找出较大的子节点与父节点比较,如果子节点大于父节点则子节点与父节点交换。此流程大概是这样的

明白了上方的概念以后我们可以就可以进行简单的操作了:

  1. 由公式所知,我们父节点的索引个数等于父节点个数(等于(数组长度8-1)/2)3个,那么最后一个父节点的索引就是3.
  2. 有了父节点索引我们就可以得到他的左孩子和右孩子的索引分别为6和7
  3. 我们先假设左孩子是子节点最大的,然后判断一下右孩子是否存在,如果存在再比较左右孩子得出最小的孩子。
  4. 比较最小孩子和父节点。如果孩子节点大于父节点则交换。
  5. 索引为3的父节点比较完了接着比较索引为2的父节点。。然后是为1的。
  6. 现在整个树上最大的元素已经在跟节点了,那么我们就把跟节点与最后一个节点交换一下位置。
  7. 再次回到1开始比较,不过需要注意的这次我们要把数组最后一个忽略。

接下来上代码

public static void sort(int []arr,int length){
    if(length==1){
        return;
    }
   for (int i=(length-1)/2;i>=1;i--){
       int max=i*2;//先假设最大的子节点为左儿子
       if(max+1<length&&arr[max+1]>arr[max]){//如果右儿子不超出数组下标且比左儿子大
           max++;//最大的子节点为右儿子
       }
       if(arr[i]<arr[max]){ //如果子节点大于父节点
           swap(arr,i,max);//交换方法
       }
   }
    swap(arr,1,length-1);//将跟节点与数组最后一个节点交换
    sort(arr,length-1);//递归调用此方法,不过排序好的就不需要再次比较了,所以忽略它
}


public static void swap(int []arr,int a ,int b){
    int temp=arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}
public static void main(String []args){
    int []arr = {0,3,1,0,2,8,4,2};
    sort(arr,arr.length);
    System.out.println(Arrays.toString(arr));
}

堆排序讲完了。在这里温馨提示大家,学习算法时,我们没必要拘泥于代码的实现,那没有意义。我的建议就是深入理解步骤,当你理解步骤以后代码是随你怎么玩都可以的。


学习更多算法系列请参考文章:死磕算法之汇总篇


堆排序主要是运用了二叉树的性质来进行的排序。

在进行堆排序之前我们先了解一下二叉树的几个性质:

1.在排序使用二叉树的时候我们要排序的数组的第0个位置其实是不可以用的,这个时候如果我们要排序的数组为[3,1,0,2,8,4,2]时,我们首先要把它变为[0,3,1,0,2,8,4,2],我们把他转换为二叉树的时候是这样的

2.观察此二叉树我们可以发现几个公式:

  • 父节点个数:(数组长度-1)/2
  • 父节点索引为1到父节点个数
  • 子节点的索引:左儿子为父节点索引*2,右儿子为左儿子索引+1

3.我们进行堆排序的时候一般先从最后的节点开始,先比较最后的子节点,找出较大的子节点与父节点比较,如果子节点大于父节点则子节点与父节点交换。此流程大概是这样的

明白了上方的概念以后我们可以就可以进行简单的操作了:

  1. 由公式所知,我们父节点的索引个数等于父节点个数(等于(数组长度8-1)/2)3个,那么最后一个父节点的索引就是3.
  2. 有了父节点索引我们就可以得到他的左孩子和右孩子的索引分别为6和7
  3. 我们先假设左孩子是子节点最大的,然后判断一下右孩子是否存在,如果存在再比较左右孩子得出最小的孩子。
  4. 比较最小孩子和父节点。如果孩子节点大于父节点则交换。
  5. 索引为3的父节点比较完了接着比较索引为2的父节点。。然后是为1的。
  6. 现在整个树上最大的元素已经在跟节点了,那么我们就把跟节点与最后一个节点交换一下位置。
  7. 再次回到1开始比较,不过需要注意的这次我们要把数组最后一个忽略。

接下来上代码

public static void sort(int []arr,int length){
    if(length==1){
        return;
    }
   for (int i=(length-1)/2;i>=1;i--){
       int max=i*2;//先假设最大的子节点为左儿子
       if(max+1<length&&arr[max+1]>arr[max]){//如果右儿子不超出数组下标且比左儿子大
           max++;//最大的子节点为右儿子
       }
       if(arr[i]<arr[max]){ //如果子节点大于父节点
           swap(arr,i,max);//交换方法
       }
   }
    swap(arr,1,length-1);//将跟节点与数组最后一个节点交换
    sort(arr,length-1);//递归调用此方法,不过排序好的就不需要再次比较了,所以忽略它
}


public static void swap(int []arr,int a ,int b){
    int temp=arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}
public static void main(String []args){
    int []arr = {0,3,1,0,2,8,4,2};
    sort(arr,arr.length);
    System.out.println(Arrays.toString(arr));
}

堆排序讲完了。在这里温馨提示大家,学习算法时,我们没必要拘泥于代码的实现,那没有意义。我的建议就是深入理解步骤,当你理解步骤以后代码是随你怎么玩都可以的。


相关文章
|
9月前
|
算法 Python
数据结构算法--4堆排序
堆排序过程概述:建立大根堆,将堆顶最大元素移出并替换为末尾元素,调整保持堆性质,重复此过程直至堆为空,实现排序。时间复杂度为O(nlogn)。Python中可用heapq模块进行堆操作。
|
10月前
|
机器学习/深度学习 人工智能 算法
数据结构与算法:堆排序和TOP-K问题
朋友们大家好,本节内容来到堆的应用:堆排序和topk问题
数据结构与算法:堆排序和TOP-K问题
|
3天前
|
存储 搜索推荐 算法
算法系列之排序算法-堆排序
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它的时间复杂度为 $O(nlogn)$,并且是一种原地排序算法(即不需要额外的存储空间)。堆排序的核心思想是利用堆的性质来维护一个最大堆或最小堆,然后逐步将堆顶元素(最大值或最小值)取出,放到数组的末尾,最终得到一个有序的数组。
21 8
算法系列之排序算法-堆排序
|
10月前
|
移动开发 算法 前端开发
前端算法之堆排序
前端算法之堆排序
50 1
|
5月前
|
算法 搜索推荐
数据结构与算法学习十八:堆排序
这篇文章介绍了堆排序是一种通过构建堆数据结构来实现的高效排序算法,具有平均和最坏时间复杂度为O(nlogn)的特点。
109 0
数据结构与算法学习十八:堆排序
|
5月前
|
算法 搜索推荐
算法之堆排序
本文介绍了堆排序算法的原理和实现,通过构建最大堆或最小堆,利用堆的性质进行高效的排序,并提供了具体的编程实现细节和示例。
52 0
算法之堆排序
|
5月前
|
算法 Java Go
深入了解堆排序算法
深入了解堆排序算法
74 1
|
9月前
|
搜索推荐 算法 Java
Java中的快速排序、归并排序和堆排序是常见的排序算法。
【6月更文挑战第21天】Java中的快速排序、归并排序和堆排序是常见的排序算法。快速排序采用分治,以基准元素划分数组并递归排序;归并排序同样分治,先分割再合并有序子数组;堆排序通过构建堆来排序,保持堆性质并交换堆顶元素。每种算法各有优劣:快排平均高效,最坏O(n²);归并稳定O(n log n)但需额外空间;堆排序O(n log n)且原地排序,但不稳定。
67 3
|
9月前
|
搜索推荐 算法
【C/排序算法】:堆排序和选择排序
【C/排序算法】:堆排序和选择排序
49 0
|
9月前
|
存储 算法 C语言
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
51 0