当前位置: 首页 > 编程日记 > 正文

前端 排序算法总结

前言

排序算法可能是你学编程第一个学习的算法,还记得冒泡吗?

当然,排序和查找两类算法是面试的热门选项。如果你是一个会写快排的程序猿,面试官在比较你和一个连快排都不会写的人的时候,会优先选择你的。那么,前端需要会排序吗?答案是毋庸置疑的,必须会。现在的前端对计算机基础要求越来越高了,如果连排序这些算法都不会,那么发展前景就有限了。本篇将会总结一下,在前端的一些排序算法。如果你喜欢我的文章,欢迎评论,欢迎Star~。欢迎关注我的github博客

正文

首先,我们可以先来看一下js自身的排序算法sort()

Array.sort

相信每个使用js的都用过这个函数,但是,这个函数本身有些优点和缺点。我们可以通过一个例子来看一下它的功能:

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 31, 88, 12, 100, 50];console.log(arr.sort());   //[ 1, 10, 100, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88 ]console.log(arr.sort((item1, item2) => item1 - item2)); //[ 1, 10, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88, 100 ]复制代码

相信你也已经看出来它在处理上的一些差异了吧。首先,js中的sort会将排序的元素类型转化成字符串进行排序。不过它是一个高阶函数,可以接受一个函数作为参数。而我们可以通过传入内部的函数,来调整数组的升序或者降序。

sort函数的性能:相信对于排序算法性能来说,时间复杂度是至关重要的一个参考因素。那么,sort函数的算法性能如何呢?通过v8引擎的源码可以看出,Array.sort是通过javascript来实现的,而使用的算法是快速排序,但是从源码的角度来看,在实现上明显比我们所使用的快速排序复杂多了,主要是做了性能上的优化。所以,我们可以放心的使用sort()进行排序。

冒泡排序

冒泡排序,它的名字由来于一副图——鱼吐泡泡,泡泡越往上越大。

回忆起这个算法,还是最初大一的c++课上面。还是自己上台,在黑板上实现的呢!

思路:第一次循环,开始比较当前元素与下一个元素的大小,如果比下一个元素小或者相等,则不需要交换两个元素的值;若比下一个元素大的话,则交换两个元素的值。然后,遍历整个数组,第一次遍历完之后,相同操作遍历第二遍。

图例:

冒泡排序

代码实现:

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 31, 88, 12, 100, 50];function bubbleSort(arr){for(let i = 0; i < arr.length - 1; i++){for(let j = 0; j < arr.length - i - 1; j++){if(arr[j] > arr[j + 1]){swap(arr, j, j+1);}}}return arr;
}function swap(arr, i, j){let temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}
console.log(arr);复制代码

代码地址

性能:

  • 时间复杂度:平均时间复杂度是O(n^2)
  • 空间复杂度:由于辅助空间为常数,所以空间复杂度是O(1);

改进:

我们可以对冒泡排序进行改进,使得它的时间复杂度在大多数顺序的情况下,减小到O(n);

  1. 加一个标志位,如果没有进行交换,将标志位置为false,表示排序完成。

代码地址

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 31, 88, 12, 100, 50];function swap(arr, i, j){const temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}for(let i = 0; i < arr.length - 1; i++){let flag = false;for(let j = 0; j < arr.length - 1 - i; j++){if(arr[j] > arr[j+1]){swap(arr, j, j+1);flag = true;}}if(!flag){break;}
}console.log(arr);  //[ 1, 10, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88, 100 ]复制代码
  1. 记录最后一次交换的位置, 因为最后一次交换的数,是在这一次排序当中最大的数,之后的数都比它大。在最佳状态时,时间复杂度也会缩小到O(n);

代码地址

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 31, 88, 12, 100, 50 ,112];function swap(arr, i, j){let temp = arr[i];arr[i] = arr[j];arr[j] = temp
}function improveBubble(arr, len){for(let i = len - 1; i >= 0; i--){let pos = 0;for(let j = 0; j < i; j++){if(arr[j] > arr[j+1]){swap(arr, j, j+1);pos = j + 1;}}len = pos + 1;}return arr;
}console.log(improveBubble(arr, arr.length));  //[ 1, 10, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88, 100, 112 ]复制代码

选择排序

选择排序,即每次都选择最小的,然后换位置

思路:

第一遍,从数组中选出最小的,与第一个元素进行交换;第二遍,从第二个元素开始,找出最小的,与第二个元素进行交换;依次循环,完成排序

图例:

选择排序

代码实现:

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 31, 88, 12, 100, 50];function swap(arr, i, j){var temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}function selectionSort(arr){for(let i = 0; i < arr.length - 1; i++){let index = i;for(let j = i+1; j < arr.length; j++){if(arr[index] > arr[j]){index = j;}}swap(arr, i, index);}return arr;
}console.log(selectionSort(arr)); //[ 1, 10, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88, 100 ]复制代码

代码地址

性能:

  • 时间复杂度:平均时间复杂度是O(n^2),这是一个不稳定的算法,因为每次交换之后,它都改变了后续数组的顺序。

  • 空间复杂度:辅助空间是常数,空间复杂度为O(1);

插入排序

插入排序,即将元素插入到已排序好的数组中

思路:

首先,循环原数组,然后,将当前位置的元素,插入到之前已排序好的数组中,依次操作。

图例:

插入排序

代码实现:

const arr = [1, 20, 10, 30, 22, 11, 55, 24, 0, 31, 88, 12, 100, 50 ,112];function insertSort(arr){for(let i = 0; i < arr.length; i++){let temp = arr[i];for(let j = 0; j < i; j++){if(temp < arr[j] && j === 0){arr.splice(i, 1);arr.unshift(temp);break;}else if(temp > arr[j] && temp < arr[j+1] && j < i - 1){arr.splice(i, 1);arr.splice(j+1, 0, temp);break;}}}return arr;
}console.log(insertSort(arr));  //[ 0, 1, 10, 11, 12, 20, 22, 24, 30, 31, 50, 55, 88, 100, 112 ]复制代码

代码地址

性能:

  • 时间复杂度:平均算法复杂度为O(n^2)
  • 空间复杂度:辅助空间为常数,空间复杂度是O(1)

我们仨之间

其实,三个算法都是难兄难弟,因为算法的时间复杂度都是在O(n^2)。在最坏情况下,它们都需要对整个数组进行重新调整。只是选择排序比较不稳定。

快速排序

快速排序,从它的名字就应该知道它很快,时间复杂度很低,性能很好。它将排序算法的时间复杂度降低到O(nlogn)

思路:

首先,我们需要找到一个基数,然后将比基数小的值放在基数的左边,将比基数大的值放在基数的右边,之后进行递归那两组已经归类好的数组。

图例:

原图片太大,放一张小图,并且附上原图片地址,有兴趣的可以看一下:

快速排序

原图片地址

代码实现:

const arr = [30, 32, 6, 24, 37, 32, 45, 21, 38, 23, 47];function quickSort(arr){if(arr.length <= 1){return arr;}let temp = arr[0];const left = [];const right = [];for(var i = 1; i < arr.length; i++){if(arr[i] > temp){right.push(arr[i]);}else{left.push(arr[i]);}}return quickSort(left).concat([temp], quickSort(right));
}console.log(quickSort(arr));复制代码

代码地址

性能:

  • 时间复杂度:平均时间复杂度O(nlogn),只有在特殊情况下会是O(n^2),不过这种情况非常少
  • 空间复杂度:辅助空间是logn,所以空间复杂度为O(logn)

归并排序

归并排序,即将数组分成不同部分,然后注意排序之后,进行合并

思路:

首先,将相邻的两个数进行排序,形成n/2对,然后在每两对进行合并,不断重复,直至排序完。

图例:

归并排序

代码实现:

//迭代版本
const arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]function mergeSort(arr){const len = arr.length;for(let seg = 1; seg < len; seg += seg){let arrB = [];for(let start = 0; start < len; start += 2*seg){let row = start, mid = Math.min(start+seg, len), heig = Math.min(start + 2*seg, len);let start1 = start, end1 = mid;let start2 = mid, end2 = heig;while(start1 < end1 && start2 < end2){arr[start1] < arr[start2] ? arrB.push(arr[start1++]) : arrB.push(arr[start2++]);}while(start1 < end1){arrB.push(arr[start1++]);}while(start2 < end2){arrB.push(arr[start2++]);}}arr = arrB;}return arr;
}console.log(mergeSort(arr));复制代码

代码地址

//递归版
const arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];function mergeSort(arr, seg = 1){const len = arr.length;if(seg > len){return arr;}const arrB = [];for(var start = 0; start < len; start += 2*seg){let low = start, mid = Math.min(start+seg, len), heig = Math.min(start+2*seg, len);let start1 = low, end1 = mid;let start2 = mid, end2 = heig;while(start1 < end1 && start2 < end2){arr[start1] < arr[start2] ? arrB.push(arr[start1++]) : arrB.push(arr[start2++]);}while(start1 < end1){arrB.push(arr[start1++]);}while(start2 < end2){arrB.push(arr[start2++]);}}return mergeSort(arrB, seg * 2);
}console.log(mergeSort(arr));复制代码

代码地址

性能:

  • 时间复杂度:平均时间复杂度是O(nlogn)
  • 空间复杂度:辅助空间为n,空间复杂度为O(n)

基数排序

基数排序,就是将数的每一位进行一次排序,最终返回一个正常顺序的数组。

思路:

首先,比较个位的数字大小,将数组的顺序变成按个位依次递增的,之后再比较十位,再比较百位的,直至最后一位。

图例:

基数排序

代码实现:

const arr = [3221, 1, 10, 9680, 577, 9420, 7, 5622, 4793, 2030, 3138, 82, 2599, 743, 4127, 10000];function radixSort(arr){let maxNum = Math.max(...arr);let dis = 0;const len = arr.length;const count = new Array(10);const tmp = new Array(len);while(maxNum >=1){maxNum /= 10;dis++;}for(let i = 1, radix = 1; i <= dis; i++){for(let j = 0; j < 10; j++){count[j] = 0;}for(let j = 0; j < len; j++){let k = parseInt(arr[j] / radix) % 10;count[k]++;}for(let j = 1; j < 10; j++){count[j] += count[j - 1];}for(let j = len - 1; j >= 0 ; j--){let k = parseInt(arr[j] / radix) % 10;tmp[count[k] - 1] = arr[j];count[k]--;}for(let j = 0; j < len; j++){arr[j] = tmp[j]; }radix *= 10;}return arr;
}console.log(radixSort(arr));复制代码

代码地址

性能:

  • 时间复杂度:平均时间复杂度O(k*n),最坏的情况是O(n^2)

总结

我们一共实现了6种排序算法,对于前端开发来说,熟悉前面4种是必须的。特别是快排,基本面试必考题。本篇的内容总结分为六部分:

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 快速排序
  • 归并排序
  • 基数排序

排序算法,是算法的基础部分,需要明白它的原理,总结下来排序可以分为比较排序和统计排序两种方式,本篇前5种均为比较排序,基数排序属于统计排序的一种。希望看完的你,能够去动手敲敲代码,理解一下

如果你对我写的有疑问,可以评论,如我写的有错误,欢迎指正。你喜欢我的博客,请给我关注Star~呦。大家一起总结一起进步。欢迎关注我的github博客

相关文章:

django 快速实现登录

前言 对于web开来说&#xff0c;用户登陆、注册、文件上传等是最基础的功能&#xff0c;针对不同的web框架&#xff0c;相关的文章非常多&#xff0c;但搜索之后发现大多都不具有完整性&#xff0c;对于想学习web开发的新手来说不具有很强的操作性&#xff1b;对于web应用来说&…

“云智一体”的全场景智能视频技术是什么?

全视频时代到来&#xff0c;各行各业对视频的应用、体验和效能提出全新升级需求&#xff0c;AI与云计算的发展则为智能视频进入新阶段注入充足动力。5月13日&#xff0c;百度智能云“云智技术论坛-智能视频专场”活动在北京举行&#xff0c;重磅发布了智能视频云3.0全景图。百度…

背水一战 Windows 10 (18) - 绑定: 与 Element 绑定, 与 Indexer 绑定, TargetNullValue, FallbackValue...

原文:背水一战 Windows 10 (18) - 绑定: 与 Element 绑定, 与 Indexer 绑定, TargetNullValue, FallbackValue[源码下载] 背水一战 Windows 10 (18) - 绑定: 与 Element 绑定, 与 Indexer 绑定, TargetNullValue, FallbackValue作者&#xff1a;webabcd介绍背水一战 Windows 10…

2-sat问题,输出方案,几种方法(赵爽的论文染色解法+其完全改进版)浅析 / POJ3683...

本文原创于 2014-02-12 09:26。 今复习之用&#xff0c;有新体会&#xff0c;故重新编辑。 2014-02-12 09:26&#xff1a; 2-sat之第二斩&#xff01;昨天看了半天论文&#xff08;赵爽的和俉昱的&#xff09;&#xff0c;终于看明白了&#xff01;好激动有木有&#xff01;终…

C#方法/函数

本节课向你介绍C#的方法&#xff0c;其目的是&#xff1a; 1.了解方法的结构格式2.了解静态和实例方法之间的区别3.学会实例对象的使用4.学会如何调用实例化的对象5.学会方法的四种参数类型的使用6.学会使用"this"引用以往&#xff0c;对于每个程序来说&#xff0c;所…

Python 的一万种用法:生成字符视频

作者 | ZackSock来源 | 新建文件夹X头图 | 下载于视觉中国前言在之前也写过生成字符视频的文章&#xff0c;但是使用的是命令行窗口输出&#xff0c;效果不是很好&#xff0c;而且存在卡顿的情况。于是我打算直接生成一个mp4的字符视频。大致思路和之前一样&#xff1a;Python2…

Codeforces 862B - Mahmoud and Ehab and the bipartiteness

862B - Mahmoud and Ehab and the bipartiteness 思路&#xff1a;先染色&#xff0c;然后找一种颜色dfs遍历每一个点求答案。 代码&#xff1a; #include<bits/stdc.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,si…

C#表达式,类型和变量

本节课将介绍C# 语言的表达式&#xff0c;类型和变量。本节课要达到如下几个目的&#xff1a; 1.了解什么是"变量"2.学习C#的简单类型3.对C#表达式有个初步的了解4.了解什么是String类型5.学习如何使用数组"变量"仅仅是数据的存储位置。你可以把数据存放到…

张一鸣卸任CEO,立下10年之约,期望突破线性延伸

整理 | 寇雪芹头图 | 下载于视觉中国出品 | AI 科技大本营&#xff08;ID:rgznai100&#xff09;5月20日&#xff0c;字节跳动创始人张一鸣发布内部全员信&#xff0c;宣布卸任CEO&#xff0c;联合创始人梁汝波将接任这一职位。张一鸣在全员信中表示&#xff0c;“我决定卸任CE…

【译】使用Kotlin和RxJava测试MVP架构的完整示例 - 第1部分

原文链接&#xff1a;android.jlelse.eu/complete-ex… 最近我创建了一个playground项目来了解更多关于Kotlin和RxJava的信息。 这是一个非常简单的项目&#xff0c;但有一部分&#xff0c;我进行了一些尝试&#xff1a;测试。 在kotlin的测试上可能会有一些陷阱&#xff0c;而…

智能改变未来,创新引领世界,第二届深圳国际人工智能展暨智能制造创新高峰论坛盛大启幕!

2021年5月20日&#xff0c;由深圳市科学技术协会、深圳市商务局、深圳市福田区人民政府共同指导&#xff0c;深圳市科技开发交流中心、深圳市人工智能行业协会联合主办的2021第二届深圳国际人工智能展开幕式暨智能制造创新高峰论坛在深圳会展中心&#xff08;福田&#xff09;启…

C#循环控制语句

本节课将介绍如何使用C#控制语句中的循环语句&#xff0c;本课目的如下&#xff1a; 1.学会"while"循环的用法。2.学会"do" 循环的用法。3.学会"for" 循环的用法。4.学会foreach循环的用法。5.进一步了解"break"语句的用法。6.如何使用…

2017-09-22 前端日报

2017-09-22 前端日报 精选 JavaScript 在 V8 中的元素种类及性能优化【译】异步递归&#xff1a;回调、Promise、Async[译]HTML&CSS Lesson5: 定位一个页面阻塞问题的排查过程前端分享之cookie的使用及单点登录An event for CSS position:stickyanvaka/ngraph.path: Path f…

C#选择控制语句

本节课将介绍如何使用C#选择控制语句&#xff0c;第三课将达到如下几个目的&#xff1a; 1.学会"if"语句的用法。2.学会"switch"语句的用法。3.学会在"switch"语句中如何使用"break"语句。4.理解"goto"语句的正确用法。在前…

将博客搬至51CTO

将博客搬至51CTO转载于:https://blog.51cto.com/imace/1540730

腾讯国风AI虚拟人学会作诗书法,背靠开源模型SongNet

5月21日&#xff0c;腾讯AI虚拟人艾灵再秀出新技能&#xff0c;首次展示AI作诗、AI书法等国风才艺&#xff0c;并与青年歌手白举纲跨次元合作&#xff0c;共同演唱国风新歌《百川千仞》。 AI“艾灵”诞生于腾讯AI Lab&#xff0c;来自实验性、探索性技术项目“多模态虚拟人”。…

Windows10安装Mysql5.7.19.0 msi 版本报错

安装环境&#xff1a;Windows10安装版本&#xff1a;MySql 5.7.19.0 msi1.安装5.7.19.0 msi版本Mysql时报如下错误&#xff1a;2.根据日志分析是缺少visual Studio 2013 Redistributable3.下载完成后&#xff0c;安装仍然显示失败&#xff1a;4.在网上下载各种vs测试&#xff0…

C#简单的欢迎程序

本节课通过介绍几个简单的程序&#xff0c;使得你对C#有所入门。本节程要达到如下几个目的&#xff1a; 1.理解一个C#程序的基本结构。2.初步了解"名称空间"的概念。3.初步了解"类"的概念。4.了解"Main"方法所做的工作。5.学会如何读取命令行输入…

知乎联合清华:开放国内最大个性化推荐实际交互数据集

5月21日&#xff0c;知乎联合清华大学对外开放基于知乎的大规模富文本查询和推荐数据集“ZhihuRec”。该数据集包含了知乎上的1亿个行为数据&#xff0c;是目前为止&#xff0c;国内用于个性化推荐的最大的实际交互数据集。 作为一个大型数据集&#xff0c;ZhihuRec具有社交化问…

SQL Server 2014 许可证(五)降级与升级

“版本”一词对应的英文单词有两个&#xff1a;&#xff08;1&#xff09; Version是指不同历史时期发生的产品&#xff0c;或者指产品不同的“代”&#xff0c;例如&#xff0c;SQL Server 2014 版本。&#xff08;2&#xff09; Edition是指在发行同一代产品&#xff08;Vers…

OCM_第十二天课程:Section6 —》数据库性能调优_ 资源管理器/执行计划

注&#xff1a;本文为原著&#xff08;其内容来自 腾科教育培训课堂&#xff09;。阅读本文注意事项如下&#xff1a;1&#xff1a;所有文章的转载请标注本文出处。2&#xff1a;本文非本人不得用于商业用途。违者将承当相应法律责任。3&#xff1a;该系列文章目录列表&#xf…

赠书 | 联邦学习如何在视觉领域应用?

前言&#xff1a;联邦学习是如何应用在视觉领域的&#xff1f;本文将通过一个获得了2020年AAAI人工智能创新应用奖的案例来向大家介绍。本案例是联邦学习在视觉、物联网、安防领域的实际应用&#xff0c;对分散在各地的摄像头数据&#xff0c;通过联邦学习&#xff0c;构建一个…

AME_Oracle自带AME审批链详解AME Standard Handler(概念)

2014-05-30 Created By BaoXinJian Oracle 自带了3大类&#xff0c;13个子类的审批链Action Type, 对应了13个标准的AME Standard Handler 1. 按主管层次审批 absolute job level / chains of authority based on absolute job levelfinal approver only / chains of authorit…

c# 中如何定义和接收消息

在C#中目前我还没有找到发送消息的类成员函数&#xff0c;所以只能采用通过调用WIN 32 API 的 SendMessage() 函数实现。由于 SendMessage的参数中需要得到窗体的句柄(handler) &#xff0c;所以又要调用另一个API FindWindow(), 两者配合使用&#xff0c;达到在不同窗体之间的…

java如何读写json文件

java如何读写json文件 在实际项目开发中&#xff0c;有时会遇到一些全局的配置缓存&#xff0c;最好的做法是配置redis数据库作为数据缓存&#xff0c;而当未有配置redis服务器时&#xff0c;读取静态资源文件&#xff08;如xml、json等&#xff09;也是一种实现方式&#xff0…

C#数组篇讲解

数组是我们经常用到的&#xff0c;我来介绍一下&#xff1a;数组是具有相同类型的一组数据。当访问数组中的数据时&#xff0c;可以通过下标来指明。c#中数组元素可以为任何数据类型&#xff0c;数组下标从0开始&#xff0c;即第一个元素对应的下标为0&#xff0c;以后逐个递增…

Spring AOP详解(转载)所需要的包

上一篇文章中&#xff0c;《Spring Aop详解&#xff08;转载&#xff09;》里的代码都可以运行&#xff0c;只是包比较多&#xff0c;中间缺少了几个相应的包&#xff0c;根据报错&#xff0c;几经百度搜索&#xff0c;终于补全了所有包。 截图如下&#xff1a; 在主测试类里面…

Mendix 披露低代码方法论,解读真实技术趋势

作者 | 宋慧头图 | 下载于视觉中国出品 | AI 科技大本营&#xff08;ID:rgznai100&#xff09;在 2021年初正式宣布进入中国市场之后&#xff0c;Mendix 在近日向媒体重点披露了关于低代码的技术方法论&#xff0c;以及近四个月在中国市场的进展。Mendix 的低代码技术方法论对于…

PHP中foreach详细解读

oreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象&#xff0c;如果尝试应用于其他数据类型的变量&#xff0c;或者未初始化的变量将发出错误信息。有两种语法&#xff1a; foreach (array_expression as $value) statement foreach (array_expression…

Android ViewPager使用具体解释

这是谷歌官方给我们提供的一个兼容低版本号安卓设备的软件包&#xff0c;里面包囊了仅仅有在安卓3.0以上能够使用的api。而viewpager就是当中之中的一个利用它&#xff0c;我们能够做非常多事情&#xff0c;从最简单的导航&#xff0c;到页面菜单等等。那怎样使用它呢&#xff…