前端(七)算法篇

算法篇

一、快速排序(Quick Sort)

快速排序的名字起的是简单粗暴,由于一听到这个名字你就知道它存在的意义,就是快,并且效率高! 它是处理大数据最快的排序算法之一了。算法

(1)算法简介shell

快速排序的基本思想:经过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另外一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。api

(2)算法描述和实现数组

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述以下:bash

  • <1>.从数列中挑出一个元素,称为 "基准"(pivot);
  • <2>.从新排序数列,全部元素比基准值小的摆放在基准前面,全部元素比基准值大的摆在基准的后面(相同的数能够到任一边)。在这个分区退出以后,该基准就处于数列的中间位置。这个称为分区(partition)操做;
  • <3>.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

Javascript代码实现:数据结构

/*方法说明:快速排序
@param  array 待排序数组*/

var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];

var quickSort=function(arr){
    if(arr.length <= 1){
        return arr;
    }
    var keyIndex=Math.floor(arr.length / 2);
    var key=arr.splice(keyIndex,1)[0];
    var left=[];
    var right=[];
    for(var i=0;i<arr.length;i++){
        if(arr[i] < index){
            left.push(arr[i]);
        }else {
            right.push(arr[i]);
        }
    }
    
    return quickSort(left).concat([index],quickSort(right);
}
复制代码

快速排序动图演示:大数据

(3)算法分析ui

  • 最佳状况:T(n) = O(nlogn)
  • 最差状况:T(n) = O(n2)
  • 平均状况:T(n) = O(nlogn)

二、冒泡排序(Bubble Sort)

(1)算法描述spa

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,若是它们的顺序错误就把它们交换过来。走访数列的工做是重复地进行直到没有再须要交换,也就是说该数列已经排序完成。这个算法的名字由来是由于越小的元素会经由交换慢慢“浮”到数列的顶端。prototype

(2)算法描述和实现

具体算法描述以下:

  • <1>.比较相邻的元素。若是第一个比第二个大,就交换它们两个;

  • <2>.对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;

  • <3>.针对全部的元素重复以上的步骤,除了最后一个;

  • <4>.重复步骤1~3,直到排序完成。

JavaScript代码实现:

传统冒泡排序中每一趟排序操做只能找到一个最大值或最小值,咱们考虑利用在每趟排序中进行正向和反向两遍冒泡的 方法一次能够获得两个最终值(最大者和最小者) ,从而使排序趟数几乎减小了一半。

function bubbleSort3(arr3) {
    var low = 0;
    var high= arr.length-1; //设置变量的初始值
    var tmp,j;
    while (low < high) {
        for (j= low; j< high; ++j) //正向冒泡,找到最大者
            if (arr[j]> arr[j+1]) {
                tmp = arr[j]; 
                arr[j]=arr[j+1];
                arr[j+1]=tmp;
            }
        --high;                 //修改high值, 前移一位
        for (j=high; j>low; --j) //反向冒泡,找到最小者
            if (arr[j]
复制代码

冒泡排序动图演示:

(3)算法分析

  • 最佳状况:T(n) = O(n)

当输入的数据已是正序时(都已是正序了,为毛何须还排序呢....)

  • 最差状况:T(n) = O(n2)

当输入的数据是反序时(卧槽,我直接反序不就完了....)

  • 平均状况:T(n) = O(n2)

三、选择排序(Selection Sort)

表现最稳定的排序算法之一,由于不管什么数据进去都是O(n²)的时间复杂度.....因此用到它的时候,数据规模越小越好。惟一的好处可能就是不占用额外的内存空间了吧。

(1)算法简介

选择排序(Selection-sort)是一种简单直观的排序算法。它的工做原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而后,再从剩余未排序元素中继续寻找最小(大)元素,而后放到已排序序列的末尾。以此类推,直到全部元素均排序完毕。

(2)算法描述和实现

n个记录的直接选择排序可通过n-1趟直接选择排序获得有序结果。具体算法描述以下:

  • <1>.初始状态:无序区为R[1..n],有序区为空;

  • <2>.第i趟排序(i=1,2,3...n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增长1个的新有序区和记录个数减小1个的新无序区;

  • <3>.n-1趟结束,数组有序化了。

Javascript代码实现:

function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {     //寻找最小的数
                minIndex = j;                 //将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    console.timeEnd('选择排序耗时');
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
复制代码

选择排序动图演示:

(3)算法分析

  • 最佳状况:T(n) = O(n2)
  • 最差状况:T(n) = O(n2)
  • 平均状况:T(n) = O(n2)

四、插入排序(Insertion Sort)

(1)算法简介

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工做原理是经过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,一般采用in-place排序(即只需用到O(1)的额外空间的排序),于是在从后向前扫描过程当中,须要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

(2)算法描述和实现

通常来讲,插入排序都采用in-place在数组上实现。具体算法描述以下:

  • <1>.从第一个元素开始,该元素能够认为已经被排序;

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

  • <3>.若是该元素(已排序)大于新元素,将该元素移到下一位置;

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

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

  • <6>.重复步骤2~5。

Javascript代码实现:

function insertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        console.time('插入排序耗时:');
        for (var i = 1; i < array.length; i++) {
            var key = array[i];
            var j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
        console.timeEnd('插入排序耗时:');
        return array;
    } else {
        return 'array is not an Array!';
    }
}
复制代码

插入排序动图演示:

(3)算法分析

  • 最佳状况:输入数组按升序排列。T(n) = O(n)
  • 最坏状况:输入数组按降序排列。T(n) = O(n2)
  • 平均状况:T(n) = O(n2)

五、希尔排序(Shell Sort)

(1)算法描述和实现

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

  • <1>. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;

  • <2>.按增量序列个数k,对序列进行k 趟排序;

  • <3>.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列做为一个表来处理,表长度即为整个序列的长度。

Javascript代码实现:

function shellSort(arr) {
    var len = arr.length,
        temp,
        gap = 1;
    console.time('希尔排序耗时:');
    while(gap < len/5) {          //动态定义间隔序列
        gap =gap*5+1;
    }
    for (gap; gap > 0; gap = Math.floor(gap/5)) {
        for (var i = gap; i < len; i++) {
            temp = arr[i];
            for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = temp;
        }
    }
    console.timeEnd('希尔排序耗时:');
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
复制代码

(2)、希尔排序动态演示 假设咱们有以下7个元素,分别为84, 25, 59, 71, 62, 16, 34,如今进行希尔排序。

第一轮选取全部元素数量的一半做为增量,即7/2,取3,因此第一轮增量为3,那么第一组分组就是索引为0,3,6对应的元素,即84,71,34,对其进行插入排序操做,

84当作已排序序列,接着准备将组内第二个元素71插入到已排序序列中,

71小于84,因此84后移到71原来的位置,

接着将组内第三个元素34插入到已排序序列中,首先与84比较,

34小于84,因此84后移,而后继续与71比较,

34小于71,因此71后移,34放进去。而后开始处理第二组分组,第二组分组就是索引为1,4对应的元素,即25,62,对其进行插入排序操做,

25当作已排序序列,接着将组内第二个元素62插入到已排序序列中,

25小于62,因此不移动。而后开始处理第三组分组,第三组分组就是索引为2,5对应的元素,即59,16,对其进行插入排序操做,

59当作已排序序列,接着将组内第二个元素16插入到已排序序列中,

16小于59,因此59后移而16前移。至此处理完增量为3的状况。

第二轮增量为上一轮增量的二分之一,即3/2,取1,因此第二轮增量为1,此时全部元素组成同一个分组,对该组进行插入排序操做,首先将34当成已排序序列,准备将25插入到已排序序列,

25小于34,因而34后移,

继续将下一个元素插入已排序序列中,1634比较,

16小于34,因而34右移,接着1625比较,

16小于25,25后移,16放进对应位置,

继续将下一个元素插入已排序序列中,71与34比较,

34小于71,不移动,71放回原来位置,

继续将下一个元素插入已排序序列中,62与71比较,

62小于71,因而71后移,接着62与34比较,

34小于62,不移动,62放到对应位置,

继续将下一个元素插入已排序序列中,59与71比较,

59小于71,因而71后移,而后继续与62比较,

59小于62,因而62也后移,而后继续与34比较,

34小于59,因而34不移动,59放到对应位置,

继续将下一个元素插入已排序序列中,已是最后一个元素了,84与71比较,

71小于84,因此不移动,此时已完成全部元素的希尔排序操做。

(3)算法分析

  • 最佳状况:T(n) = O(nlog2 n)
  • 最坏状况:T(n) = O(nlog2 n)
  • 平均状况:T(n) =O(nlog n)

六、堆排序(Heap Sort)

(1)算法简介

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似彻底二叉树的结构,并同时知足堆积的性质:即子结点的键值或索引老是小于(或者大于)它的父节点。

(2)算法描述和实现

具体算法描述以下:

  • 首先遍历数组,判断该节点的父节点是否比他小,若是小就交换位置并继续判断,直到他的父节点比他大 从新以上操做 1,直到数组首位是最大值

  • 而后将首位和末尾交换位置并将数组长度减一,表示数组末尾已经是最大值,不须要再比较大小

  • 对比左右节点哪一个大,而后记住大的节点的索引而且和父节点对比大小,若是子节点大就交换位置

  • 重复以上操做 3 - 4 直到整个数组都是大根堆。

Javascript代码实现:

function heap(array) {
  checkArray(array);
  // 将最大值交换到首位
  for (let i = 0; i < array.length; i++) {
    heapInsert(array, i);
  }
  let size = array.length;
  // 交换首位和末尾
  swap(array, 0, --size);
  while (size > 0) {
    heapify(array, 0, size);
    swap(array, 0, --size);
  }
  return array;
}

function heapInsert(array, index) {
  // 若是当前节点比父节点大,就交换
  while (array[index] > array[parseInt((index - 1) / 2)]) {
    swap(array, index, parseInt((index - 1) / 2));
    // 将索引变成父节点
    index = parseInt((index - 1) / 2);
  }
}
function heapify(array, index, size) {
  let left = index * 2 + 1;
  while (left < size) {
    // 判断左右节点大小
    let largest =
      left + 1 < size && array[left] < array[left + 1] ? left + 1 : left;
    // 判断子节点和父节点大小
    largest = array[index] < array[largest] ? largest : index;
    if (largest === index) break;
    swap(array, index, largest);
    index = largest;
    left = index * 2 + 1;
  }
}

复制代码

堆排序动图演示:

(3)算法分析

  • 最佳状况:T(n) = O(nlogn)
  • 最差状况:T(n) = O(nlogn)
  • 平均状况:T(n) = O(nlogn)

参考文章:十大经典排序算法总结(JavaScript描述)

相关文章
相关标签/搜索