iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript十大排序的算法是什么
  • 709
分享到

JavaScript十大排序的算法是什么

2024-04-02 19:04:59 709人浏览 八月长安
摘要

这篇文章主要讲解了“javascript十大排序的算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript十大排序的算法是什么”吧!冒泡

这篇文章主要讲解了“javascript十大排序算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript十大排序的算法是什么”吧!

JavaScript十大排序的算法是什么

冒泡排序

通过相邻元素的比较和交换,使得每一趟循环都能找到未有序数组的最大值或最小值。

最好:O(n),只需要冒泡一次数组就有序了。

最坏:O(n²)

平均:O(n²)

单向冒泡

1.  function bubbleSort(nums) {  
2.  for(let i=0, len=nums.length; i<len-1; i++) {  
3.  // 如果一轮比较中没有需要交换的数据,则说明数组已经有序。主要是对[5,1,2,3,4]之类的数组进行优化  
4.  let mark = true;  
5.  for(let j=0; j<len-i-1; j++) {  
6.  if(nums[j] > nums[j+1]) {  
7.  [nums[j], nums[j+1]] = [nums[j+1], nums[j]];  
8.  mark = false;  
9.  }  
10.  }  
11.  if(mark)  return;  
12.  }  
13.  }

一个人学习会有迷茫,动力不足。这里推荐一下我的前端学习交流群:731771211 ,里面都是学习前端的,如果你想制作酷炫的网页,想学习编程。自己整理了一份2019最全面前端学习资料,从最基础的html+CSS+js【炫酷特效,游戏,插件封装,设计模式】到移动端HTML5项目实战的学习资料都有整理,送给每一位前端小伙伴,有想学习web前端的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入学习。

双向冒泡

普通的冒泡排序在一趟循环中只能找出一个最大值或最小值,双向冒泡则是多一轮循环既找出最大值也找出最小值。

1.  function bubbleSort_twoWays(nums) {  
2.  let low = 0;  
3.  let high = nums.length - 1;  
4.  while(low < high) {  
5.  let mark = true;  
6.  // 找到最大值放到右边  
7.  for(let i=low; i<high; i++) {  
8.  if(nums[i] > nums[i+1]) {  
9.  [nums[i], nums[i+1]] = [nums[i+1], nums[i]];  
10.  mark = false;  
11.  }  
12.  }  
13.  high--;  
14.  // 找到最小值放到左边  
15.  for(let j=high; j>low; j--) {  
16.  if(nums[j] < nums[j-1]) {  
17.  [nums[j], nums[j-1]] = [nums[j-1], nums[j]];  
18.  mark = false;  
19.  }  
20.  }  
21.  low++;  
22.  if(mark)  return;  
23.  }  
24.  }

选择排序

和冒泡排序相似,区别在于选择排序是将每一个元素和它后面的元素进行比较和交换。

最好:O(n²)

最坏:O(n²)

平均:O(n²)

1.  function selectSort(nums) {  
2.  for(let i=0, len=nums.length; i<len; i++) {  
3.  for(let j=i+1; j<len; j++) {  
4.  if(nums[i] > nums[j]) {  
5.  [nums[i], nums[j]] = [nums[j], nums[i]];  
6.  }  
7.  }  
8.  }  
9.  }

插入排序

以第一个元素作为有序数组,其后的元素通过在这个已有序的数组中找到合适的位置并插入。

最好:O(n),原数组已经是升序的。

最坏:O(n²)

平均:O(n²)

1.  function insertSort(nums) {  
2.  for(let i=1, len=nums.length; i<len; i++) {  
3.  let temp = nums[i];  
4.  let j = i;  
5.  while(j >= 0 && temp < nums[j-1]) {  
6.  nums[j] = nums[j-1];  
7.  j--;  
8.  }  
9.  nums[j] = temp;  
10.  }  
11.  }

快速排序

选择一个元素作为基数(通常是第一个元素),把比基数小的元素放到它左边,比基数大的元素放到它右边(相当于二分),再不断递归基数左右两边的序列。

最好:O(n * logn),所有数均匀分布在基数的两边,此时的递归就是不断地二分左右序列。

最坏:O(n²),所有数都分布在基数的一边,此时划分左右序列就相当于是插入排序。

平均:O(n * logn)

快速排序之填坑

从右边向中间推进的时候,遇到小于基数的数就赋给左边(一开始是基数的位置),右边保留原先的值等之后被左边的值填上。

1.  function quickSort(nums) {  
2.  // 递归排序基数左右两边的序列  
3.  function recursive(arr, left, right) {  
4.  if(left >= right)  return;  
5.  let index = partition(arr, left, right);  
6.  recursive(arr, left, index - 1);  
7.  recursive(arr, index + 1, right);  
8.  return arr;  
9.  }  
10.  // 将小于基数的数放到基数左边,大于基数的数放到基数右边,并返回基数的位置  
11.  function partition(arr, left, right) {  
12.  // 取第一个数为基数  
13.  let temp = arr[left];  
14.  while(left < right) {  
15.  while(left < right && arr[right] >= temp)  right--;  
16.  arr[left] = arr[right];  
17.  while(left < right && arr[left] < temp)  left++;  
18.  arr[right] = arr[left];  
19.  }  
20.  // 修改基数的位置  
21.  arr[left] = temp;  
22.  return left;  
23.  }  
24.  recursive(nums, 0, nums.length-1);  
25.  }

快速排序之交换

从左右两边向中间推进的时候,遇到不符合的数就两边交换值。

1.  function quickSort1(nums) {  
2.  function recursive(arr, left, right) {  
3.  if(left >= right)  return;  
4.  let index = partition(arr, left, right);  
5.  recursive(arr, left, index - 1);  
6.  recursive(arr, index + 1, right);  
7.  return arr;  
8.  }  
9.  function partition(arr, left, right) {  
10.  let temp = arr[left];  
11.  let p = left + 1;  
12.  let q = right;  
13.  while(p <= q) {  
14.  while(p <= q && arr[p] < temp)  p++;  
15.  while(p <= q && arr[q] > temp)  q--;  
16.  if(p <= q) {  
17.  [arr[p], arr[q]] = [arr[q], arr[p]];  
18.  // 交换值后两边各向中间推进一位  
19.  p++;  
20.  q--;  
21.  }  
22.  }  
23.  // 修改基数的位置  
24.  [arr[left], arr[q]] = [arr[q], arr[left]];  
25.  return q;  
26.  }  
27.  recursive(nums, 0, nums.length-1);  
28.  }

归并排序

递归将数组分为两个序列,有序合并这两个序列。

最好:O(n * logn)

最坏:O(n * logn)

平均:O(n * logn)

1.  function mergeSort(nums) {  
2.  // 有序合并两个数组  
3.  function merge(l1, r1, l2, r2) {  
4.  let arr = [];  
5.  let index = 0;  
6.  let i = l1, j = l2;  
7.  while(i <= r1 && j <= r2) {  
8.  arr[index++] = nums[i] < nums[j] ? nums[i++] : nums[j++];  
9.  }  
10.  while(i <= r1)  arr[index++] = nums[i++];  
11.  while(j <= r2)  arr[index++] = nums[j++];  
12.  // 将有序合并后的数组修改回原数组  
13.  for(let t=0; t<index; t++) {  
14.  nums[l1 + t] = arr[t];  
15.  }  
16.  }  
17.  // 递归将数组分为两个序列  
18.  function recursive(left, right) {  
19.  if(left >= right)  return;  
20.  // 比起(left+right)/2,更推荐下面这种写法,可以避免数溢出  
21.  let mid = parseInt((right - left) / 2) + left;  
22.  recursive(left, mid);  
23.  recursive(mid+1, right);  
24.  merge(left, mid, mid+1, right);  
25.  return nums;  
26.  }  
27.  recursive(0, nums.length-1);  
28.  }

桶排序

取 n 个桶,根据数组的最大值和最小值确认每个桶存放的数的区间,将数组元素插入到相应的桶里,最后再合并各个桶。

最好:O(n),每个数都在分布在一个桶里,这样就不用将数插入排序到桶里了(类似于计数排序以空间换时间)。

最坏:O(n²),所有的数都分布在一个桶里。

平均:O(n + k),k表示桶的个数。

1.  function bucketSort(nums) {  
2.  // 桶的个数,只要是正数即可  
3.  let num = 5;  
4.  let max = Math.max(...nums);  
5.  let min = Math.min(...nums);  
6.  // 计算每个桶存放的数值范围,至少为1,  
7.  let range = Math.ceil((max - min) / num) || 1;  
8.  // 创建二维数组,第一维表示第几个桶,第二维表示该桶里存放的数  
9.  let arr = Array.from(Array(num)).map(() => Array().fill(0));  
10.  nums.forEach(val => {  
11.  // 计算元素应该分布在哪个桶  
12.  let index = parseInt((val - min) / range);  
13.  // 防止index越界,例如当[5,1,1,2,0,0]时index会出现5  
14.  indexindex = index >= num ? num - 1 : index;  
15.  let temp = arr[index];  
16.  // 插入排序,将元素有序插入到桶中  
17.  let j = temp.length - 1;  
18.  while(j >= 0 && val < temp[j]) {  
19.  temp[j+1] = temp[j];  
20.  j--;  
21.  }  
22.  temp[j+1] = val;  
23.  })  
24.  // 修改回原数组  
25.  let res = [].concat.apply([], arr);  
26.  nums.forEach((val, i) => {  
27.  nums[i] = res[i];  
28.  })  
29.  }

基数排序

使用十个桶 0-9,把每个数从低位到高位根据位数放到相应的桶里,以此循环最大值的位数次。但只能排列正整数,因为遇到负号和小数点无法进行比较。

最好:O(n * k),k表示最大值的位数。

最坏:O(n * k)

平均:O(n * k)

1.  function radixSort(nums) {  
2.  // 计算位数  
3.  function getDigits(n) {  
4.  let sum = 0;  
5.  while(n) {  
6.  sum++;  
7.  n = parseInt(n / 10);  
8.  }  
9.  return sum;  
10.  }  
11.  // 第一维表示位数即0-9,第二维表示里面存放的值  
12.  let arr = Array.from(Array(10)).map(() => Array());  
13.  let max = Math.max(...nums);  
14.  let maxDigits = getDigits(max);  
15.  for(let i=0, len=nums.length; i<len; i++) {  
16.  // 用0把每一个数都填充成相同的位数  
17.  nums[i] = (nums[i] + '').padStart(maxDigits, 0);  
18.  // 先根据个位数把每一个数放到相应的桶里  
19.  let temp = nums[i][nums[i].length-1];  
20.  arr[temp].push(nums[i]);  
21.  }  
22.  // 循环判断每个位数  
23.  for(let i=maxDigits-2; i>=0; i--) {  
24.  // 循环每一个桶  
25.  for(let j=0; j<=9; j++) {  
26.  let temp = arr[j]  
27.  let len = temp.length;  
28.  // 根据当前的位数i把桶里的数放到相应的桶里  
29.  while(len--) {  
30.  let str = temp[0];  
31.  temp.shift();  
32.  arr[str[i]].push(str);  
33.  }  
34.  }  
35.  }  
36.  // 修改回原数组  
37.  let res = [].concat.apply([], arr);  
38.  nums.forEach((val, index) => {  
39.  nums[index] = +res[index];  
40.  })   
41.  }

计数排序

以数组元素值为键,出现次数为值存进一个临时数组,最后再遍历这个临时数组还原回原数组。因为 JavaScript 的数组下标是以字符串形式存储的,所以计数排序可以用来排列负数,但不可以排列小数。

最好:O(n + k),k是最大值和最小值的差。

最坏:O(n + k)

平均:O(n + k)

1.  function countingSort(nums) {  
2.  let arr = [];  
3.  let max = Math.max(...nums);  
4.  let min = Math.min(...nums);  
5.  // 装桶  
6.  for(let i=0, len=nums.length; i<len; i++) {  
7.  let temp = nums[i];  
8.  arr[temp] = arr[temp] + 1 || 1;  
9.  }  
10.  let index = 0;  
11.  // 还原原数组  
12.  for(let i=min; i<=max; i++) {  
13.  while(arr[i] > 0) {  
14.  nums[index++] = i;  
15.  arr[i]--;  
16.  }  
17.  }  
18.  }

计数排序优化

把每一个数组元素都加上 min 的相反数,来避免特殊情况下的空间浪费,通过这种优化可以把所开的空间大小从 max+1 降低为 max-min+1,max 和 min 分别为数组中的最大值和最小值。

比如数组 [103, 102, 101, 100],普通的计数排序需要开一个长度为 104 的数组,而且前面 100 个值都是 undefined,使用该优化方法后可以只开一个长度为 4 的数组。

1.  function countingSort(nums) {  
2.  let arr = [];  
3.  let max = Math.max(...nums);  
4.  let min = Math.min(...nums);  
5.  // 加上最小值的相反数来缩小数组范围  
6.  let add = -min;  
7.  for(let i=0, len=nums.length; i<len; i++) {  
8.  let temp = nums[i];  
9.  temp += add;  
10.  arr[temp] = arr[temp] + 1 || 1;  
11.  }  
12.  let index = 0;  
13.  for(let i=min; i<=max; i++) {  
14.  let temp = arr[i+add];  
15.  while(temp > 0) {  
16.  nums[index++] = i;  
17.  temp--;  
18.  }  
19.  }  
20.  }

堆排序

根据数组建立一个堆(类似完全二叉树),每个结点的值都大于左右结点(最大堆,通常用于升序),或小于左右结点(最小堆,通常用于降序)。对于升序排序,先构建最大堆后,交换堆顶元素(表示最大值)和堆底元素,每一次交换都能得到未有序序列的最大值。重新调整最大堆,再交换堆顶元素和堆底元素,重复 n-1 次后就能得到一个升序的数组。

最好:O(n * logn),logn是调整最大堆所花的时间。

最坏:O(n * logn)

平均:O(n * logn)

1.  function heapSort(nums) {  
2.  // 调整最大堆,使index的值大于左右节点  
3.  function adjustHeap(nums, index, size) {  
4.  // 交换后可能会破坏堆结构,需要循环使得每一个父节点都大于左右结点  
5.  while(true) {  
6.  let max = index;  
7.  let left = index * 2 + 1;   // 左节点  
8.  let right = index * 2 + 2;  // 右节点  
9.  if(left < size && nums[max] < nums[left])  max = left;  
10.  if(right < size && nums[max] < nums[right])  max = right;  
11.  // 如果左右结点大于当前的结点则交换,并再循环一遍判断交换后的左右结点位置是否破坏了堆结构(比左右结点小了)  
12.  if(index !== max) {  
13.  [nums[index], nums[max]] = [nums[max], nums[index]];  
14.  index = max;  
15.  }  
16.  else {  
17.  break;  
18.  }  
19.  }  
20.  }  
21.  // 建立最大堆  
22.  function buildHeap(nums) {  
23.  // 注意这里的头节点是从0开始的,所以最后一个非叶子结点是 parseInt(nums.length/2)-1  
24.  let start = parseInt(nums.length / 2) - 1;  
25.  let size = nums.length;  
26.  // 从最后一个非叶子结点开始调整,直至堆顶。  
27.  for(let i=start; i>=0; i--) {  
28.  adjustHeap(nums, i, size);  
29.  }  
30.  }  
31.  buildHeap(nums);  
32.  // 循环n-1次,每次循环后交换堆顶元素和堆底元素并重新调整堆结构  
33.  for(let i=nums.length-1; i>0; i--) {  
34.  [nums[i], nums[0]] = [nums[0], nums[i]];  
35.  adjustHeap(nums, 0, i);  
36.  }  
37.  }

希尔排序

通过某个增量 gap,将整个序列分给若干组,从后往前进行组内成员的比较和交换,随后逐步缩小增量至 1。希尔排序类似于插入排序,只是一开始向前移动的步数从 1 变成了 gap。

最好:O(n * logn),步长不断二分。

最坏:O(n * logn)

平均:O(n * logn)

1.  function shellSort(nums) {  
2.  let len = nums.length;  
3.  // 初始步数  
4.  let gap = parseInt(len / 2);  
5.  // 逐渐缩小步数  
6.  while(gap) {  
7.  // 从第gap个元素开始遍历  
8.  for(let i=gap; i<len; i++) {  
9.  // 逐步其和前面其他的组成员进行比较和交换  
10.  for(let j=i-gap; j>=0; j-=gap) {  
11.  if(nums[j] > nums[j+gap]) {  
12.  [nums[j], nums[j+gap]] = [nums[j+gap], nums[j]];  
13.  }  
14.  else {  
15.  break;  
16.  }  
17.  }  
18.  }  
19.  gap = parseInt(gap / 2);  
20.  }  
21.  }

感谢各位的阅读,以上就是“JavaScript十大排序的算法是什么”的内容了,经过本文的学习后,相信大家对JavaScript十大排序的算法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: JavaScript十大排序的算法是什么

本文链接: https://www.lsjlt.com/news/85478.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript十大排序的算法是什么
    这篇文章主要讲解了“JavaScript十大排序的算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript十大排序的算法是什么”吧!冒泡...
    99+
    2024-04-02
  • JavaScript如何实现十大排序算法
    本文小编为大家详细介绍“JavaScript如何实现十大排序算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“JavaScript如何实现十大排序算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,...
    99+
    2024-04-02
  • JAVA十大排序算法之堆排序详解
    目录堆排序知识补充二叉树满二叉树完全二叉树二叉堆代码实现时间复杂度算法稳定性思考总结堆排序 这里的堆并不是JVM中堆栈的堆,而是一种特殊的二叉树,通常也叫作二叉堆。它具有以下特点: ...
    99+
    2024-04-02
  • JAVA十大排序算法之桶排序详解
    目录桶排序代码实现时间复杂度算法稳定性总结桶排序 桶排序是计数排序的升级,计数排序可以看成每个桶只存储相同元素,而桶排序每个桶存储一定范围的元素,通过函数的某种映射关系,将待排序数组...
    99+
    2024-04-02
  • Java十大排序算法之堆排序刨析
    二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性︰ 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最...
    99+
    2024-04-02
  • Java十大排序算法怎么实现
    本篇内容介绍了“Java十大排序算法怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!排序算法的稳定性:  &nbs...
    99+
    2023-06-29
  • TypeScript十大排序算法插入排序怎么实现
    今天小编给大家分享一下TypeScript十大排序算法插入排序怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一. 插...
    99+
    2023-07-05
  • JAVA十大排序算法之选择排序详解
    目录选择排序代码实现动图演示代码实现时间复杂度算法稳定性总结选择排序 1.找到数组中最大(或最小)的元素 2.将它和数组的第一个元素交换位置(如果第一个元素就是最大(小)元素那么它就...
    99+
    2024-04-02
  • JAVA十大排序算法之快速排序详解
    目录快速排序问题思路荷兰国旗问题代码实现时间复杂度算法稳定性总结快速排序 快速排序是对冒泡排序的一种改进,也是采用分治法的一个典型的应用。JDK中Arrays的sort()方法,具体...
    99+
    2024-04-02
  • JAVA十大排序算法之基数排序详解
    目录基数排序代码实现时间复杂度算法稳定性基数排序 vs 桶排序 vs 计数排序总结基数排序 常见的数据元素一般是由若干位组成的,比如字符串由若干字符组成,整数由若干位0~9数字组成。...
    99+
    2024-04-02
  • Java十大排序算法之计数排序刨析
    计数排序是非比较的排序算法,用辅助数组对数组中出现的数字计数,元素转下标,下标转元素 计数排序优缺点 优点:快 缺点:数据范围很大,比较稀疏,会导致辅助空间很大,造成空间的浪费 使用...
    99+
    2024-04-02
  • JAVA十大排序算法之插入排序详解
    目录插入排序代码实现动图演示代码实现时间复杂度算法稳定性总结插入排序 当我们在玩扑克牌的时候,总是在牌堆里面抽取最顶部的一张然后按顺序在手中排列。 插入排序是指在待排序的元素中,假设...
    99+
    2024-04-02
  • Java 十大排序算法之希尔排序刨析
    目录希尔排序原理希尔排序的API设计希尔排序的代码实现希尔排序是插入排序的一种,又称"缩小增量排序”,是插入排序算法的一种更高效的改进版本。 希尔排序原理 1.选定一个增长量h,按照...
    99+
    2024-04-02
  • Java 十大排序算法之选择排序刨析
    目录选择排序原理选择排序API设计选择排序代码实现选择排序的时间复杂度选择排序原理 ①假设第一个索引处的元素为最小值,和其他值进行比较,如果当前的索引处的元素大于其他某个索引处的值,...
    99+
    2024-04-02
  • Java 十大排序算法之归并排序刨析
    目录归并排序原理归并排序API设计归并排序代码实现归并排序的时间复杂度分析归并排序原理 1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元...
    99+
    2024-04-02
  • Java 十大排序算法之插入排序刨析
    目录插入排序原理插入排序API设计插入排序代码实现插入排序的时间复杂度分析插入排序原理 ①把所有元素分成已排序和未排序两组 ②找到未排序组的第一个元素,向已经排序的组中进行插入 ③倒...
    99+
    2024-04-02
  • Java 十大排序算法之冒泡排序刨析
    目录冒泡排序原理冒泡排序API设计冒泡排序的代码实现冒泡排序的时间复杂度分析冒泡排序原理 ①比较相邻的元素,如果前一个元素比后一个元素大,则交换这两个元素的位置 ②对每一对相邻的元素...
    99+
    2024-04-02
  • JAVA十大排序算法之冒泡排序详解
    目录冒泡排序代码实现代码实现时间复杂度算法稳定性总结冒泡排序 1.从数组头开始,比较相邻的元素。如果第一个比第二个大(小),就交换它们两个 2.对每一对相邻元素作同样的工作,从开始第...
    99+
    2024-04-02
  • JAVA十大排序算法之希尔排序详解
    目录希尔排序代码实现时间复杂度算法稳定性总结希尔排序 一种基于插入排序的快速的排序算法。简单插入排序对于大规模乱序数组很慢,因为元素只能一点一点地从数组的一端移动到另一端。例如,如果...
    99+
    2024-04-02
  • JAVA十大排序算法之归并排序详解
    目录归并排序怎么分怎么治代码实现时间复杂度算法稳定性总结归并排序 归并,指合并,合在一起。归并排序(Merge Sort)是建立在归并操作上的一种排序算法。其主要思想是分而治之。什么...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作