【面试知识点】史上最全面讲解----堆排序

简介: 【面试知识点】史上最全面讲解----堆排序

堆排序的过程

 

堆父节点和子节点

 

  1. parent(3) = (i - 1) / 2;
  2. c1(5) = 2 * i + 1;
  3. c2(6) = 2 * i + 2;

 

建立大顶推和小顶推

 

建堆的过程,我们需要知道一个函数heapify()【这里的heapify不代表最终版本】

 

public static void heapify(int[] tree, int n, int i) {
            if (i >= n) {
      return;
    }
    int max = i;
    int c1 = 2 * i + 1;
    int c2 = 2 * i + 2;
    if (c1 < n && tree[c1] > tree[max]) {
      max = c1;
    }
    if (c2 < n && tree[c2] > tree[max]) {
      max = c2;
    }
    if (max != i) {
      duiSwap(tree, max, i);
    }
  }

 

 

这个函数用来进行3、5、6中,将最大的数与3交换

 

 

 

我们对于每一个结点利用heapify,这样,我们是否就得到了一个完整的堆?

我们往下看看,当3与6交换完后,我们再对结点2进行heapify(),2与7进行交换,然后对结点4进行heapify,6与4进行交换,最后1与7交换,我们看看最后的结果

我们考虑下,关于堆的定义:是一个完全二叉树、父节点全部大于等于或者全部小于等于子节点

我们看下图,可以看出明明5和3是4的子节点,为什么4还小于6呢?

同理,5和2也是1的子节点,为什么1还小于5呢?

 

这说明了我们对于堆的建立出现了错误,难道是我们的heapify出现了错误,我们从头开始分析一下:

首先,当我们将3和6进行交换时,这时候我们仅仅改变的是3-5-6之间的关系,也就是合理的,继而我们以2为父节点,改变2-5-7之间的关系,也是合理的,

当我们对以节点4进行heapify时,我们会将6和4的位置进行调换

这时候,聪明的你有没有看出什么错误导致的我们的建堆错误?

答案是:当我们对结点4进行heapify时,将4转变至子节点,破坏了下面这个小堆

也就是,对于交换后,我们原来排序好的堆,就失去了稳定性,有什么办法能让我们原来排序的堆也是顺序的嘛?

聪明的你可能想到了,我们再一次进行heapify不就可以了,对,我们只需要对交换完之后的节点再一次使用heapify,也就是对于上图中进行heapify,得到如下

按照上面的想法,我们对节点1再一次进行heapify

这时候聪明的你,能不能想到我们的heapify少了点什么?

对,我们一开始的heapify少了对改变的子节点进行heapify,我们怎么实现呢?

这里只需要递归就可以了,也就是对改变的子节点进行heapify

 

public static void heapify(int[] tree, int n, int i) {
    if (i >= n) {
      return;
    }
    int max = i;
    int c1 = 2 * i + 1;
    int c2 = 2 * i + 2;
    if (c1 < n && tree[c1] > tree[max]) {
      max = c1;
    }
    if (c2 < n && tree[c2] > tree[max]) {
      max = c2;
    }
    if (max != i) {
      duiSwap(tree, max, i);
      heapify(tree, n, max);
    }
  }

 

这时候我们的堆就建好了,我们可以进行下一步操作,堆排序

 

进行堆排序

 

对于堆排序,我们使用方法是:

每次将root与末尾的进行交换,然后对root进行heapify

我们看一下图示:

依次进行这种操作,我们最后得到的数组就是从小到大排序好的

 

 

注意:我们进行堆排序的时候,我们每次重新对节点使用heapify时,我们已经排序好了一个7,所以下一次进行heapify时,n(也就是heapify的范围)就可以直接除去一个7,后面也是这样

 

 

源代码

 

public static void duiSwap(int[] tree, int i, int j) {
    int x = tree[i];
    tree[i] = tree[j];
    tree[j] = x;
  }
  public static void heapify(int[] tree, int n, int i) {
            if (i >= n) {
      return;
    }
    int max = i;
    int c1 = 2 * i + 1;
    int c2 = 2 * i + 2;
    if (c1 < n && tree[c1] > tree[max]) {
      max = c1;
    }
    if (c2 < n && tree[c2] > tree[max]) {
      max = c2;
    }
    if (max != i) {
      duiSwap(tree, max, i);
      heapify(tree, n, max);
    }
  }
  public static void bulidDui(int[] tree, int n) {
    int last = n - 1;
    int parent = (last - 1) / 2;
    for (int i = parent; i >= 0; i--) {
      heapify(tree, n, i);
    }
  }
  public static void duiSort(int[] tree, int n) {
    bulidDui(tree, n);
    for (int i = n - 1; i >= 0; i--) {
      duiSwap(tree, i, 0);
      heapify(tree, i, 0);
    }
  }
  public static void main(String[] args) {
    int[] tree = new int[] { 2, 5, 3, 1, 10 };
    int n = tree.length;
    duiSort(tree, n);
    for (int i = 0; i < n; i++) {
      System.out.println(tree[i]);
    }
  }

 

相关文章
|
2月前
|
Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
2月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
5月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
76 0
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
2月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
31 3
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
29 2
|
2月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
58 1
|
2月前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
Android面试高频知识点(1) 图解 Android 事件分发机制
45 1
|
3月前
|
Web App开发 前端开发 Linux
「offer来了」浅谈前端面试中开发环境常考知识点
该文章归纳了前端开发环境中常见的面试知识点,特别是围绕Git的使用进行了详细介绍,包括Git的基本概念、常用命令以及在团队协作中的最佳实践,同时还涉及了Chrome调试工具和Linux命令行的基础操作。
「offer来了」浅谈前端面试中开发环境常考知识点
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制

热门文章

最新文章