js实现在一个全是整型的大数组中,找出最大的前10个数

这个题目原本是一个面试题,我写了三种用JS实现的方式,做个笔记,就当做是温习知识点吧!有别的实现方式欢迎评论。

先造五千条随机且不重复的假数据,代码如下:

js 复制代码
function genData() {
    const arr = [];
    while(arr.length < 5000) {
        const num = Math.floor(10000 * Math.random()) + 1;
        if (!arr.includes(num)) {
            arr.push(num);
        }
    }
    return arr;
}

一、数组的sort方法实现

利用数组提供的API:sortslice就可以非常快速的实现。这种方式很easy,就不过多赘述了,直接上代码。

js 复制代码
 function getTop10() {
    const list = genData();
    if (!list || list.length === 0) return [];
    
    // 使用sort配合reverse多此一举。
    // list.sort((a, b) => a - b).reverse();
    // const top10 = list.slice(0, 10);
    
    const top10 = list.sort((a, b) => b - a).slice(0, 10);
    return top10;
}

二、使用快排的方法实现

快速排序,这种排序方式在日常开发中很常见,为了巩固知识点,先来回顾一下快速排序的思想。

快速排序的排序过程只需要三步即可:

  1. 在要排序的数组中,找一个元素作为一个基准点;
  2. 准备两个空数组,将所有小于基准点的元素放在左边,所有大于基准点的元素放在右边;
  3. 重复上面两个步骤,递归执行完成,直到每个数组中只有一个元素为止;

为了实现标题中提到的功能,需要稍微改动一下,将大于基准元素的数据放在左边,将小于基准元素的数据放在右边,就能得到一个由大到小排序的数组了。

首先定义一个快排函数quickSort,函数接收一个数组作为参数,函数体内有以下逻辑:

  1. 先判断数组长度是否小于等于1,为真就直接返回;
  2. 找到基准点对应的元素,一般取数组总长度的中间值;
  3. 定义两个空数组,right存放大于基准元素的数据,left存放小于基准元素的数据;
  4. 遍历数组;
  5. 递归调用quickSort方法;
js 复制代码
function quickSort(arr) {
    if (arr.length <= 1) return arr;
    const piovtIndex = Math.floor(arr.length / 2);
    // 利用数组splice方法,将基准元素从数组中删除
    const piovt = arr.splice(piovtIndex, 1)[0];
    const left = [];
    const right = [];
    for(let i = 0, len = arr.length; i < len; i++) {
        if (arr[i] > piovt) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    // 递归调用quickSort方法
    return quickSort(left).concat([piovt], quickSort(right));
}      

通过上面的代码得到了一个由大到小排序的数组,而数组中最前面的十个元素就是我们想要的结果了。 具体代码如下:

js 复制代码
function findTop10() {
    const arr = quickSort(genData()); 
    console.log(arr)
    return arr.splice(0, 10);
}

效果截图:

三、使用小顶堆方式实现

注意:

小顶堆这种方式性能还算OK,空间复杂度低,不过IO读取非常频繁,对系统压力比较大,在写业务的时候,如若遇到需要处理超大型数据的时候,前端若要用此种方式来处理大数据,需要综合考虑,慎重慎重!

在实现最小堆之前,需要了解一些前置知识

  1. 什么是小顶堆?
    • 堆是一个完全二叉树
    • 堆上任意一个节点的值,都必须小于等于其左右两个子节点的值。(大顶堆正好相反)
    • 在小顶堆中,根节点是堆中最小的元素
  2. 用数组实现的小顶堆,每个节点中,它的父节点、左右子节点对应的位置是什么?
    • 小顶堆可以用一个数组表示,给定一个节点i,那么它的父节点一定为A(i/2),左子节点为A(2i),右子节点为A(2i+1)

放上一张图再配合上面的概念,理解起来会轻松些~

上面这张图来自于前端进阶算法9,想要了解更多关于堆的知识,可以看下这篇文章。

有了前面的知识铺垫后,接下来开始构想实现思路:

  1. 维护一个最小堆,这个堆最多包含10个元素(10个最大的数)
  2. 遍历数组中的每个元素,判断最小堆的长度,如果堆的长度不足10个:
    1. 就将当前元素作为插入元素,直接插入到最小堆中,同时将该元素与其父节点做比较,如果插入元素小于父节点,则插入元素与父节点交换位置,确保父节点总是小于子节点的。
  3. 如果最小堆的长度已满10个元素,则判断当前元素与最小堆的根节点进行比较:(在小顶堆中,根节点是堆中最小的元素)
    1. 当前元素比最小堆中的第一个元素大,把最小堆中的根节点替换掉。
    2. 进行下沉操作,即将当前元素放到合适的位置上面。
  4. 最终遍历完成后,最小堆中存放的10个数就是数组中最大的10个数。

代码示例:

js 复制代码
function findTopTen(array) {  
    if (!array || array.length === 0) {
        return [];
    }
    
    if (array.length <= 10) {
       return array.sort((a, b) => b - a);
    }
    // 创建一个最小堆,用于存储最大的10个数  
    const minHeap = new MinHeap(10);  

    // 遍历数组,将元素插入最小堆  
    for (let i = 0; i < array.length; i++) {  
        minHeap.insert(array[i]);  
    }  

    // 从最小堆中取出最大的10个数  
    const topTen = minHeap.extractTopTen();  

    return topTen;  
} 
// 最小堆类  
class MinHeap {  
    constructor(maxSize) {  
        this.heap = [];  
        this.maxSize = maxSize;  
    }  
  
    // 插入元素到堆中  
    insert(element) {  
        if (this.heap.length < this.maxSize) {  
            this.heap.push(element);  
            this.bubbleUp(this.heap.length - 1);  
        } else if (element > this.heap[0]) {  
            this.heap[0] = element;  
            this.sinkDown(0);  
        }  
    }  
  
    // 上浮操作,确保父节点小于子节点  
    bubbleUp(index) {  
        const parentIndex = Math.floor((index - 1) / 2);  
        if (index && this.heap[parentIndex] > this.heap[index]) {  
            this.swap(parentIndex, index);  
            this.bubbleUp(parentIndex);  
        }  
    }  
  
    // 下沉操作,确保父节点小于子节点  
    sinkDown(index) {  
        const length = this.heap.length;  
        let smallest = index;  
        const left = 2 * index + 1;  
        const right = 2 * index + 2;  
  
        if (left < length && this.heap[left] < this.heap[smallest]) {  
            smallest = left;  
        }  
  
        if (right < length && this.heap[right] < this.heap[smallest]) {  
            smallest = right;  
        }  
  
        if (smallest !== index) {  
            this.swap(index, smallest);  
            this.sinkDown(smallest);  
        }  
    }  
  
    // 交换堆中两个元素的位置  
    swap(i, j) {  
        [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];  
    }  
  
    // 提取堆中最大的10个数  
    extractTopTen() {  
        return this.heap.sort((a, b) => b - a).slice(0, 10);  
    }  
}

在上面的示例代码中,MinHeap 类维护了一个最小堆,最多包含10个元素。当插入一个新元素时,如果堆的大小还没有达到10,就直接插入并上浮;如果堆已满且新元素大于堆顶元素,就替换堆顶元素并下沉。最终,extractTopTen 方法将堆中的元素排序并返回前10个最大的数。

打印结果:

本文内容就是这些了,有不正确的地方欢迎掘友们纠正~

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
不二人生5 小时前
SQL面试题——连续出现次数
hive·sql·面试
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui