《糊涂算法》之八大排序

文章8 |   阅读 3611 |   点赞0

《糊涂算法》之八大排序——堆排序

x33g5p2x  于2021-09-29 转载在 其他  
字(2.2k)|赞(0)|评价(0)|浏览(487)

待续>📚 八大排序算法合集——两万字,8张动图,450行代码。大厂面试必备。
🌲 配套源码地址:《八大排序》源码,提取码:5ehp

哈喽,大家好,我是一条~

今天给大家带来《糊涂算法》专栏的第二期内容——排序算法的讲解。相信无论是初学者学习还是大厂面试,都少不了排序算法这关,即使没学过算法,对冒泡排序也不会陌生。

今天,一条就带大家彻底跨过**「排序算法」这道坎,保姆级教程建议收藏**。⭐️

准备

古语云:“兵马未动,粮草先行”。想跟着一条一块把「排序算法」弄明白的,建议先准备好以下代码模板。

📢 观看本教程需知道基本循环语法两数交换双指针等前置知识。

📚 建议先看完代码逐步分析后再尝试自己写。

  • 新建一个Java工程,本文全篇也基于Java语言实现代码。
  • 建立如下目录结构

  • MainTest测试类中编写测试模板。
  1. /** * 测试类 * Author:一条 * Date:2021/09/23 */
  2. public class MainTest {
  3. public static void main(String[] args) {
  4. //待排序序列
  5. int[] array={6,10,4,5,2,8};
  6. //调用不同排序算法
  7. // BubbleSort.sort(array);
  8. // 创建有100000个随机数据的数组
  9. int[] costArray=new int[100000];
  10. for (int i = 0; i < 100000; i++) {
  11. // 生成一个[0,100000) 的一个数
  12. costArray[i] = (int) (Math.random() * 100000);
  13. }
  14. Date start = new Date();
  15. //过长,先注释掉逐步打印
  16. //BubbleSort.sort(costArray);
  17. Date end = new Date();
  18. System.out.println("耗时:"+(end.getTime()-start.getTime())/1000+"s");
  19. }
  20. }

该段代码内容主要有两个功能:

  • 调用不同的排序算法进行测试
  • 测试不同排序算法将10w个数排好序需要的时间。更加具象的理解时间复杂度的不同

堆排序

此章节对基础知识要求较高,初学者可跳过。

基本思想

堆排序是利用这种数据结构而设计的一种排序算法,堆排序是一种/*/选择排序,//*它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。

堆是具有以下性质的完全二叉树:

  • 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
  • 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

主要利用堆顶元素最大或最小的特性,通过不断构建大顶堆,交换堆顶和堆尾,断尾重构的方式实现排序。

动图讲解

代码实现

  1. public class HeapSort {
  2. public static void sort(int[] array) {
  3. //创建堆
  4. for (int i = (array.length - 1) / 2; i >= 0; i--) {
  5. //从第一个非叶子结点从下至上,从右至左调整结构
  6. adjustHeap(array, i, array.length);
  7. }
  8. //调整堆结构+交换堆顶元素与末尾元素
  9. for (int i = array.length - 1; i > 0; i--) {
  10. //将堆顶元素与末尾元素进行交换
  11. int temp = array[i];
  12. array[i] = array[0];
  13. array[0] = temp;
  14. //重新对堆进行调整
  15. adjustHeap(array, 0, i);
  16. }
  17. }
  18. /** * 调整堆 * @param array 待排序列 * @param parent 父节点 * @param length 待排序列尾元素索引 */
  19. private static void adjustHeap(int[] array, int parent, int length) {
  20. //将temp作为父节点
  21. int temp = array[parent];
  22. //左孩子
  23. int lChild = 2 * parent + 1;
  24. while (lChild < length) {
  25. //右孩子
  26. int rChild = lChild + 1;
  27. // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
  28. if (rChild < length && array[lChild] < array[rChild]) {
  29. lChild++;
  30. }
  31. // 如果父结点的值已经大于孩子结点的值,则直接结束
  32. if (temp >= array[lChild]) {
  33. break;
  34. }
  35. // 把孩子结点的值赋给父结点
  36. array[parent] = array[lChild];
  37. //选取孩子结点的左孩子结点,继续向下筛选
  38. parent = lChild;
  39. lChild = 2 * lChild + 1;
  40. }
  41. array[parent] = temp;
  42. System.out.println(Arrays.toString(array));
  43. }
  44. }

输出结果

逐步分析

  1. 构建初始堆,将待排序列构成一个大顶堆(或者小顶堆),升序大顶堆,降序小顶堆;
  2. 将堆顶元素与堆尾元素交换,并断开(从待排序列中移除)堆尾元素。
  3. 重新构建堆。
  4. 重复2~3,直到待排序列中只剩下一个元素(堆顶元素)。

耗时测试

算法优化

优化点关键就在于我们以什么手法找到顶部元素该有的位置,有兴趣同学可以继续研究。

点击查看更多排序算法

上一篇:计数排序
下一篇:归并排序

相关文章