常用排序算法汇总

这篇具有很好参考价值的文章主要介绍了常用排序算法汇总。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 分类

  • 内部排序
    将所有数据加载到内部存储器中排序
  • 外部排序
    数据量过大,需要借助外部存储进行排序

2 算法性能

时间复杂度是用来描述算法运行时间的,那么该如何估计程序运行时间呢,通常会估算算法的操作单元数量来代表程序消耗的时间,也可以这样考虑,时间复杂度就是操作一个单元的次数。

这里上几个例子,
(1)对数阶

let i = 1
while(i<n){
  i = i * 3
}

n = 3^x,即x = log3(n),循环执行了x次,因此这里时间复杂度为对数阶
(2)线性对数阶

for(let j = 0; j < n; j++) {
  let i = 1
  while(i<n){
    i = i * 3
  }
}

也就是将时间复杂度为对数阶的代码重复了n次,所以线性对数阶

一般讨论时间复杂度都是在最坏情况下的时间复杂度

3 排序算法

3.1 交换排序

冒泡

如果数据有序,这里就会提前终止循环,这样就相当于只有外层一个遍历,所以最好情况的时间复杂度为O(n)

function fn(arr) {
  let len = arr.length
  // 优化:如果一趟循环,没有发生交换,说明数组有序,可以提前终止遍历
  let flag = false
  //外层循环控制趟数
  for (let i = 0; i < len - 1; i++) {
    //内层循环控制每趟需要交换的次数
    for (let j = 0; j < len - i - 1; j++) {
      // 从小到大
      if (arr[j] > arr[j + 1]) {
        flag = true
        ;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
      }
    }
    if (flag === false) {
      break
    } else {
      flag = false
    }
  }
  return arr
}

快速排序

快速排序的基本思想是找一个基准值,然后把小于基准值的元素放在一边,大于基准值的元素放在一边,然后在左右两边重复进行这样的操作

一个最简单的未优化的快速排序算法代码如下:

function sort(nums) {
  // 利用dfs解决快速排序问题(从小到大)
  function dfs(start, end) {
    // 当区间中只有一个元素时,就不用分区了
    if (start >= end) return

    // 把每个区间的最后一个元素作为基准(比基准小的放左边,大的放右边),实现分区,返回分区基准所在的位置,方便下次分区
    let temp = partition(start, end)
    dfs(start, temp - 1)
    dfs(temp + 1, end)
  }

  // 分区函数,利用的是双指针
  function partition(start, end) {
    // 最后一个元素作为基准
    let pivot = nums[end]
    // 快慢指针
    let less = start
    let great = start
    for (; great < end; great++) {
      // 比基准小的放左边,大的放右边
      if (nums[great] < pivot) {
        swap(nums, less, great)
        less++
      }
    }
    // 把基准元素放到对应位置
    swap(nums, less, end)
    return less
  }

  // 交换两个元素
  function swap(data, i, j) {
    let temp = data[i]
    data[i] = data[j]
    data[j] = temp
  }

  dfs(0, nums.length - 1)
}

3.2 选择排序

遍历所有元素,每遍历一个元素,都要拿到这个元素之后的元素的最小值,并替换当前元素

不稳定:举个例子,序列5 8 5 2 9

function fn(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    let index = i
    let min = arr[i]
    // 获取当前元素之后元素的最小值
    for (let j = i + 1; j < len; j++) {
      // 从小到大
      if (arr[j] < min) {
        min = arr[j]
        index = j
      }
    }
    // 如果当前值就是最小值,就不要换了
    if (index !== i) {
      ;[arr[i], arr[index]] = [arr[index], arr[i]]
    }
  }
  return arr
}

3.3 插入排序

直接插入

把数组分为一个有序表和一个无序表,遍历无序表,每遍历一个元素从有序表中找到合适位置插入(这里也就需要一个循环)

如果数据有序,就不会经过内层循环,这样就相当于只有外层一个遍历,所以最好情况的时间复杂度为O(n)

function fn(arr) {
  // 遍历无序表
  for (let i = 1; i < arr.length; i++) {
    let insertVal = arr[i]
    let insertIndex = i - 1
    // 遍历有序表,确定插入位置;从小到大
    //给insertVal找到插入位置
    //说明
    //1 insertIndex >= 0  保证在给insertVal 找插入位置的时候,不越界
    //2 insertVal < arr[insertIndex]  说明待插入的数,还没有找到插入位置
    //3 就需要将arr[insertIndex]  后移
    while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
      arr[insertIndex + 1] = arr[insertIndex]
      insertIndex--
    }
    //当退出while循环时,说明插入的位置找到
    arr[insertIndex + 1] = insertVal
  }
  return arr
}

arr = [2, 1, -3, 5]
console.log(fn(arr))

希尔排序

缩小增量的方式,当增量减为1的时候,算法结束

function fn(arr) {
  let len = arr.length
  // 本层循环控制需要几趟循环
  for (let gap = len / 2; gap > 0; gap = parseInt(gap / 2)) {
    //遍历各组中所有元素(共gap组,每组有10/gap个元素),步长gap
    for (let i = gap; i < len; i++) {
      for (let j = i - gap; j >= 0; j -= gap) {
        if (arr[j] > arr[j + gap]) {
          ;[arr[j], arr[j + gap]] = [arr[j + gap], arr[j]]
        }
      }
    }
  }
  return arr
}

3.4 归并排序

在递的时候不断将区间一分为二,直到每个区间只有一个元素;在归的时候,完成合并,在合并时要做顺序的调整

function sort(nums) {
  // 从小到大

  function dfs(start, end) {
    if (start >= end) return

    // 对数组区间不断一分为二,直到每个区间只有一个元素
    let mid = parseInt((start + end) / 2)
    dfs(start, mid)
    dfs(mid + 1, end)

    // 在归的时候,完成合并,在合并时要做顺序的调整
    merge(start, mid, end)
  }

  function merge(start, mid, end) {
    let temp = []
    // 需要两个指针,分别指向两个区间开始的位置
    let i = start
    let j = mid + 1
    // 操作temp的指针,直接使用temp.push()也是可以的
    let tmpPos = 0

    // 排序,把有序的元素保存到temp数组中
    while (i <= mid && j <= end) {
      if (nums[i] < nums[j]) {
        temp[tmpPos++] = nums[i++]
      } else {
        temp[tmpPos++] = nums[j++]
      }
    }

    // 若第一个区间还有元素,直接全部放进temp中
    while (i <= mid) {
      temp[tmpPos++] = nums[i++]
    }

    // 若第二个区间还有元素,直接全部放进temp中
    while (j <= end) {
      temp[tmpPos++] = nums[j++]
    }

    // temp数组拷贝给nums
    for (let i = 0; i < temp.length; i++) {
      nums[start++] = temp[i]
    }
  }

  dfs(0, nums.length - 1)
}

3.4 基数排序

4 小结

常用排序算法汇总,算法,排序算法,算法
注:图片来自于网络,如有侵权,请联系删除文章来源地址https://www.toymoban.com/news/detail-535749.html

  • 快速排序和归并排序都可以用递归来做,用迭代应该也可以,对于递归原理可以查看 递归(原理学习)

到了这里,关于常用排序算法汇总的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法】常用排序算法

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。 目录  一、常见排序算法  二、直接插入排序 1、直接插入排序思想 2、直接插入排序代码 二、希尔排序 1、希尔排序思想 2、

    2024年02月02日
    浏览(34)
  • C++,stl,常用排序算法,常用拷贝和替换算法

    目录 1.常用排序算法 sort random_shuffle merge reverse 2.常用拷贝和替换算法 copy replace replace_if swap 默认从小到大排序  使用的时候要加随机数种子            交换的容器要是同种类型

    2024年02月20日
    浏览(38)
  • 【数据结构与算法】常用排序算法对比

    常用排序算法对比 相关术语解释 : 稳定:如果 a 原本在 b 前面,而 a = b,排序之后 a 仍然在 b 的前面。 不稳定: 如果 a 原本在 b 前面,而 a = b,排序之后 a 可能出现在 b 的后面。 内排序:所有排序操作都在内存中完成。 外排序:由于数据太大,因此把数据放在磁盘中,而

    2024年02月15日
    浏览(47)
  • 常用排序算法

    目录 直接插入排序 希尔排序 ​编辑 选择排序 堆排序 冒泡排序 快速排序 hoare版 挖坑法 前后指针法 非递归 归并排序 非递归 计数排序 直接插入排序跟依次模扑克牌一样,将最后一张牌依次与前面的牌比较,最后将牌插入到指定位置 单趟排序: 将最后一个数依次与前面的数

    2024年02月08日
    浏览(34)
  • 常用排序算法的理解

    1.插入排序 插入排序的思想是将一个记录插入到已经排好序的有序表中,从而形成一个新的、记录数加1的有序表。在其实现过程使用双层循环,外层循环是进行插入的次数(也可以理解为比较的轮数),内层循环是当前记录查找插入有序表的位置,并进行移动(可以理解为每

    2024年02月07日
    浏览(36)
  • js 常用排序算法

    1、基本思想 一个数组arr=[9,5,8,4,7,3,2],冒泡就是从数组第一个值开始与依次与之后的值比较,如果是从小到大排序,那么9先和5比较,9大就换与5交换位置,再和8比较还大,再和8交换位置,继续。。。直到2还大,那么9放在了数组的最后,下一次比较的数组变为arr=[5,8,4,7,3,2,9

    2024年02月02日
    浏览(33)
  • 常用的排序算法

    GO实现 另一种实现 GO实现 GO实现 GO实现 GO实现 GO实现 有两种建堆方式:从顶向下O(n)(已知堆的大小),从底向上O(nlogn)(堆的大小动态调整) 参考博文:【堆/排序】堆排序的两种建堆方法 GO实现 相当于为每个数字安排一个桶 GO实现 一位一位的来处理数据,桶的数量固定为十个

    2024年02月13日
    浏览(28)
  • 软考——常用排序算法

    目录 1,直接插入排序 2,折半插入排序 3,希尔排序 4,冒泡排序 5,快速排序 6,简单选择排序 7,堆排序 8,归并排序  各种排序方法的特性 :   稳定性 : 若在待排序的一个序列中,Ri和Rj的关键码相同,即Ri=Rj,且在排序前Ri领先于Rj,那么当排序后,如果Ri和Rj的相对次序

    2024年02月06日
    浏览(31)
  • 几大常用的排序算法

    直接插入排序是一种简单的插入排序法,其基本思想是: 在待排序的元素中,假设 第一个元素已有序 ,现将后面的元素与第一个元素作比较,比第一个元素小插入到前面已经排好的序列中,使得前面的元素有序。按照此法对所有元素进行插入,直到整个序列有序为止 动图演

    2024年03月17日
    浏览(37)
  • 常用的排序算法(二)

    归并排序的时间复杂度为O(nlogn),在使用递归程序时,其额外空间复杂度为O(nlogn) 归并排序使用了一种叫做分而治之(Divide and conquer)的策略,将原本很庞大的数组排序问题分割成更小的子问题,在每一个子问题得到解决后,再合并它们。下面我们以数组arr[8]={9,2,4,6,3,

    2024年01月25日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包