zoukankan      html  css  js  c++  java
  • 排序算法记录

    前言:看过好大佬写的排序,终究是写了忘忘了写,发现过一段时间还是会忘记,记录在这里,忘了可以常看看~~有大哥发现是自己的代码,留言call我,加引用

    .js文件

    const arr = [91, 60, 96, 7, 35, 65, 10, 65, 9, 30, 20, 31, 77, 81, 24];
    // 常用函数,数组元素换位置
    function swap(arr, q, w) {
      return [arr[q], arr[w]] = [arr[w], arr[q]]
    }
    

      

    1.冒泡排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>冒泡排序</title>
    </head>
    <body>
    
    </body>
    </html>
    
    <script>
      // 循环两两比较,交换位置
      // 冒泡排序
      const arr = [91, 60, 96, 7, 35, 65, 10, 65, 9, 30, 20, 31, 77, 81, 24]
      // 常用函数,数组元素换位置
      function swap(arr, q, w) {
        return [arr[q], arr[w]] = [arr[w], arr[q]]
      }
      // 基本版本
      function bubbleSort(arr) {
        const len = arr.length - 1
        for (let i = len; i > 0; i--) {
          for (let j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
              swap(arr, j, j + 1)
            }
          }
        }
        return arr
      }
      // 设置缓存
      // 设置一标志性变量 pos,用于记录每趟排序中最后一次进行交换的位置。 由于 pos 位置之后的记录均已交换到位,故在进行下一趟排序时只要扫描到 pos 位置即可。
      function bubbleSort2(arr) {
        let i = arr.length - 1
        while (i > 0) {
          let pos = 0
          for (let j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
              pos = j
              swap(arr, j, j + 1)
            }
          }
          i = pos
        }
        return arr
      }
      // 双向遍历
      function bubbleSort3(arr) {
        let start = 0
        let end = arr.length - 1
        while (start < end) {
          for (let i = start; i < end; i++) {
            if (arr[i] > arr[i+1]) {
              swap(arr, i, i+1)
            }
          }
          end -= 1
          for (let i = end; i > start ; i--) {
            if (arr[i] < arr[i - 1]) {
              swap(arr, i-1, i)
            }
          }
          start += 1
        }
        return arr
      }
      // 缓存加双向
      function bubbleSort4(arr) {
        let start = 0
        let end = arr.length - 1
        while (start < end) {
          let posStart = 0
          let posEnd = 0
          for (let i = start; i < end; i++) {
            if (arr[i] > arr[i+1]) {
              swap(arr, i, i+1)
              posEnd = i
            }
          }
          end = posEnd
          for (let i = end; i > start ; i--) {
            if (arr[i] < arr[i - 1]) {
              swap(arr, i-1, i)
              posStart = i
            }
          }
          start = posStart
        }
        return arr
      }
    
      console.log(bubbleSort4(arr))
    </script>
    

    2.选择排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>选择排序</title>
    </head>
    <body>
    
    </body>
    </html>
    <script src="./js"></script>
    <script>
    // 选择一个元素挨个与数组中元素比较,每次循环选出最小的放到前面
    // 最小值
    function selectSort(arr) {
      let len = arr.length
      let minIndex = 0
      if (len <= 1) {
        return arr
      }
      for (let i = 0; i < len - 1; i++) {
        minIndex = i
        for (let j = i+1; j < len; j++) {
          if (arr[j] < arr[minIndex]) {
            minIndex = j
          }
        }
        swap(arr, i, minIndex)
      }
      return arr
    }
    
    // 最大值
    function selectSort2(arr) {
      const len = arr.length
      let maxIndex = 0
      if (len <= 1) {
        return arr
      }
      for (let i = len-1; i > 0; i--) {
        maxIndex = i
        for (let j = i-1; j >= 0; j--) {
          if (arr[j] > arr[maxIndex]) {
            maxIndex = j
          }
        }
        swap(arr, i, maxIndex)
      }
      return arr
    }
    
    console.log(selectSort(arr))
    console.log(selectSort2(arr))
    </script>
    

    3.插入排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>插入排序</title>
    </head>
    <body>
    
    </body>
    <script src="./js"></script>
    <script>
    // 默认 a[0] 为已排序数组中的元素,从 arr[1] 开始逐渐往已排序数组中插入元素,从后往前一个个比较,如果待插入元素小于已排序元素,则已排序元素往后移动一位,
    // 直到待插入元素找到合适的位置并插入已排序数组。经过 n - 1 次这样的循环插入后排序完毕。
    function insertSort(arr) {
      const len = arr.length
      if (len <= 1) {
        return arr
      }
      for (let i = 1; i < len; i++) {
        for (let j = i; j > 0; j--) {
          if (arr[j] < arr[j-1]) {
            swap(arr, j-1, j)
          }
        }
      }
      return [...arr]
    }
    
    function insert_sort(arr) {
      let count = 0
      for (let j = arr.length; j > 0; j--) {
        for (let i = j; i > 0; i--) {
          if (arr[i] < arr[i - 1]) {
            [arr[i], arr[i - 1]] = [arr[i - 1], arr[i]]
            count++
          }
        }
        if (count === 0) {
          return
        }
      }
      return arr
    }
    let arr1 = [7, 4, 3, 67, 34, 1, 8]
    let arr2 = [ 1, 3, 4, 7, 8, 34, 67 ]
    insert_sort(arr1) // [ 1, 3, 4, 7, 8, 34, 67 ] 时间复杂度:O(n^2)
    insert_sort(arr2) // [ 1, 3, 4, 7, 8, 34, 67 ] 时间复杂度:O(n)
    
    console.log(insertSort(arr))
    </script>
    </html>
    

    4.希尔排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>希尔排序</title>
    </head>
    <body>
    
    </body>
    <script src="./js"></script>
    <script>
        // 插入排序升级版
        function shellSort(arr) {
          const len = arr.length
          let temp = 0
          //增量(一般第一趟取长度的一半向下取整)
          let gap = Math.floor(len / 2)
          let j
          //每一趟过后增量会变成原来的一半并向下取整,可知最后一趟增量肯定是1
          //增量为1即实现普通的插入排序,执行完毕整个排序肯定就完成了
          //而最后一趟增量为1过完时,增量变成0
          //gap > 0是为了控制当增量变成0时,整个排序已完成,停止排序
          for (gap; gap > 0; gap = Math.floor(gap / 2)) {
            //以下开始即普通的插入排序(按分好的组进行插入)
            //初始i=gap是为了让第gap+1个数和第一个数相比
            //i<len是从第gap+1个数开始之后的每一个数都和之前差n个增量的数相比
            for (let i = gap; i < len; i++) {
              //保存当前要拿来对比插入的数(比较数)
              temp = arr[i]
              //j=i-gap是将temp和之前差一个增量的数相比,arr[j]即被比较数
              //j>=0是按增量向前比,一直比到向前减一个增量没有数 即下标j<0
              //arr[j] > temp是判断被比较数是否大于比较数,
              //如果大于,将被比较数向后移一个增量的位置,
              //即比较数的位置 i或者j+gap
              //j -= gap 每次在上次被比较数的基础上向前比差一个增量的数
              for (j = i-gap; j>=0 && arr[j]>temp; j-=gap) {
                //将被比较数向后移一个增量的位置,
                //即比较数的位置 i或者j+gap
                arr[j + gap] = arr[j]
              }
              arr[j + gap] = temp//插入比较数
            }
          }
          return arr
        }
        console.log(shellSort(arr))
    </script>
    </html>
    

    5.快速排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>快速排序</title>
    </head>
    <body>
    
    </body>
    </html>
    <script>
    /*
    * 选择一个基准,根据基准分开
    * 进行迭代
    * */
    const arr = [91, 60, 96, 7, 35, 65, 10, 65, 9, 30, 20, 31, 77, 81, 24]
    const quickSort = function (arr) {
      if (arr.length <= 1) {
        return arr
      }
      const pivotIndex = Math.floor(arr.length / 2)
      const pivot = arr.splice(pivotIndex, 1)[0]
      const left = []
      const right = []
      for (let i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
          left.push(arr[i])
        } else {
          right.push(arr[i])
        }
      }
      return [...quickSort(left), ...[pivot], ...quickSort(right)]
    }
    
    function quickSort2(arr) {
      if (arr.length <= 1) {
        return arr
      }
      const pivotIndex = Math.floor(arr.length / 2)
      const pivot = arr.splice(pivotIndex, 1)[0]
      const left = arr.filter(q => q < pivot)
      const right = arr.filter(q => q >= pivot)
      return [...quickSort2(left), ...[pivot], ...quickSort2(right)]
    }
    
    console.log(quickSort2(arr))
    </script>
    

    6.归并排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>归并排序</title>
    </head>
    <body>
    
    </body>
    <script src="./js"></script>
    <script>
    // 归并排序使用分而治之的思想,以折半的方式来递归/迭代排序元素,利用空间来换时间,做到了时间复杂度 O(n·log(n)) 的同时保持了排序
    // 元素的 stable,这让它在一些更考虑排序效率和稳定性,次考虑存储空间的场合非常适用(如数据库内排序,和堆排序相比,归并
    // 排序的 stable 是优点)。并且归并排序非常适合于列表排序。
    function mergeSort(arr) {  // recursion
      const len = arr.length
      const mid = Math.floor(len / 2)
      let left = arr.slice(0, mid)
      let right = arr.slice(mid)
      if (len < 2) {
        return arr
      }
      return merge(mergeSort(left), mergeSort(right))
    }
    
    function merge(left, right) {
      let result = []
      while (left.length > 0 && right.length > 0) {  // sorting: small to big
        result.push(left[0] <= right[0] ? left.shift() : right.shift())  // keep stable
      }
      return result.concat(left, right)
    }
    
    // test
    let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
    console.log(mergeSort(arr))
    // [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
    </script>
    </html>
    

    7.堆排序

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>堆排序</title>
    </head>
    <body style=" 1200px;margin: 0 auto">
        <p>
            一,堆的概念
            堆是一棵顺序存储的二叉树
            其中每个节点的关键字都不大于其子节点的关键字,这样的堆称为小根堆
            其中每个节点的关键字都不小于其自己点的关键字,这样的堆称为大根堆
            下面是一个典型的小根堆:
        </p>
        <img src="./img/典型小根堆.jpg" alt="">
        <p>
            二,堆的调整
            堆的调整是为了保持堆的特性而做的一个操作,对以某一个节点为根的子树做堆调整,其实就是将该根节点进行”下沉操作”(具体是通过和子节点的交换完成的),一直下沉到合适位置,使得刚才的子树满足堆的性质为止。
            对大根堆的调整步骤如下:
            1,在对应元素A[i],找到左孩子A[left(i)]和右孩子A[right(i)]中最大的那一个,将其下标存储在largest中。
            2,如果A[i]已经是最大元素,则程序结束
            3,否则,i的某个子节点为最大的元素,将A[largest]与A[i]交换
            4,再从交换的子节点开始,重复1,2,3步骤,直至叶子节点,算完成一次堆调整。
            做一次堆调整的时间复杂度为lgn,从二叉树的根节点到叶子结点,树的深度为lgn,也就是需要下沉的最大次数为lgn。
            三,堆的建立
            建堆是一个通过不断的堆调整,使得整个二叉树满足堆性质的操作。在数组中,我们一般从下标n/2的数开始作调整,一直到下标为0的数
            疑问:为什么是从n/2的数开始?因为下标大于n/2的数都是叶子节点,其子树已经满足堆的性质,所以不用再调整了。下图为一个小根堆的建立图示:
        </p>
        <img src="./img/小根堆建立图.jpg" alt="">
        <img src="./img/小根堆建立图2.jpg" alt="">
        <p>
            四,堆的排序
            堆的排序是堆建立完成之后进行的,假设数组存储成大根堆的形式之后
            第一次将A[0]与A[n-1]交换,然后将A[0~n-2]数组进行堆恢复操作(做堆调整)。
            第二次将A[0]与A[n-2]交换,然后将A[0~n-3]数组进行堆恢复操作(做堆调整)。
            重复这样的操作,直到A[0]与A[1]交换,排序结束。
            由于每次都是将最大的数并入到后面的有序区间,所以整个数组是有序的,上述步骤产生的是升序排列。一个大根堆排序过程的示意图:
        </p>
        <img src="./img/大根堆排序过程示意图.jpg" alt="">
        <img src="./img/大根堆排序过程示意图2.jpg" alt="">
        <img src="./img/大根堆排序过程示意图3.jpg" alt="">
        <img src="./img/大根堆排序过程示意图4.jpg" alt="">
        <p>
            五,堆排序性能分析
            堆排序时间=建堆时间+堆恢复时间
            建堆时间:建堆的过程就是堆不断调整的过程,前面分析过一次堆调整的时间复杂度为O(lgn),堆建立过程调整了n/2次,因此时间复杂度是O(nlgn).
            堆恢复时间:堆恢复操作共进行了n-1次堆调整操作,因此,时间复杂度是O(nlgn)
            综上得:堆排序的最差、最优、平均时间复杂度均是O(nlgn) 不稳定
    
            “空间复杂度”指占内存大小,堆排序每次只对一个元素操作,是就地排序,所以空间复杂度是O(1)
        </p>
    </body>
    <script src="./js"></script>
    <script>
    /**
    *
    *@Description:堆排序
    *@param arr
    *@author  肖芳
    */
    function headSort(arr){
      buildHeap(arr)//构建堆
      let len = arr.length
      for(let i=len-1;i>0;i--){
        swap(arr,0,i)//交换堆的第一个元素和最后一个元素
        heapify(arr,i)//调整堆
      }
      return arr
    }
    /**
    *
    *@Description:创建堆
    *@param arr
    *@author  肖芳
    */
    function buildHeap(arr){
      let len = arr.length
      if(len === 0)
        return
      for(let i=Math.floor(len/2);i>0;i--){
        heapify(arr,i)
      }
    }
    /**
    *
    *@Description:调整堆
    *@param arr 调整数组
    *@param i 跟
    *@author  肖芳
    */
    function heapify(arr,i){
      const left = 2 * i + 1
      const right = 2 * i + 2
      let largest = i
      const len = arr.length
      if(left <len && arr[left]>arr[largest]){//先判断左节点还否超出
        largest=left
      }
      if(right <len && arr[right]>largest){//有节点是否超出 找出最大的子节点
        largest=right
      }
      if(largest !== i){
        swap(arr,i,largest)//交换 largrst为i
        heapify(arr,largest)//递归调整
      }
    }
    /**
    *
    *@Description:交换
    *@param arr
    *@author  肖芳
    */
    function swap(arr,i,j){
      let temp=arr[i]
      arr[i] = arr[j]
      arr[j] = temp
    }
    </script>
    </html>
    

    8.基数排序

    参考网址:https://www.cnblogs.com/0603ljx/p/4379418.html  

      

      

      

      

      

      

  • 相关阅读:
    【SQL】SQL Server登录常见问题
    【毒思】纪念我死去的爱情
    【毒思】化蝶双飞
    VS2013常用快捷键你敢不会?
    SSIS 更新变量
    一次SSIS Package的调试经历
    binary 和 varbinary 用法全解
    Execute SQL Task 第二篇:返回结果集
    OLEDB 命令转换组件的用法
    脚本组件的用法
  • 原文地址:https://www.cnblogs.com/sxdjy/p/12986100.html
Copyright © 2011-2022 走看看