排序算法记录

前言:看过好大佬写的排序,终究是写了忘忘了写,发现过一段时间还是会忘记,记录在这里,忘了可以常看看~~有大哥发现是自己的代码,留言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  

  

  

  

  

  

  

原文地址:https://www.cnblogs.com/sxdjy/p/12986100.html