高频面试题目

一、堆排序

1、基础知识

* ------基本知识:
* 1. 堆数据结构特征:
* 大顶堆:所有父节点大于等于左右子节点,arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2];
* 大顶堆:所有父节点小于等于左右子节点,arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2];
* 大顶堆只能保证顶元素时最大的,无法保证整个堆(数组)是有序的,小顶堆同理。
* 2. 索引规律:
* 最后一个非叶子节点:N/2-1;
* 父节点i,则左子节点2*i+1,右子节点2*i+2;
* 3. 堆与树的区别
* ①堆占用空间较少;
*   树结构需要存储左右节点指针,占用空间较多;堆仅使用数组;
* ②二叉搜索树与堆
*   二叉搜索树整体都是有序的,搜索很快(logN),插入或删除元素时需要保持平衡,复杂度会超过;
*   使用堆的主要目的是将最大值或最小值放在最前面,从而快速地进行插入和删除操作。
* -----------------------------------------------------------------
* 2021-02-22 17:20:20
* 堆排序的过程包括两部分(升序):构建大顶堆+交换元素调整堆;
* 其中核心操作就是adjustHeap;
* S1:构建大顶堆:从下往上遍历所有非叶子节点,调整堆;
* S2:构建大顶堆之后,保证顶元素最大,交换顶元素与末尾元素,再次调整堆(堆长度减1)。
* 关键方法:adjustHeap调整堆方法,adjustHeap(int[] arr, int rootIndex, int len).
* -----------------------------------------------------------------
* adjustHeap方法功能:
* 当前节点及之下的节点满足父节点大于等于左右子节点,但是改变了当前节点的值,
* 此时当前节点可能会小于左右子节点,因此需要将调整堆,使其再恢复大顶堆特征。
* adjustHeap方法思路:
* ①当前节点是叶子节点,即2*i+1>=len,则直接退出;
* ②找到左右子节点的较大者;
* ③若当前节点小于较大子节点,则交换;当前子节点值发生改变,则需要递归或循环执行①②。
*   若当前节点大于较大子节点,方法结束。
* -----------------------------------------------------------------
* 如何构建大顶堆或小顶堆(堆的初始化)?
* adjustHeap方法本来是在大顶堆已经建立的基础上,调整堆的,而大顶堆的初始化是通过从下而上,
* 对每一个非叶子节点都执行一次adjustHeap,因此后一次调用在前一次执行的基础之上,因此满足adjustHeap的条件,
* 最后是调整顶节点,因此最终完成大顶堆的初始化。
* 具体实现过程: 依次从最后一个非叶子节点向上遍历,进行调整;
* 假如节点个数为N,则最后一个非叶子节点序号为N/2-1,即N/2个非叶子节点,
* 也就是需要调用N/2次adjustHeap方法;从N/2-1到0.
* ------------------------------------------------------------------
* 升序采用大顶堆,降序采用小顶堆,为什么?
* 答:大顶堆的顶元素最大,将顶元素交换到末尾,满足升序;
*   小顶堆的顶元素最小,将顶元素交换到末尾,满足降序;
*   PS:保证堆的下标规律,因此将最大值或最小值转移到最后。
* ------------------------------------------------------------------
*  堆排时间复杂度分析:最好、最坏、平均都是N*logN;
*  仔细分析:堆排核心依赖都是adjustHeap方法,一次堆调整adjustHeap复杂度为O(logN),
*  构建大顶堆调用N/2次adjustHeap,复杂度为(N/2)logN=O(N*logN);
*  交换元素调整堆需要N-2次adjustHeap;因此堆排复杂度为O(N*logN);
*
* 堆排序
* Date:2018-11-09 22:35
* 堆排序的主要思想:
* 根据大顶堆的特点,堆的顶元素为整个堆的最大值,因此,首先就是构建大顶堆,
* 然后循环执行:将顶元素与有效堆的最后一个元素交换,再次调整堆;
* 注意:循环一次,堆的长度减1,因为堆顶元素移动最后,最后一个元素不参与下次堆的调整。
* adjustHeap方法功能:
* ------------------------------------------------------------------------
* 为什么最后一个叶子节点的序号肯定为N/2-1呢?
* 证明:因为堆是一个完全二叉树,父节点的编号为i,则左子节点为2*i+1,右子节点为2*i+2。
* 假设最后一个非叶子节点的编号为k,则其要么只有左子节点,要么左、右子节点都有。
* ①只有左子节点:左子节点编号为2*k+1,此时N=2*k+1+1;那么N/2-1 = k;
* ②左右子节点都存在:右子节点编号为2*k+2,此时N=2*k+2+1,那么N/2-1 = k;
* 综合①和②,N/2-1=k正好是最后一个非叶子节点的编号。
*/

类:HeapSort:

/*** 堆排序heapSort*/public void heapSort(int[] arr) {//1.构建大顶堆:从第一个非叶子结点从下至上调整堆结构int notLeaf = arr.length / 2 - 1;while (notLeaf >= 0) adjustHeap(arr, notLeaf--, arr.length);System.out.println("大顶堆初始化后:" + Arrays.toString(arr));//2.交换堆顶元素与末尾元素并调整堆结构for (int heapLen = arr.length; heapLen > 1; heapLen--) {swap(arr, 0, heapLen - 1);//将堆顶元素与末尾元素进行交换adjustHeap(arr, 0, heapLen - 1);//重新对堆进行调整}}
    /*** 使用场景及功能:顶节点值发生改变,不一定大于子节点,找到该顶节点值合适的位置,置入即可;* 步骤:* S1: 比较左右子节点,找到较大值;* S2: 将较大值填入root位置,并更新root值和index值;* S3: while循环执行S1、S2,直到遇到叶子节点(即左子节点下标大于等于len);* S4: 记得最后将rootVal设置到root位置上。*/public void adjustHeapMaxTop(int[] arr, int root, int len) {int index = root * 2 + 1;if (index >= len) return;int rootVal = arr[root];//根值while (index < len) {//找出左右子节点的最大值(避免交换两次)if (index + 1 < len && arr[index + 1] > arr[index]) index++;if (rootVal >= arr[index]) break;//根节点值大于等于子节点值,结束arr[root] = arr[index];//利用swap交换root和index也可以,不过有点冗余,index位置可能会多次覆盖root = index;index = index * 2 + 1;}arr[root] = rootVal;//若while循环中调用swap,则该操作可省略}
/*** 小顶堆*/public void adjustHeapMinTop(int[] arr, int root, int len) {int index = root * 2 + 1;if (index >= len) return;int rootVal = arr[root];//根值while (index < len) {//找出左右子节点的最大值(避免交换两次)if (index + 1 < len && arr[index + 1] < arr[index]) index++;if (rootVal <= arr[index]) break;//根节点值大于等于子节点值,结束arr[root] = arr[index];//利用swap交换root和index也可以,不过有点冗余,index位置可能会多次覆盖root = index;index = index * 2 + 1;}arr[root] = rootVal;//若while循环中调用swap,则该操作可省略}
/*** 递归方式*/public void adjustHeapMaxTopRecursive(int[] arr, int root, int len) {int index = root * 2 + 1;//左子节点if (index >= len) return;//找出左右子节点的最大值(避免交换两次)if (index + 1 < len && arr[index + 1] > arr[index]) index++;if (arr[root] >= arr[index]) return;//根节点值大于等于左右子节点值,结束swap(arr, root, index);//交换adjustHeapMaxTopRecursive(arr, index, len);}
 /*** 交换数组中的两个元素*/public void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
//测试@Testpublic void test() {int[] arr = {-2, 100, 9, 8, 7, 6, 11, 5, 4, 3, 2, 1};System.out.println("排序前:" + Arrays.toString(arr));heapSort(arr);//堆排System.out.println("排序后:" + Arrays.toString(arr));}

输出结果:

排序前:[-2, 100, 9, 8, 7, 6, 11, 5, 4, 3, 2, 1]
大顶堆初始化后:[100, 8, 11, 5, 7, 6, 9, -2, 4, 3, 2, 1]
排序后:[-2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 100]

二、找出最小的或最大的10个数

 /*** 从10亿个数中找出最小的或最大的10个数* 思路:找出最小的10个数* 采用大顶堆。* S1: 首先构建长度为10的大顶堆;* S2: 不断地从10亿个数据中读取,* 若大于等于顶元素,则丢弃;* 若小于顶元素,则替换顶元素,并调整堆adjustHeap。*/public int[] findMin10Nums(int[] arr) {if (arr == null || arr.length < 10) return Arrays.copyOf(arr, arr.length);//构建长度为10的大顶堆int[] res = Arrays.copyOf(arr, 10);int notLeaf = res.length / 2 - 1;while (notLeaf >= 0) adjustHeapForMaxTop(res, notLeaf--, res.length);//遍历读取每一个数值for (int j = 10; j < arr.length; j++) {if (arr[j] >= res[0]) continue;//大于顶元素(最大值)res[0] = arr[j];adjustHeapForMaxTop(res, 0, res.length);}return res;}/*** 与寻找最小10个数对应*/public int[] findMax10Nums(int[] arr) {if (arr == null || arr.length < 10) return Arrays.copyOf(arr, arr.length);//构建长度为10的大顶堆int[] res = Arrays.copyOf(arr, 10);int notLeaf = res.length / 2 - 1;while (notLeaf >= 0) adjustHeapForMinTop(res, notLeaf--, res.length);//遍历读取每一个数值for (int j = 10; j < arr.length; j++) {if (arr[j] <= res[0]) continue;//大于顶元素(最大值)res[0] = arr[j];adjustHeapForMinTop(res, 0, res.length);}return res;}//调整堆--复用堆排的adjustHeap方法(大顶堆)public void adjustHeapForMaxTop(int[] arr, int root, int len) {HeapSort heapSort = new HeapSort();heapSort.adjustHeapMaxTop(arr, root, len);}//调整堆--复用堆排的adjustHeap方法(小顶堆)public void adjustHeapForMinTop(int[] arr, int root, int len) {HeapSort heapSort = new HeapSort();heapSort.adjustHeapMinTop(arr, root, len);}/******************************测试******************************/@Testpublic void test() {int[] arr = {-2, 100, 9, -8, 7, 6, 11, 5, 4, 3, 2, 1, 32, 4, 56, 67, 44, 23, 54, 34, 23, 234, 65, 34, 1, 0, 5, 0, 6, -23, 1004, 1024, 8989};int[] min10Nums = findMin10Nums(arr);System.out.println("最小的10个数:" + Arrays.toString(min10Nums));int[] max10Nums = findMax10Nums(arr);System.out.println("最大的10个数:" + Arrays.toString(max10Nums));}

输出结果:

最小的10个数:[4, 3, 2, 0, -2, 1, 1, -8, 0, -23]
最大的10个数:[44, 54, 65, 56, 1004, 234, 1024, 67, 100, 8989]

堆排序及从10亿个数据中找出最小或最大的10个数相关推荐

  1. 如何在10亿个整数中找出前1000个最大的数?

    作者:vincent-duan,专注 Java,沉迷开源,架构师社区合伙人! 面试题目:如何在10亿个整数中找出前1000个最大的数. 我们知道排序算法有很多: 冒泡算法:通过两层for循环,外层第一 ...

  2. 如何在10亿个整数中找出前1000个最大的数(TopN算法)

    面试题目:如何在10亿个整数中找出前1000个最大的数. 我们知道排序算法有很多: 冒泡算法:通过两层for循环,外层第一次循环找到数组中最大的元素放置在倒数第一个位置,第二次循环找到第二大的元素放置 ...

  3. n个数里找出前m个数(或者 从10亿个浮点数中找出最大的1万个)

    转载自:http://blog.csdn.net/winsunxu/article/details/6219376点击打开链接 引子 每年十一月各大IT公司都不约而同.争后恐后地到各大高校进行全国巡回 ...

  4. 从10亿个数字中找出最大的前100个数

    先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的数(10000中最小的),将这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样,遍历完后,堆中的10000个数就是所需的最大的10000个 ...

  5. 一道笔试题:从1亿个整数中找出最大的一万个

    今天看到一篇赖永浩大牛的博客,由一道笔试题目谈算法优化.http://blog.csdn.net/lanphaday/archive/2008/12/19/3547776.aspx. 题目原题是从10 ...

  6. 大数据面试题——如何在大量的数据中找出不重复的数

    问题描述: 在2.5亿个整数中找出不重复的数,注意,内存不足以容纳2.5亿个整数. 分析解读: 方法一:分治法 采用hash的方法,把这2.5亿个数划分到更小的文件中,从而保证每个文件的大小不超过可用 ...

  7. 2.5亿个整数中找出不重复的整数

    问题描述:在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数. 思路:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共 ...

  8. PTA在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。

    在一大堆数据中找出重复的是一件经常要做的事情.现在,我们要处理许多整数,在这些整数中,可能存在重复的数据. 你要写一个程序来做这件事情,读入数据,检查是否有重复的数据.如果有,输出"YES& ...

  9. 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数

    方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受.然后扫描这2.5亿个整数 ...

最新文章

  1. Swift 3.0 预告:将 Objc 库转换成更符合 Swift 语法风格的形式
  2. JS实现上下左右对称的九九乘法表
  3. 【算法】图论学习笔记与代码实现
  4. SAP Spartacus home 页面的 cx-page-slot selector
  5. 审车按月还是日期_@老司机,你该审车了,秒懂的审车攻略,快快揣口袋吧
  6. JSON语法之JSON字符串
  7. 普通程序员,如何转型大数据相关方向?
  8. 信号与系统:综述【知识梳理】
  9. 形容谣言的四字词语_四字词语加解释大全
  10. 审稿意见的“so what”如何处理?
  11. AI轻松入门,AI零基础入门,AI初级教学,
  12. 【抓包】【Mac Charles】局域网无法抓包 手机热点来解决
  13. MPAndroidchart自定义样式二在柱状图上显示文本和间断式显示柱状图
  14. 上拉加载更多其他方法
  15. Excel中F4键的作用
  16. 《我在未来等你》的读书笔记和读后感作文2900字
  17. 在职场要避免这些“潜规则”
  18. 博途PLC和MATLAB矩阵运算存储方法对比
  19. 在职人员如何发表期刊论文
  20. java 下载速度_java下载速度慢啊!!

热门文章

  1. Mac 安装depot_tools
  2. 高斯消去、列主元消去、Lu分解、追赶法(matlab)
  3. 最近网络很火的支付宝 收款码 小议
  4. javascript scrollbar滚动条相关属性
  5. 软件测试,作为职场新鸟?我该怎么办?看看资深5年测试的见解......
  6. android go 联发科 p10,联发科P10和高通骁龙435哪个性能强?联发科P10对比高通骁龙435评测...
  7. python入门(中)
  8. 一文了解Anatha项目社区流动资金获取活动
  9. RabbitMQ实战
  10. 想精通 Python 数据挖掘?清华博士带你入门!