Git Product home page Git Product logo

blog's Introduction

blog's People

Contributors

jnoodle avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

前端需要掌握的算法之——选择排序(Selection sort)

Bad programmers worry about the code. Good programmers worry about data structures and their relationships. —— Linus Torvalds

选择排序(Selection sort) 的原理很简单,每次从待排序的元素中选出最小(大)的一个元素,放在序列的起始位置,然后一直重复,直到排序完成。

image

选择排序算法复杂度是:O(n2),效率较低,实际适用的场合很少。

选择排序交换次数比冒泡排序少,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。

image

上代码:

// 随机生成一个乱序数组
let arr = Array.from(new Array(10), () => ~~(Math.random() * 100))

console.log('Source array is [ %s ]\n', arr.join(', '))

// 选择排序
function selectionSort(arr) {
    const len = arr.length
    let minIndex // 最小值的 index
    for (let i = 0; i < len - 1; i++) {
        minIndex = i;
        for (let j = i + 1; j < len; j++) {
            // 遍历未排序元素,选出最小值 index
            if (arr[minIndex] > arr[j]) minIndex = j;
        }
        // 在确定最小值坐标之后,再交换元素位置,把最小值放到未排序元素最前面,提高效率
        if (minIndex !== i) {
            [arr[minIndex], arr[i]] = [arr[i], arr[minIndex]]
        }
        console.log('Step %d: [ %s ] (%s)', i + 1, arr.join(', '), minIndex !== i ? 'Swapped' : 'No swap')
    }
    console.log('\nSorted array is [ %s ]', arr.join(', '))
}

selectionSort(arr)

结果:

Source array is [ 38, 39, 41, 43, 61, 25, 85, 60, 71, 91 ]

Step 1: [ 25, 39, 41, 43, 61, 38, 85, 60, 71, 91 ] (Swapped)
Step 2: [ 25, 38, 41, 43, 61, 39, 85, 60, 71, 91 ] (Swapped)
Step 3: [ 25, 38, 39, 43, 61, 41, 85, 60, 71, 91 ] (Swapped)
Step 4: [ 25, 38, 39, 41, 61, 43, 85, 60, 71, 91 ] (Swapped)
Step 5: [ 25, 38, 39, 41, 43, 61, 85, 60, 71, 91 ] (Swapped)
Step 6: [ 25, 38, 39, 41, 43, 60, 85, 61, 71, 91 ] (Swapped)
Step 7: [ 25, 38, 39, 41, 43, 60, 61, 85, 71, 91 ] (Swapped)
Step 8: [ 25, 38, 39, 41, 43, 60, 61, 71, 85, 91 ] (Swapped)
Step 9: [ 25, 38, 39, 41, 43, 60, 61, 71, 85, 91 ] (No swap)

Sorted array is [ 25, 38, 39, 41, 43, 60, 61, 71, 85, 91 ]

注意:提升效率,较少交换次数:不要在遍历未排序元素时去交换,判断 minIndex !== i 再进行交换。

Egg.js 框架集成阿里 Node.js 性能平台 alinode

什么是 alinode?

Node.js 性能平台 ( Node.js Performance Platform,原 alinode ) 是面向所有 Node.js 应用提供 性能监控、安全提醒、故障排查、性能优化 等服务的整体性解决方案,尤其适用于中大型 Node.js 应用。

现在 alinode 是全免费的,不花钱。

集成步骤

1、创建应用

打开 Node.js 性能平台 ,然后点击 创建新应用 按钮,如下图所示:

创建新应用

创建应用成功后会展示出您创建的应用 App Id 以及 App secret 信息,如下图所示:

创建新应用

2、安装 alinode runtime

可以用全局方式安装,不过我个人比较喜欢把 runtime 安装到需要使用的项目里,这样不会有太多副作用。

npm i nodeinstall -g
nodeinstall --install-alinode ^3 --china

nodeinstall 会把对应版本的 alinode 安装到项目的 node_modules 目录下。加上 --china 参数,在国内的话会更快。

这里安装的版本号注意和服务器的 node 版本要对应

3、安装 egg-alinode 插件

执行如下命令将 egg-alinode 依赖安装并保存到您的 Node.js 项目中:

npm i egg-alinode --save

或者

yarn add egg-alinode

4、在 Egg 项目的 config/plugin.js 中启用此插件

// config/plugin.js
exports.alinode = {
  enable: true,
  package: 'egg-alinode'
};

5、在 Egg 项目的 config/config.default.js 中添加配置

// config/config.default.js
exports.alinode = {
  enable: true,
  server: 'wss://agentserver.node.aliyun.com:8080',
  appid: '***',  // Node.js 性能平台给您的项目生成的 appid
  secret: '***',  // Node.js 性能平台给您的项目生成的 secret
  logdir: '***',  // Node.js 性能平台日志输出地址绝对路径,与 NODE_LOG_DIR 保持一致。如:/tmp/,也可以不写
  error_log: [
    // '您的应用在业务层面产生的异常日志的路径,数组,可选,可配置多个',
    // '例如:/root/.logs/error.#YYYY#-#MM#-#DD#.log',
    // '不更改 Egg 默认日志输出路径可不配置本项目',
  ],
  agentidMode:'IP',  // 可选,如果设置,则在实例ID中添加部分IP信息,用于多个实例 hostname 相同的场景(以容器为主)
};

6、使用 Node.js 性能平台提供的 runtime 启动 Egg 应用

egg-scripts start --daemon

完成了上面几步,就可以在阿里 Node.js 性能平台看到监控信息了。如果你用的操作系统是 MacOS 或者 Windows,有的功能会不能用,Node.js 性能平台对 Linux 的支持最好。

前端需要掌握的算法之——希尔排序(Shell sort)

Bad programmers worry about the code. Good programmers worry about data structures and their relationships. —— Linus Torvalds

希尔排序(Shell sort) 也称递减增量排序算法,是插入排序的一种更高效的改进版本。插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能,这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

步长的选择是希尔排序的重要部分。比较在希尔排序中是最主要的操作,而不是交换。

步长序列 最坏情况下复杂度
n/2i O(n2)
2k - 1 O(n3/2)
2i3j O(n log2n)

上代码:

// 随机生成一个乱序数组
let arr = Array.from(new Array(10), () => ~~(Math.random() * 100))

console.log('Source array is [ %s ]\n', arr.join(', '))

// 希尔排序
function shellSort(arr) {
    const len = arr.length
    let step = 1
    let gap = len >> 1
    let temp
    for (; gap > 0; gap >>= 1) {
        console.log('Gap is %d:', gap)
        let log = ''
        arr.forEach((v, i) => {
            log += `${v}\t${(i + 1) % gap === 0 ? '\n' : ''}`
        })
        console.log('Initial: \n%s', log)

        for (let i = gap, j; i < len; i++) {
            temp = arr[i]
            for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
                arr[j + gap] = arr[j]
            }
            arr[j + gap] = temp

            log = ''
            arr.forEach((v, i) => {
                log += `${v}\t${(i + 1) % gap === 0 ? '\n' : ''}`
            })
            console.log('Step %d: \n%s', step++, log)
        }
    }
    console.log('\nSorted array is [ %s ]', arr.join(', '))
}

shellSort(arr)

结果:

Source array is [ 38, 46, 96, 16, 70, 19, 53, 21, 27, 74 ]

Gap is 5:
Initial: 
38	46	96	16	70	
19	53	21	27	74	

Step 1: 
19	46	96	16	70	
38	53	21	27	74	

Step 2: 
19	46	96	16	70	
38	53	21	27	74	

Step 3: 
19	46	21	16	70	
38	53	96	27	74	

Step 4: 
19	46	21	16	70	
38	53	96	27	74	

Step 5: 
19	46	21	16	70	
38	53	96	27	74	

Gap is 2:
Initial: 
19	46	
21	16	
70	38	
53	96	
27	74	

Step 6: 
19	46	
21	16	
70	38	
53	96	
27	74	

Step 7: 
19	16	
21	46	
70	38	
53	96	
27	74	

Step 8: 
19	16	
21	46	
70	38	
53	96	
27	74	

Step 9: 
19	16	
21	38	
70	46	
53	96	
27	74	

Step 10: 
19	16	
21	38	
53	46	
70	96	
27	74	

Step 11: 
19	16	
21	38	
53	46	
70	96	
27	74	

Step 12: 
19	16	
21	38	
27	46	
53	96	
70	74	

Step 13: 
19	16	
21	38	
27	46	
53	74	
70	96	

Gap is 1:
Initial: 
19	
16	
21	
38	
27	
46	
53	
74	
70	
96	

Step 14: 
16	
19	
21	
38	
27	
46	
53	
74	
70	
96	

Step 15: 
16	
19	
21	
38	
27	
46	
53	
74	
70	
96	

Step 16: 
16	
19	
21	
38	
27	
46	
53	
74	
70	
96	

Step 17: 
16	
19	
21	
27	
38	
46	
53	
74	
70	
96	

Step 18: 
16	
19	
21	
27	
38	
46	
53	
74	
70	
96	

Step 19: 
16	
19	
21	
27	
38	
46	
53	
74	
70	
96	

Step 20: 
16	
19	
21	
27	
38	
46	
53	
74	
70	
96	

Step 21: 
16	
19	
21	
27	
38	
46	
53	
70	
74	
96	

Step 22: 
16	
19	
21	
27	
38	
46	
53	
70	
74	
96	


Sorted array is [ 16, 19, 21, 27, 38, 46, 53, 70, 74, 96 ]

注意:这里根据步长分割后是纵向排序,不是横向。

前端需要掌握的算法之——鸡尾酒排序(Cocktail sort)

鸡尾酒排序(Cocktail sort) 是冒泡排序的改进版本,也叫定向冒泡排序,鸡尾酒搅拌排序,搅拌排序,涟漪排序,来回排序或快乐小时排序之类的,与冒泡排序的不同处在于排序时是以双向在序列中进行排序。

鸡尾酒排序可以得到比冒泡排序稍微好一点的性能。鸡尾酒排序最糟或是平均所花费的次数都是 O(n2),但如果序列在一开始已经大部分排序过的话,会接近 O(n)。

上代码:

// 随机生成一个乱序数组
let arr = Array.from(new Array(10), () => ~~(Math.random() * 100))

console.log('Source array is [ %s ]\n', arr.join(', '))

// 鸡尾酒排序
function cocktailSort(arr) {
    const len = arr.length
    let swapped // 是否有过交换,一旦没有任何元素交换,排序结束
    let step = 1
    let i, left = 0, right = len - 1;
    while (left < right) {
        // 先从左扫到右,把最大的放到最右边
        for (i = left; i < right; i++) {
            swapped = false
            if (arr[i] > arr[i + 1]) {
                [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
                swapped = true
            }
        }
        console.log('Step %d: [ %s ] ( left -> right )', step++, arr.join(', '))
        right--;
        // 再从右扫到左,把最小的放到最左边
        for (i = right; i > left; i--) {
            if (arr[i - 1] > arr[i]) {
                [arr[i], arr[i - 1]] = [arr[i - 1], arr[i]]
            }
        }
        left++;
        console.log('Step %d: [ %s ] ( right -> left )', step++, arr.join(', '))
        if (!swapped) break
    }
    console.log('\nSorted array is [ %s ]', arr.join(', '))
}

cocktailSort(arr)

结果:

Source array is [ 84, 83, 37, 79, 78, 48, 26, 67, 23, 42 ]

Step 1: [ 83, 37, 79, 78, 48, 26, 67, 23, 42, 84 ] ( left -> right )
Step 2: [ 23, 83, 37, 79, 78, 48, 26, 67, 42, 84 ] ( right -> left )
Step 3: [ 23, 37, 79, 78, 48, 26, 67, 42, 83, 84 ] ( left -> right )
Step 4: [ 23, 26, 37, 79, 78, 48, 42, 67, 83, 84 ] ( right -> left )
Step 5: [ 23, 26, 37, 78, 48, 42, 67, 79, 83, 84 ] ( left -> right )
Step 6: [ 23, 26, 37, 42, 78, 48, 67, 79, 83, 84 ] ( right -> left )
Step 7: [ 23, 26, 37, 42, 48, 67, 78, 79, 83, 84 ] ( left -> right )
Step 8: [ 23, 26, 37, 42, 48, 67, 78, 79, 83, 84 ] ( right -> left )
Step 9: [ 23, 26, 37, 42, 48, 67, 78, 79, 83, 84 ] ( left -> right )
Step 10: [ 23, 26, 37, 42, 48, 67, 78, 79, 83, 84 ] ( right -> left )

Sorted array is [ 23, 26, 37, 42, 48, 67, 78, 79, 83, 84 ]

用10000个随机10位数组,和冒泡排序简单测试比较一下:

let sumBubble = 0
let sumCocktail = 0

for (let i = 0; i < 10000; i++) {
    arr = Array.from(new Array(10), () => ~~(Math.random() * 100))
    sumBubble += bubbleSort(arr)
    sumCocktail += cocktailSort(arr)
}

console.log('Bubble sort average steps: %s', sumBubble / 10000)
console.log('Cocktail sort average steps: %s', sumCocktail / 10000)

结果:

Bubble sort average steps: 8.4829
Cocktail sort average steps: 3

前端需要掌握的算法之——冒泡排序(Bubble Sort)

Bad programmers worry about the code. Good programmers worry about data structures and their relationships. —— Linus Torvalds

冒泡排序(Bubble Sort) 顾名思义,就是两两依次比较,如果顺序错误,就交换,直到没有交换,排序结束。有点类似水里的气泡一点一点浮上来,所以叫冒泡排序。

具体步骤如下(假设是从小到大排序):

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个(因为已经排序好了)
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

image

冒泡排序算法复杂度是:O(n2),效率较低。

  • 最坏时间复杂度 O(n2)
  • 最优时间复杂度 O(n)
  • 平均时间复杂度 O(n2)
  • 最坏空间复杂度 总共 O(n),需要辅助空间 O(1)

http://bigocheatsheet.com/

上代码:

// 随机生成一个乱序数组
let arr = Array.from(new Array(10), () => ~~(Math.random() * 100))

console.log('Source array is [ %s ]\n', arr.join(', '))

// 冒泡排序
function bubbleSort(arr) {
    const len = arr.length
    let swapped // 是否有过交换,一旦没有任何元素交换,排序结束
    let step = 1
    for (let i = 0; i < len; i++) {
        swapped = false
        // 注意这里是len - i,每一轮都会把最大的元素放在最后,所以 len - i 后面的元素不用再比较
        for (let j = 0; j < len - i; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换元素位置,这里是es6的方式
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
                swapped = true
            }
        }
        console.log('Step %d: [ %s ]', step++, arr.join(', '))
        if (!swapped) break
    }
    console.log('\nSorted array is [ %s ]', arr.join(', '))
}

bubbleSort(arr)

结果:

Source array is [ 87, 94, 38, 54, 7, 89, 71, 82, 26, 20 ]

Step 1: [ 87, 38, 54, 7, 89, 71, 82, 26, 20, 94 ]
Step 2: [ 38, 54, 7, 87, 71, 82, 26, 20, 89, 94 ]
Step 3: [ 38, 7, 54, 71, 82, 26, 20, 87, 89, 94 ]
Step 4: [ 7, 38, 54, 71, 26, 20, 82, 87, 89, 94 ]
Step 5: [ 7, 38, 54, 26, 20, 71, 82, 87, 89, 94 ]
Step 6: [ 7, 38, 26, 20, 54, 71, 82, 87, 89, 94 ]
Step 7: [ 7, 26, 20, 38, 54, 71, 82, 87, 89, 94 ]
Step 8: [ 7, 20, 26, 38, 54, 71, 82, 87, 89, 94 ]
Step 9: [ 7, 20, 26, 38, 54, 71, 82, 87, 89, 94 ]

Sorted array is [ 7, 20, 26, 38, 54, 71, 82, 87, 89, 94 ]

注意:不要忘记对 swappedj < len - i 的判断,否则会增添很多没有必要的比较,降低效率。

前端需要掌握的算法之——插入排序(Insertion sort)

Bad programmers worry about the code. Good programmers worry about data structures and their relationships. —— Linus Torvalds

插入排序(Insertion sort) 就是每一步都将一个待排序的元素,按照它的大小,插入到已经排序的元素中的适当位置,一直重复,直到全部待排序的元素插入完毕。

具体步骤如下(假设是从小到大排序):

  1. 将待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列
  2. 从后向前依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置

插入排序算法复杂度是:O(n2)。

  • 最坏时间复杂度 O(n2)
  • 最优时间复杂度 O(n)
  • 平均时间复杂度 O(n2)
  • 最坏空间复杂度 总共 O(n),需要辅助空间 O(1)

image

上代码:

// 随机生成一个乱序数组
let arr = Array.from(new Array(10), () => ~~(Math.random() * 100))

console.log('Source array is [ %s ]\n', arr.join(', '))

// 插入排序
function insertionSort(arr) {
    const len = arr.length
    let step = 1;
    // i 为未排序序列 index,j 为已排序序列 index,起始 arr[0] 作为已排序序列,所以 i 从 1 开始
    for (let i = 1; i < len; i++) {
        // 选取 arr[i] 作为待排序元素,从右到左依次与左侧的已排序序列比较
        let insertItem = arr[i]
        for (let j = i - 1; j >= -1; j--) {
            // j === -1 代表已经比较到第一个元素,都没有发现更小的,则需要插入到最前端
            // 这里采用直接插入的方式,也可以选择依次交换的方式
            if (j === -1 || arr[j] < insertItem) {
                if (j + 1 !== i) {
                    // 把元素从 i 插入到 j + 1 位置
                    arr.splice(j + 1, 0, insertItem); // 插入元素
                    arr.splice(i + 1, 1); // 删除元素
                }
                console.log('Step %d: [ %s ] (insert %s from %d to %d, %s)', step++, arr.join(', '), insertItem, i, j + 1, j + 1 !== i ? 'Moved' : 'No move')
                break;
            }
        }
    }
    console.log('\nSorted array is [ %s ]', arr.join(', '))
}

insertionSort(arr)

结果:

Source array is [ 38, 12, 34, 65, 10, 47, 51, 55, 27, 11 ]

Step 1: [ 12, 38, 34, 65, 10, 47, 51, 55, 27, 11 ] (insert 12 from 1 to 0, Moved)
Step 2: [ 12, 34, 38, 65, 10, 47, 51, 55, 27, 11 ] (insert 34 from 2 to 1, Moved)
Step 3: [ 12, 34, 38, 65, 10, 47, 51, 55, 27, 11 ] (insert 65 from 3 to 3, No move)
Step 4: [ 10, 12, 34, 38, 65, 47, 51, 55, 27, 11 ] (insert 10 from 4 to 0, Moved)
Step 5: [ 10, 12, 34, 38, 47, 65, 51, 55, 27, 11 ] (insert 47 from 5 to 4, Moved)
Step 6: [ 10, 12, 34, 38, 47, 51, 65, 55, 27, 11 ] (insert 51 from 6 to 5, Moved)
Step 7: [ 10, 12, 34, 38, 47, 51, 55, 65, 27, 11 ] (insert 55 from 7 to 6, Moved)
Step 8: [ 10, 12, 27, 34, 38, 47, 51, 55, 65, 11 ] (insert 27 from 8 to 2, Moved)
Step 9: [ 10, 11, 12, 27, 34, 38, 47, 51, 55, 65 ] (insert 11 from 9 to 1, Moved)

Sorted array is [ 10, 11, 12, 27, 34, 38, 47, 51, 55, 65 ]

注意:这里采用直接插入的方式,也可以选择依次交换的方式,代码相对会简单一点。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.