参考博客: https://www.cnblogs.com/Unknw/p/6346681.html#4195503

十大经典算法

一张图概括:

名词解释:

n:数据规模

k:“桶”的个数

In-place:占用常数内存,不占用额外内存

Out-place:占用额外内存

稳定性:排序后2个相等键值的顺序和排序之前它们的顺序相同

冒泡排序

作为最简单的排序算法之一,冒泡排序给我的感觉就像Abandon在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。。。冒泡排序还有一种优化算法,就是立一个flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来说并没有什么太大作用。。。

什么时候最快

当输入的数据已经是正序时(都已经是正序了,我还要你冒泡排序有何用啊。。。。)

什么时候最慢

当输入的数据是反序时(写一个for循环反序输出数据不就行了,干嘛要用你冒泡排序呢,我是闲的吗。。。)

冒泡排序动图演示

JavaScript代码实现
 复制function bubbleSort(arr) { var len = arr.length; for (var i = 0; i < len; i++) { for (var j = 0; j < len - 1 - i; j++) { if (arr[j] > arr[j+1]) { //相邻元素两两对比 var temp = arr[j+1]; //元素交换 arr[j+1] = arr[j]; arr[j] = temp; } } } return arr; }

选择排序

表现最稳定的排序算法之一,因为无论什么数据进去都是O(n²)的时间复杂度。。。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

选择排序动图演示

JavaScript代码实现
 复制function selectionSort(arr) { var len = arr.length; var minIndex, temp; for (var i = 0; i < len - 1; i++) { minIndex = i; for (var j = i + 1; j < len; j++) { if (arr[j] < arr[minIndex]) { //寻找最小的数 minIndex = j; //将最小数的索引保存 } } temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } return arr; }

插入排序

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。当然,如果你说你打扑克牌摸牌的时候从来不按牌的大小整理牌,那估计这辈子你对插入排序的算法都不会产生任何兴趣了。。。

插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。对于这种算法,得了懒癌的我就套用教科书上的一句经典的话吧:感兴趣的同学可以在课后自行研究。。。

插入排序动图演示

JavaScript代码实现
 复制function insertionSort(arr) { var len = arr.length; var preIndex, current; for (var i = 1; i < len; i++) { preIndex = i - 1; current = arr[i]; while(preIndex >= 0 && arr[preIndex] > current) { arr[preIndex+1] = arr[preIndex]; preIndex--; } arr[preIndex+1] = current; } return arr; }

希尔排序

希尔排序是插入排序的一种更高效率的实现。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版》的合著者Robert Sedgewick提出的。在这里,我就使用了这种方法。

JavaScript代码实现
 复制function shellSort(arr) { var len = arr.length, temp, gap = 1; while(gap < len/3) { //动态定义间隔序列 gap =gap*3+1; } for (gap; gap > 0; gap = Math.floor(gap/3)) { for (var i = gap; i < len; i++) { temp = arr[i]; for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) { arr[j+gap] = arr[j]; } arr[j+gap] = temp; } } return arr; }

归并排序

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第2种方法)
  • 自下而上的迭代

在《数据结构与算法JavaScript描述》中,作者给出了自下而上的迭代方法。但是对于递归法,作者却认为:

However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle.

然而,在 JavaScript 中这种方式不太可行,因为这个算法的递归深度对它来讲太深了。

说实话,我不太理解这句话。意思是JavaScript编译器内存太小,递归太深容易造成内存溢出吗?还望有大神能够指教。

和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

归并排序动图演示

归并排序JavaScript代码实现:
 复制function mergeSort(arr) { //采用自上而下的递归方法 var len = arr.length; if(len < 2) { return arr; } var middle = Math.floor(len / 2), left = arr.slice(0, middle), right = arr.slice(middle); return merge(mergeSort(left), mergeSort(right)); } function merge(left, right) { var result = []; while (left.length && right.length) { if (left[0] <= right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result; }

快速排序

快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高! 它是处理大数据最快的排序算法之一了。虽然Worst Case的时间复杂度达到了O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为O(n log n) 的排序算法表现要更好,可是这是为什么呢,我也不知道。。。好在我的强迫症又犯了,查了N多资料终于在《算法艺术与信息学竞赛》上找到了满意的答案:

快速排序的最坏运行情况是O(n²),比如说顺序数列的快排。但它的平摊期望时间是O(n log n) ,且O(n log n)记号中隐含的常数因子很小,比复杂度稳定等于O(n log n)的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

快速排序动图演示

快速排序JavaScript代码实现:
 复制function quickSort(arr, left, right) { var len = arr.length, partitionIndex, left = typeof left != 'number' ? 0 : left, right = typeof right != 'number' ? len - 1 : right; if (left < right) { partitionIndex = partition(arr, left, right); quickSort(arr, left, partitionIndex-1); quickSort(arr, partitionIndex+1, right); } return arr; } function partition(arr, left ,right) { //分区操作 var pivot = left, //设定基准值(pivot) index = pivot + 1; for (var i = index; i <= right; i++) { if (arr[i] < arr[pivot]) { swap(arr, i, index); index++; } } swap(arr, pivot, index - 1); return index-1; } function swap(arr, i, j) { var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }

堆排序

堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列
堆排序动图演示

堆排序JavaScript代码实现:
 复制var len;    //因为声明的多个函数都需要数据长度,所以把len设置成为全局变量 function buildMaxHeap(arr) { //建立大顶堆 len = arr.length; for (var i = Math.floor(len/2); i >= 0; i--) { heapify(arr, i); } } function heapify(arr, i) { //堆调整 var left = 2 * i + 1, right = 2 * i + 2, largest = i; if (left < len && arr[left] > arr[largest]) { largest = left; } if (right < len && arr[right] > arr[largest]) { largest = right; } if (largest != i) { swap(arr, i, largest); heapify(arr, largest); } } function swap(arr, i, j) { var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } function heapSort(arr) { buildMaxHeap(arr); for (var i = arr.length-1; i > 0; i--) { swap(arr, 0, i); len--; heapify(arr, 0); } return arr; }
计数排序

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

计数排序动图演示

计数排序JavaScript代码实现:
 复制function countingSort(arr, maxValue) { var bucket = new Array(maxValue+1), sortedIndex = 0; arrLen = arr.length, bucketLen = maxValue + 1; for (var i = 0; i < arrLen; i++) { if (!bucket[arr[i]]) { bucket[arr[i]] = 0; } bucket[arr[i]]++; } for (var j = 0; j < bucketLen; j++) { while(bucket[j] > 0) { arr[sortedIndex++] = j; bucket[j]--; } } return arr; }

桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。

为了使桶排序更加高效,我们需要做到这两点:

  1. 在额外空间充足的情况下,尽量增大桶的数量
  2. 使用的映射函数能够将输入的N个数据均匀的分配到K个桶中

同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。

什么时候最快

当输入的数据可以均匀的分配到每一个桶中

什么时候最慢

当输入的数据被分配到了同一个桶中

桶排序JavaScript代码实现:
 复制function bucketSort(arr, bucketSize) { if (arr.length === 0) { return arr; } var i; var minValue = arr[0]; var maxValue = arr[0]; for (i = 1; i < arr.length; i++) { if (arr[i] < minValue) { minValue = arr[i]; //输入数据的最小值 } else if (arr[i] > maxValue) { maxValue = arr[i]; //输入数据的最大值 } } //桶的初始化 var DEFAULT_BUCKET_SIZE = 5; //设置桶的默认数量为5 bucketSize = bucketSize || DEFAULT_BUCKET_SIZE; var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; var buckets = new Array(bucketCount); for (i = 0; i < buckets.length; i++) { buckets[i] = []; } //利用映射函数将数据分配到各个桶中 for (i = 0; i < arr.length; i++) { buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]); } arr.length = 0; for (i = 0; i < buckets.length; i++) { insertionSort(buckets[i]); //对每个桶进行排序,这里使用了插入排序 for (var j = 0; j < buckets[i].length; j++) { arr.push(buckets[i][j]); } } return arr; 

转载于:https://www.cnblogs.com/xumBlog/p/10827786.html

JavaScript实现10大算法可视化相关推荐

  1. 细数二十世纪最伟大的10大算法

    导读:作者July总结了一篇关于计算方法的文章< 细数二十世纪最伟大的10大算法 >. 一.1946 蒙特卡洛方法 [1946: John von Neumann, Stan Ulam, ...

  2. 干货丨机器学习新手一定要掌握的10大算法

    文章来源:机器之心 本文介绍了机器学习新手需要了解的 10 大算法,包括线性回归.Logistic 回归.朴素贝叶斯.K 近邻算法等. 在机器学习中,有一种叫做「没有免费的午餐」的定理.简而言之,它指 ...

  3. 编程面试过程中最常见的10大算法

    编程面试过程中最常见的10大算法 编程语言:C/C++ 1. 字符串 如果IDE没有代码自动补全功能,所以你应该记住下面的这些方法. toCharArray() // 获得字符串对应的char数组 A ...

  4. 编程面试的10大算法概念汇总

    编程面试的10大算法概念汇总 嘿,第一次翻译文章,在ProgramCreek看到的,原文章名为Top 10 Algorithms for Coding Interview, 对于我这个明年即将直奔BA ...

  5. 数学狂想曲(三)——统计杂谈, PID算法, 20世纪10大算法, 矩阵向量的积

    http://antkillerfarm.github.io/ 统计杂谈 统计模拟 统计模拟是数理统计中非常有用的工具之一, 它是利用计算机产生某概率模型的随机数,再通过这些随机数来模拟真实模型. 这 ...

  6. 代码面试最常用的10大算法

    摘要:面试也是一门学问,在面试之前做好充分的准备则是成功的必须条件,而程序员在代码面试时,常会遇到编写算法的相关问题,比如排序.二叉树遍历等等. 在程序员的职业生涯中,算法亦算是一门基础课程,尤其是在 ...

  7. 面试10大算法汇总+常见题目解答

    http://www.programcreek.com/2012/12/%E9%9D%A2%E8%AF%9510%E5%A4%A7%E7%AE%97%E6%B3%95%E6%B1%87%E6%80%B ...

  8. 20 世纪 10 大算法

    1. 蒙特卡洛采样算法 2. 矩阵运算相关 Krylov子空间迭代法 求解如下形式的线性方程组 Ax=bAx=b,当方阵 An×nA_{n\times n} nn 足够大时,算术解 x=A∖bx=A\ ...

  9. 数据挖掘10大算法(1)——PageRank

    1. 前言 这系列的文章主要讲述2006年评出的数据挖掘10大算法(见图1).文章的重点将偏向于算法的来源以及算法的主要思想,不涉及具体的实现.如果发现文中有错,希望各位指出来,一起讨论. 图1 来自 ...

最新文章

  1. 383. Ransom Note/691. Stickers to Spell Word-- String, Map, back tracking-- 未完待续
  2. Softmax v.s. LogSoftmax
  3. UC伯克利发现「没有免费午餐定理」加强版:每个神经网络,都是一个高维向量...
  4. python简笔画绘制 数据驱动绘图_pytorch visdom可视化工具学习—2—详细使用-2-plotting绘图...
  5. UVA 12266 Stock prices --优先队列
  6. htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
  7. php用什么做缓存文件格式,怎么用php语言来做文件缓存
  8. 设备坐标与逻辑坐标关系
  9. VTLN(Vocal Tract Length Normalisation)
  10. [LeetCode] Majority Element II
  11. GetCurrentTime(),GetLocalTime(),GetSystemTime()之间的区别
  12. CentOS 逻辑卷扩容
  13. Spark 学习路线
  14. 第七周博客作业西北师范大学|李晓婷
  15. 常见程序(discuz,ecshop,shopex,dedecms等)重置破解管理密码
  16. powershell过滤查询结果
  17. 2022最新常用API接口
  18. python已知两条直角边求斜边_Python实现已知三角形两直角边,求斜边--思路,伪代码,优化...
  19. 程序员七夕特刊,绝无狗粮添加
  20. LVS NAT模式搭建

热门文章

  1. oracle数据库函数手册,oracle函数大全连载(四)T
  2. 学院后勤报修系统php_如何有效提升医院医疗设备故障报修问题?
  3. 丹佛大学计算机科学专业,丹佛大学
  4. zigbee传输速率_wifi智能开关和zigbee智能开关有哪些区别
  5. python数据结构基础知识点二分查找
  6. java泛型(三)、通配符的使用
  7. 零基础学前端开发技术之第七章 浮动塌陷
  8. 比较两个日期大小和获取当前月最大天数的存储过程
  9. 深入浅出KNN算法(二) sklearn KNN实践
  10. java验证生日的正则表达式