对排序算法的研究

算法是什么?、

算法(Algorithm) 代表着用系统的方法描述解决问题的策略机制,可以通过一定规范的 输入,在有限时间内获得所需要的 输出

一个算法的好坏是通过 时间复杂度 与 空间复杂度 来衡量的。

简单来说,时间复杂度 就是执行算法的 时间成本 ,空间复杂度 则是执行算法的 空间成本 。

时间复杂度 与 空间复杂度 都是用 “大O” 来表示,写作 O(*)。有一点值得注意的是,我们谈论复杂度,一般谈论的都是时间复杂度。

常见时间复杂度的 “大O表示法” 描述有以下几种:

时间复杂度非正式术语
O(1)常数阶
O(n)线性阶
O(n2)平方阶
O(log n)对数阶
O(n log n)线性对数阶
O(n3)立方阶
O(2n)指数阶

一个算法在N规模下所消耗的时间消耗从大到小如下:

O(1) < O(log n) < O(n) < O(n log n) < O(n2) < O(n3) < O(2n)

常见的排序算法

1.O(n²) 的排序算法

  • 冒泡排序

  • 选择排序

  • 插入排序

  • 希尔排序

2.O(n log n) 的排序算法

  • 归并排序

  • 快速排序

  • 堆排序

3.线性的排序算法

  • 计数排序

  • 桶排序

  • 基数排序

冒泡排序

冒泡排序之所以叫冒泡排序,是因为它每一种元素都像小气泡一样根据自身大小一点一点往数组的一侧移动。

算法步骤如下:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个;

  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数;

  3. 针对所有的元素重复以上的步骤,除了最后一个;

  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

const bubbleSort = arr => {
    const len = arr.length - 1
    for (let i = 0; i < len; ++i) { /* 外循环为排序趟数,len个数进行len-1趟 */
        for (let j = 0; j < len - i; ++j) { /* 内循环为每趟比较的次数,第i趟比较len-i次 */
            if (arr[j] > arr[j + 1]) { /* 相邻元素比较,若逆序则交换(升序为左大于右,逆序反之) */
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
            }
        }
    }
    return arr
}

选择排序(Selection sort) 是一种简单直观的排序算法。

选择排序的主要优点与数据移动有关。

如果某个元素位于正确的最终位置上,则它不会被移动。

选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对 n 个元素的表进行排序总共进行至多 n - 1 次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

选择排序的算法步骤如下:

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;

  2. 然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;

  3. 以此类推,直到所有元素均排序完毕。

代码实现:

    const selectionSort = arr => {
    const len = arr.length
    let min
    for (let i = 0; i < len - 1; ++i) {
        min = i /* 初始化未排序序列中最小数据数组下标 */
        for (let j = i + 1; j < len; ++j) { /* 访问未排序的元素 */
            if (arr[j] < arr[min]) { /* 找到目前最小值 */
                min = j /* 记录最小值 */
            }
        }
        [arr[i], arr[min]] = [arr[min], arr[i]] /* 交换位置 */
    }
    return arr
}

插入排序

插入排序(Selection sort) 是一种简单直观的排序算法。

它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

插入排序的算法步骤如下:

  1. 从第一个元素开始,该元素可以认为已经被排序;

  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;

  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;

  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

  5. 将新元素插入到该位置后;

  6. 重复步骤2~5。

const insertionSort = arr => {
    const len = arr.length
    let j, temp
    for (let i = 0; i < len; ++i) {
        j = i /* 存储当前索引,便于后续与数组其他元素对比 */
        while (j > 0 && arr[j - 1] > temp) {
            arr[j] = arr[j - 1]
            j--
        }
        [arr[j], arr[i]] = [arr[i], arr[i]]
    }
    return arr
}

希尔排序

希尔排序,也称 递减增量排序算法,是 插入排序 的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到 线性排序 的效率;

  2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

步长的选择是希尔排序的重要部分。

只要最终步长为1任何步长序列都可以工作。

算法最开始以一定的步长进行排序。

然后会继续以一定步长进行排序,最终算法以步长为1进行排序。

当步长为1时,算法变为普通插入排序,这就保证了数据一定会被排序。

插入排序的算法步骤如下:

  1. 定义一个用来分割的步长;

  2. 按步长的长度K,对数组进行K趟排序;

  3. 不断重复上述步骤。

const shellSort = arr => {
    let gaps = [5, 3, 1] // 定义步长以及分割次数
    let len = arr.length
    for (let g = 0, gLen = gaps.length; g < gaps.length; ++g) {
        for (let i = gaps[g]; i < len; ++i) {
            let j
            for (j = i; j >= gaps[g] && arr[j - gaps[g]] > arr[i]; j -= gaps[g]) {
                arr[j] = arr[j - gaps[g]]
            }
            [arr[i], arr[j]] = [arr[j], arr[i]]
        }
    }
    return arr
}

快速排序

快速排序(Quicksort),又称 划分交换排序(partition-exchange sort) 。

快速排序(Quicksort) 在平均状况下,排序 n 个项目要 O(n log n) 次比较。在最坏状况下则需要 O(n2) 次比较,但这种状况并不常见。事实上,快速排序 O(n log n) 通常明显比其他算法更快,因为它的 内部循环(inner loop) 可以在大部分的架构上很有效率地达成。

快速排序使用 分治法(Divide and conquer) 策略来把一个序列分为较小和较大的2个子序列,然后递归地排序两个子序列。

快速排序的算法步骤如下:

  1. 挑选基准值:从数列中挑出一个元素,称为 “基准”(pivot) ;

  2. 分割:重新排序序列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成;

  3. 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。

递归到最底部的判断条件是序列的大小是零或一,此时该数列显然已经有序。

选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。

const quickSort = arr => {
    const len = arr.length
    if (len < 2) {
        return arr
    }
    const pivot = arr[0]
    const left = []
    const right = []
    for (let i = 1; i < len; ++i) {
        if (arr[i] >= pivot) {
            right.push(arr[i])
        }
        if (arr[i] < pivot) {
            left.push(arr[i])
        }
    }
    return [...quickSort(left), pivot, ...quickSort(right)]
}

三路快排

const quickSort = arr => {
    const len = arr.length
    if (len < 2) {
        return arr
    }
    let left = []
    let center = []
    let right = []
    let pivot = arr[0]
    for (let i = 0; i < len; ++i) {      
        if (arr[i] < pivot) {
            left.push(arr[i])
        } else if (arr[i] === pivot) {
            center.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return [...quickSort(left), ...center, ...quickSort(right)]
}

归并排序

第一种是 自上而下的递归 ,算法步骤如下:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;

  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

  4. 重复步骤3直到某一指针到达序列尾;

  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

具体实现:

 

 

 

 

 

 

 

 

 

 

const merge = (left, right) => {
    let resArr = []
    while (left.length && right.length) {
        if (left[0] < right[0]) {
            resArr.push(left.shift())
        } else {
            resArr.push(right.shift())
        }
    }
    return resArr.concat(left, right)
}

const mergeSort = arr => {
    if (arr.length <= 1) {
        return arr
    }
    let middle = Math.floor(arr.length / 2)
    let left = arr.slice(0, middle)
    let right = arr.slice(middle)
    return merge(mergeSort(left), mergeSort(right))
}

自下而上的迭代 ,由于 分治法 的具体算法基本都能用 递归 跟 迭代 来实现,所有才有这种写法,其主要步骤如下:

  1. 将序列每相邻两个数字进行 归并操作 ,形成 ceil(n / 2) 个序列,排序后每个序列包含两/一个元素;

  2. 若此时序列数不是1个则将上述序列再次归并,形成 ceil(n / 4)  个序列,每个序列包含四/三个元素;

  3. 重复步骤2,直到所有元素排序完毕,即序列数为1。

具体实现如下:

const merge = (arr, startLeft, stopLeft, startRight, stopRight) => {
    /* 建立左右子序列 */
    let rightArr = new Array(stopRight - startRight + 1)
    let leftArr = new Array(stopLeft - startLeft + 1)
    /* 给左右序列排序 */
    let k = startRight
    for (let i = 0, len = rightArr.length; i < len - 1; ++i) {
        rightArr[i] = arr[k]
        ++k
    }
    k = startLeft
    for (let i = 0, len = leftArr.length; i < len - 1; ++i) {
        leftArr[i] = arr[k]
        ++k
    }
    //设置哨兵值,当左子列或右子列读取到最后一位时,即Infinity,可以让另一个剩下的列中的值直接插入到数组中
    rightArr[rightArr.length - 1] = Infinity
    leftArr[leftArr.length - 1] = Infinity
    let m = 0
    let n = 0
    // 比较左子列和右子列第一个值的大小,小的先填入数组,接着再进行比较
    for (let c = startLeft; c < stopRight; ++c) {
        if (leftArr[m] <= rightArr[n]) {
            arr[c] = leftArr[m]
            m++
        } else {
            arr[c] = rightArr[n]
            n++
        }
    }
}
const mergeSort = arr => {
    if (arr.length <= 1) {
        return arr
    }
    //设置子序列的大小
    let step = 1
    let left
    let right
    while (step < arr.length) {
        left = 0
        right = step
        while (right + step <= arr.length) {
            merge(arr, left, left + step, right, right + step)
            left = right + step
            right = left + step
        }
        if (right < arr.length) {
            merge(arr, left, left + step, right, arr.length)
        }
        step *= 2
    }
    return arr
}

鱼头注:迭代比起递归还是安全很多,太深的递归容易导致堆栈溢出。

堆排序

堆排序的算法步骤如下:

  1. 把无序数列构建成二叉堆;

  2. 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶。

/* 堆下沉调整 */
const adjustHeap = (arr, parentIndex, length) => {
    let temp = arr[parentIndex] /* temp保存父节点值,用于最后赋值 */
    let childIndex = 2 * parentIndex + 1 /* 保存子节点位置 */
    while (childIndex < length) {
        /* 如果有右子节点,且右子节点大于左子节点的值,则定位到右子节点 */
        if (childIndex + 1 < length && arr[childIndex + 1] > arr[childIndex]) {
            childIndex++
        }
        /* 如果父节点小于任何一个子节点的值,直接退出循环 */
        if (temp >= arr[childIndex]) {
            break;
        }
        /* 无序交换,单向赋值即可 */
        arr[parentIndex] = arr[childIndex]
        parentIndex = childIndex
        childIndex = 2 * childIndex + 1
    }
    arr[parentIndex] = temp
}
const heapSort = arr => {
    /* 把无序数列构建成最大堆 */
    for (let i = Math.floor(arr.length / 2); i >= 0; --i) {
        adjustHeap(arr, i, arr.length - 1)
    }
    for (let i = arr.length - 1; i > 0; --i) {
        /* 交换最后一个元素与第一个元素 */
        [arr[i], arr[0]] = [arr[0], arr[i]]
        /* 调整最大堆 */
        adjustHeap(arr, 0, i)
    }
    return arr
}

计数排序

计数排序(Counting sort) 是一种稳定的线性时间排序算法。该算法于1954年由 Harold H. Seward 提出。计数排序使用一个额外的数组来存储输入的元素,计数排序要求输入的数据必须是有确定范围的整数。

当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 O(n + k) 。计数排序不是比较排序,排序的速度快于任何比较排序算法。

计数排序的算法步骤如下:

  1. 找出待排序的数组中最大和最小的元素;

  2. 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;

  3. 对所有的计数累加(从数组 C 中的第一个元素开始,每一项和前一项相加);

  4. 反向填充目标数组:将每个元素 i 放在新数组的第 C[i] 项,每放一个元素就将 C[i] 减去1

具体实现如下:

const countSort = arr => {
    const C = []
    for (let i = 0, iLen = arr.length; i < iLen; ++i) {
        const j = arr[i]
        if (C[j] >= 1) {
            C[j]++
        } else {
            C[j] = 1
        }
    }
    const D = []
    for (let j = 0, jLen = C.length; j < jLen; ++j) {
        if (C[j]) {
            while (C[j] > 0) {
                D.push(j)
                C[j]--
            }
        }
    }
    return D
}

桶排序(Bucket Sort) 跟 计数排序(Counting sort) 一样是一种稳定的线性时间排序算法,不过这次需要的辅助不是计数,而是桶。

工作的原理是将数列分到有限数量的桶里。每个桶再个别排序。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间 O(n)

桶排序的算法步骤如下:

  1. 设置一个定量的数组当作空桶子;

  2. 寻访序列,并且把项目一个一个放到对应的桶子去;

  3. 对每个不是空的桶子进行排序;

  4. 从不是空的桶子里把项目再放回原来的序列中。

const bucketSort = arr => {
    let bucketsCount = 10 /* 默认桶的数量 */
    const max = Math.max(...arr) /* 序列最大数字 */
    const min = Math.min(...arr) /* 数列最小数字 */
    const bucketsSize = Math.floor((max - min) / bucketsCount) + 1 /* 桶的深度 */
    const __buckets = [] /* 空桶 */
    for (let i = 0, len = arr.length; i < len; ++i) {
        const index = ~~(arr[i] / bucketsSize) /* 骚操作,取数列中最大或最小的序列 */
        if (!__buckets[index]) {
            __buckets[index] = [] /* 创建子桶 */
        }
        __buckets[index].push(arr[i])
        let bLen = __buckets[index].length
        while (bLen > 0) { /* 子桶排序 */
            if (__buckets[index][bLen] < __buckets[index][bLen - 1]) {
                [__buckets[index][bLen], __buckets[index][bLen - 1]] = [__buckets[index][bLen - 1], __buckets[index][bLen]]
            }
            bLen--
        }
    }
    let buckets = [] /* 真实序列 */
    for (let i = 0, len = __buckets.length; i < len; ++i) {
        if (__buckets[i]) {
            buckets.push(...__buckets[i])
        }
    }
    return buckets
}

基数排序

基数排序(Radix sort) 是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

工作原理是将所有待比较数值(正整数)统一为同样的数字长度,数字较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

const LSDRadixSort = arr => {
    const max = Math.max(...arr) /* 获取最大值 */
    let digit = `${max}`.length /* 获取最大值位数 */
    let start = 1 /* 桶编号 */
    let buckets = [] /* 空桶 */
    while (digit > 0) {
        start *= 10
        /* 入桶 */
        for (let i = 0, len = arr.length; i < len; ++i) {
            const index = (arr[i] % start)
            if (!buckets[index]) {
                buckets[index] = []
            }
            buckets[index].push(arr[i]) /* 往不同桶里添加数据 */
        }
        arr = []
        /* 出桶 */
        for(let i = 0; i < buckets.length; i++) {
            if (buckets[i]) {
                arr = arr.concat(buckets[i])
            }
        }
        buckets = []
        digit --
    }
    return arr
}

鸡尾酒排序,是 冒泡排序 的一种变形。此算法与 冒泡排序 不同的地方在于从低到高然后从高到低,而 冒泡排序 则仅从低到高去比较序列里的每个元素。它可以得到比 冒泡排序 稍微好一点的性能,原因是 冒泡排序 只从一个方向进行比对(由低到高),每次循环只移动一个项目。

步骤跟冒泡算法差不多,区别在于从起点到终点遍历完之后会进行一次终点到起点的遍历。

const cocktailSort = arr => {
    let i
    let left = 0
    let right = arr.length - 1
    while (left < right) {
        for (i = left; i < right; ++i)
            if (arr[i] > arr[i + 1]) {
                [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
            }
        right--
        for (i = right; i > left; --i)
            if (arr[i - 1] > arr[i]) {
                [arr[i], arr[i - 1]] = [arr[i - 1], arr[i]]
            }
        left++
    }
    return arr
}

 

转载于:https://www.cnblogs.com/zhouyideboke/p/11164024.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js实用算法

判断文本是否为回文 定义&#xff1a;如果将一个文本翻转过来&#xff0c;能和原文本完全相等&#xff0c;那么就可以称之为“回文”。 方法一&#xff08;字符串、数组内置方法&#xff09;123456789101112131415/** 判断文字是否为回文* param {string|number} val 需要判断的…

stylus

stylus格式 指将css中{} &#xff1b;去掉即可

随笔记录(2019.7.10)

1、ISO/OSI 网络七层参考模型 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 2、 TCP/IP 网络四层模型和五层模型 四层模型&#xff1a; 网络接口层 网络层 传输层 应用层 五层模型&#xff1a; 物理层 数据链路层 网络层 传输层 应用层 3、 协议簇 &#xff08;1&a…

转发:Ajax动态画EChart图表

本人由于项目需要&#xff0c;在状态变化的时候需要动态绘制对应数据的EChart图表&#xff0c;并且不刷新整个网页。 所以就用Ajax动态画EChart图表&#xff0c;下面是开发过程中遇到的一些坑的总结。 流程&#xff1a;页面首次加载时展示一幅原始的图形&#xff0c;若后台数据…

如果硬盘不显示可以这么处理

http://www.zhuangjiba.com/soft/9574.html转载于:https://www.cnblogs.com/braveheart007/p/11167311.html

Highcharts的饼图大小的控制

在Highcharts中&#xff0c;饼图的大小是Highcharts自动计算并进行绘制。饼图的大小受数据标签大小、数据标签到切片的距离影响。当数据标签内容较多&#xff0c;并且距离切片较远时&#xff0c;饼图就会被压缩的很小。解决这个问题&#xff0c;有以下几种方法&#xff1a;&…

转:谷歌离线地图基础

一.需要文件 gapi3文件夹&#xff1a;存放接口等tilemap文件夹&#xff1a;存放图片gapi.js文件maptool.js文件 二.html配置 <script type"text/javascript" src"gapi.js"></script> <script type"text/javascript" src"map…

HTTP Header 详解

搜集资料 HTTP&#xff08;HyperTextTransferProtocol&#xff09;即超文本传输协议&#xff0c;目前网页传输的的通用协议。HTTP协议采用了请求/响应模型&#xff0c;浏览器或其他客户端发出请求&#xff0c;服务器给与响应。就整个网络资源传输而言&#xff0c;包括message-h…

Windows CE 6.0中断处理过程(转载)

这里我们主要讨论的是CE的中断建立和中断相应的大概流程以及所涉及的代码位置。这里所讲述的&#xff0c;是针对ARM平台的。在CE的中断处理里面&#xff0c;有一部分工作是CE Kernel完成的&#xff0c;有一部分工作是要由OEM完成的。 Kernel代码工作 ExVector.s&#xff1a;中断…

document.createDocumentFragment 以及创建节点速度比较

document.createDocumentFragment document.createDocumentFragment()方法创建一个新空白的DocumentFragment对象。 DocumentFragments是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段&#xff0c;将元素附加到文档片段&#xff0c;然后将文档片段附加到DOM树。…

Javascript重温OOP之原型与原型链

prototype原型对象 每个函数都有一个默认的prototype属性&#xff0c;其实际上还是一个对象&#xff0c;如果被用在继承中&#xff0c;姑且叫做原型对象。 在构造函数中的prototype中定义的属性和方法&#xff0c;会被创建的对象所继承下来。举个栗子&#xff1a; function F()…

webpack超详细配置

在这里就不详细介绍webpack来源以及作用了, 本篇博文面向新手主要说明如何配置webpack, 以及webpack的使用方法, 直到创建出一个合理的属于自己webpack项目; 流程 webpack安装 Step 1: 首先安装Node.js, 可以去Node.js官网下载.Step2: 在Git或者cmd中输入下面这段代码, 通过全局…

小白十分钟-推荐导航栏

大腿绕道&#xff0c;给小白学习用&#xff0c;上代码 <div class"list"><div class"infor"><ul class"left"><li><a href"">限时特价</a></li><li><a href"">热门推…

Underscore.js常用方法介绍

Underscore.js是一个很精干的库&#xff0c;压缩后只有4KB。它提供了几十种函数式编程的方法&#xff0c;弥补了标准库的不足&#xff0c;大大方便了JavaScript的编程。MVC框架Backbone.js就将这个库作为自己的工具库。除了可以在浏览器环境使用&#xff0c;Underscore.js还可以…

掌握ES6/ES2015核心内容

ECMAScript 6&#xff08;以下简称ES6&#xff09;是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的&#xff0c;所以又称ECMAScript 2015。 也就是说&#xff0c;ES6就是ES2015。 虽然目前并不是所有浏览器都能兼容ES6全部特性&#xff0c;但越来越多的程序员…

express-generator——Express应用生成器贼快!

通过应用生成器工具 express 可以快速创建一个应用的骨架。 通过如下命令安装&#xff1a; $ npm install express-generator -g-h 选项可以列出所有可用的命令行选项&#xff1a; $ express -hUsage: express [options] [dir]Options:-h, --help output usage inform…

转:canvas--放大镜效果

<!DOCTYPE html><html><head><meta charset"UTF-8"><title>鼠标事件</title></head><body><canvas id"canvas"></canvas><canvas id"offCanvas" style" display: none;&qu…

MON

早上5点,咪咪牛就醒了,开始跳到我边上,用白毛毛把我弄醒,在我身上走来走去,把她按住抚摸也不能让她停止.....只能拎起来扔到边上了 ;)看起来还的确是很调皮的猫咪呢昨天晚上就开始不太怕我了,走到我的椅子边上喵喵叫,直到把她放在身上,才慢慢睡觉,满可爱的早上出门叫车,一车正停…

CSS做个Switch开关

Switch开关&#xff1a;根据需求可知&#xff0c;Switch开关只有两种选择&#xff0c;true或false。所以我们想到HTML的checkbox控件&#xff0c;用它来做。  <input id"switch" type"checkbox" class"switch" />但是在浏览器中&#xf…

vue小记录1

1.入口index.html文件 做reset.css初始化&#xff0c;视口viewport设置 2.规范化eslint配置&#xff08;常用&#xff09; &#xff08;1&#xff09;rules -->"semi"分号 "semi":[error,alway], &#xff08;2&#xff09;indent 空格 "inde…