前端常见的6种排序算法

算法

算法特征:

  1. 输入:一个算法必须有一个或多个的输入量
  2. 输出:一个算法应有一个或以上的输出量,输出量是算法计算的结果
  3. 明确下:算法的描述必须无歧义,以保证算法的实际执行结果是精确地匹配要求或期望,通常要求实际运行结果是确定的。
  4. 有限性:依据图灵的定义,一个算法是能够被任何图灵完备系统模拟的一串运算,而图灵机只有有限个状态、有限个输入符号和有限个转移函数(指令)。而一些定义更要求算法必须在有限个步骤内完成任务。 有效性:又称可行性。能够实现,算法中描述的操作都是可以通过已经实现的基本运算执行有限次数来实现。

排序算法

1. 冒泡排序

冒泡排序思想:比较相邻两个数的大小(两两比较,除了首尾两个数字,其他数字都要比较两次),将较大(或小)的数换到右边(或左边),这样就能将最大(或最小)的数一个个比较出来,放到一端。循环这个过程,就能将所有数字的顺序排列出来。
时间复杂度:n * n
流程:

  1. 比较相邻两个数字的大小,对他们进行交换
  2. 对所有相邻的数字重复进行 1 的工作,等所有的数字都比较完,就能得出一个极端(最大或最小)的数字
  3. 继续重复以上的两个工作,将剩下数字中的极端数字找出来
  4. 依然重复,知道没有数字需要比较
JavaScript实现冒泡排序

冒泡排序算法最重要的是先确定冒泡次数:array.length - 1

function bubbleSort(array){
    for(let i = array.length - 1;i > 0;i--){ // 冒泡次数
        for(let j = 0;j < i;j++){            // 冒泡循环
            if(array[j] > array[j + 1]){
                let temp = array[j]
                array[j] = array[j + 1]
                array[j + 1] = temp
            }
        }
    }
    return array
}
复制代码
2. 选择排序

选择排序思想:在序列中将最大(最小)的数找出来,放到一边。之后重复这个过程,直到所有数字都被找出来。
时间复杂度:n * n
流程:

  1. 找出极端值
  2. 循环找出极端值
JavaScript实现选择排序
function selectSort(array){
    for(let i = 0;i < array.length - 1;i++){
        for(let j = i + 1;j < array.length;j++){
            if(array[i] > array[j]){
                let temp = array[i]
                array[i] = array[j]
                array[j] = temp
            }
        }
    }
    return array
}
复制代码
3. 计数排序

计数排序思想:使用一个额外的哈希,将需要排序的数组的数字变作哈希的键,之后遍历哈希的键,就得到排序后的数组。
时间复杂度:n + max

JavaScript实现计数排序
function countingSort(array){
    let hash = {}
    let newArray = []
    for(let i = 0 ;i < array.length;i++){
        let num = array[i]
        if(hash[num]){
            hash += 1
        } else{
            hash[num] = 1
        }
    }
    for(let i in hash){
        if(hash[i] = 1){
            newArray.push(i)
        } else{
            for(let i = 0;i < hash[i];i++){
                newArray.push(i)
            }
        }
    }

    newArray = Array.prototype.slice.call(newArray)
    return newArray
}
复制代码
4. 插入排序

插入排序思想:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

JavaScript实现插入排序
function insertSort(array){
    for(let i = 1; i < array.length; i++){
        for(let j = i; j >= 0; j--){
            if(array[j - 1] > array[j] ){
                let temp = array[j - 1]
                array[j - 1] = array[j]
                array[j] = temp
            } else {
                break
            }
        }
    }
    return array
}
复制代码
5. 堆排序算法

堆排序算法思想:把最大堆堆顶的数字取出,将剩余的数字继续调整为最大堆,再取出,重复过程,知道所有数字全部被取出。

二叉树:二叉树是每个节点最多有两个子树的的树结构。
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。 完全二叉树:满二叉树下,最后一层节点全部在一侧的的二叉树。

堆排序可以看作一个完全二叉树 某个节点下标i,算出该节点的父节点、左子节点和右子节点:

  • 父节点:parent(i) = floor(i/2)
  • 左子节点:left(i) = floor(2i)
  • 右子节点:right(i) = floor(2i+1)
    由于数组的下标从0开始,所以需要变化一下:
  • 父节点:parent(i) = floor((i-1)/2)
  • 左子节点:left(i) = floor(2(i+1))
  • 右子节点:right(i) = floor(2(i+1))

堆排序流程:

  1. 最大堆调整:将堆的末端子节点进行调整,使得子节点永远小于父节点。
  2. 创建最大堆:对调整后的父节点再进行最大堆调整,循环,使其成为最大堆。
  3. 堆排序:取出最大堆堆顶数字,再重复1、2

算法时间复杂度:nlog2n

JavaScript实现堆排序算法
function heapSort(array){
    let heapSize = array.length
    for(let i = 0; i < array.length; i++){
        createMaxHeap(array)

        heapSize -= 1

        swap(0, heapSize,array)
    }
    return array


    // 交换函数
    function swap(a, b,array){
        var temp = array[a]
        array[a] = array[b]
        array[b] = temp
    }

     // 创建最大堆
     function createMaxHeap(array){
        let iParent = Math.floor((array.length - 1 - 1) / 2)
        for(let i = iParent; i >= 0; i--){
            maxHeapify(array, i, heapSize)
        }
    } 

    // 最大堆调整
    function maxHeapify(array, index, heapSize){  // heapSize 是堆的大小,也就是数组的length
        while(true){
            let iMax = index
            let iLeft = Math.floor(2 * index + 1)
            let iRight = Math.floor(2 * index + 2)

            if (iLeft < heapSize && array[iLeft] > array[index]){
                iMax = iLeft
            }
            if (iRight < heapSize && array[iRight] > array[iMax]){
                iMax = iRight
            }

            if (iMax !== index){
                swap(index,iMax,array)
                maxHeapify(array, iMax, heapSize)
            } else {
                break
            }
        }     
        return array
    }
复制代码

未优化代码:

function heapSort(array){
    // 最大堆调整
    function maxHeapify(array, index, heapSize){  // heapSize 是堆的大小,也就是数组的length
        while(true){
            let iMax = index
            let iLeft = Math.floor(2 * index + 1)
            let iRight = Math.floor(2 * index + 2)

            if (iLeft < heapSize && array[iLeft] > array[index]){
                iMax = iLeft
            }
            if (iRight < heapSize && array[iRight] > array[iMax]){
                iMax = iRight
            }

            if (iMax !== index){
                let temp = array[index]
                array[index] = array[iMax]
                array[iMax] = temp

                maxHeapify(array, iMax, heapSize)
            } else {
                break
            }
        }     
        return array
    }

    let iParent = Math.floor((array.length-2)/2)
    let heapSize = array.length

    for(let i = 0; i < array.length;i++){
         for(let i = iParent; i >= 0; i--){
            maxHeapify(array,i,heapSize)
        }

        heapSize -= 1

        let temp = array[0]
        array[0] = array[heapSize]
        array[heapSize] = temp
    }
    return array
}

var a = [1,5,2,3,4,8,6,9,7]
heapSort(a)
复制代码
6. 快速排序

快速排序算法思想: 设置一个基准数,将基准数交换到数组的末尾,遍历数组,将小于基准数的换到左边,大于基准数的换到右边,之后将基准书换到他们的中间,这时候基准数就完成排序。这称为分区。快速排序就是不断分区的过程。完成第一个分区之后,再对左右两边分成的数组进行分区,重复以上过程,直到数组排序完毕。
算法复杂度:平均情况下快速排序的时间复杂度是Θ(nlg⁡n),最坏情况是n*n。

JavaScript实现快速排序
function quickSort(array){
    // 交换函数
    function swap(array,a,b){
        let temp = array[a]
        array[a] = array[b]
        array[b] = temp
    }

    // 分区函数
    function partition(array, left, right){
        let storeIndex = left
        let pivot = array[right]
        for(let i = left; i < right; i++){
            if(array[i] < pivot){
                swap(array, i, storeIndex)
                storeIndex += 1
            }
        }
        swap(array, storeIndex, right)
        return storeIndex
    }

    // 排序
    function sort(array, left, right){
        if(left > right){
            return;
        }
        let storeIndex = partition(array, left, right)
        sort(array, left, storeIndex - 1)
        sort(array, storeIndex + 1, right)
    }

    sort(array, 0, array.length - 1)
    return array
}
复制代码
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值