首页
Search
1
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
69 阅读
2
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
51 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
42 阅读
4
如何在 Clash for Windows 上配置服务
40 阅读
5
如何在 IOS Shadowrocket 上配置服务
40 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1061
篇与
的结果
2024-10-20
如何减少函数参数的输入
前几天在某论坛上看的一个问题,实际上这问题并不难,如何减少函数参数的输入,目前可以用两种方法来实现: 柯里化:把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数; 解构:基于ES6的变量解构 1. 柯里化 # 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。比如有一个数据上报的函数A,在多次调用这个函数A时,有两个参数是固定的,这样我使用柯里化的原理来优先输入这两个固定的参数:// bossid和pwd为数据必须的参数 // page为当前页面 // act为操作 function funcA(bossId, pwd, page, act) { let img = new Image(); img.src = `xxx.com/?bossId=${bossId}&pwd=${pwd}&page=${page}&act=${act}`; } funcA(1234, 'qer45fg', 'mainpage', 'login'); funcA(1234, 'qer45fg', 'ownpage', 'withdraw'); 使用柯里化来实现:function curryFuncA(bossId, pwd) { return (page, act) => { let img = new Image(); img.src = `xxx.com/?bossId=${bossId}&pwd=${pwd}&page=${page}&act=${act}`; } } const send = curryFuncA(1234, 'qer45fg'); send('mainpage', 'login'); send('ownpage', 'withdraw'); 2. 解构 # 在ES6中提供了解构的概念,我们可以只获取并使用其中的某几个变量即可。解构更详细的理解,可以参考阮一峰的文章:变量的解构赋值。针对上面的函数funcA,我们也可以这样实现:function funcA({ bossId = 1234, pwd = 'qer45fg', page = '', act = '' }) { let img = new Image(); img.src = `xxx.com/?bossId=${bossId}&pwd=${pwd}&page=${page}&act=${act}`; } funcA({ page: 'mainpage', act: 'login' }); // 需要改变bossId和pwd的值时,可以直接传入即可 funcA({ bossId: '5678', pwd: 'aabbcc', page: 'ownpage', act: 'withdraw' })
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
前端:形成自己的方法论
方法论,顾名思义,是通过日常项目的洗礼,经过自己的锤炼,形成一套方法体系。在前端中,有着各种各样的方法论,每个人的方法论也不一样。那么我的思路是如何形成一套排查错误的方法论。我们的项目在上线后,我的思考是:容灾和监控是我们项目的最后一道保障,我们应当尽量在编码和测试阶段,进行规避。 编码阶段:实行code review,利用Git的的代码评审机制,让同组的同事对当前项目的代码进行评审,指导代码中不合理的地方,尽快修改。 单元测试:单元测试并不是为了编写大覆盖率、可通过的代码,而是希望从使用者(调用者)的角度,来测试代码逻辑的各种可能性,进而辅助性地增强代码的健壮性 我们也在整个项目中加入了各种的监控和日志机制,例如我们在前端使用performance来监控页面的性能,同时,我们也设置预警机制,当超过我们设定的上限时,给我们提供告警信息,方便我们能够及时地响应。 1. 排查线上出现的问题 # 例如,我们在某一天,忽然收到告警信息,整体页面的加载时间增加、错误率提升,超过了我设定的阈值,再经过记录的详细日志查看,发现加载了很多的空白图片,再通过这个信息经过深入地排查后,发现最终的问题是:头像图片服务器出现波动,导致接口返回了空的图片地址,然后前端加载了各种空的图片。找到出现的原因后,我这里做的修复措施是:将头像图片设置为懒加载,同时,为空的图片地址添加默认的头像地址。 2. 总结出的方法论 # 通过上面刚才的举例,我们也能总结出一套排查问题的方法论: 高效详细的反馈机制; 发现问题; 分析定位问题; 解决问题 最终形成自己的一套方法论。这套方法论可以推广其他的项目中使用,当有新项目上线时,首先应该建立有效的反馈和错误收集机制,然后才能进行快速的响应,最终解决问题。而不是永远等着用户的反馈,当出现用户的反馈时,必然是出现了特别严重的问题。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
JavaScript:如何获取某一天所在的星期
我们会遇到的需求的是,获取今天或者某一天所在星期的开始和结束日期。我们这里来获取今天所在星期的始末日期,我们可以通过(new Date).getDay()来获取今天是星期几,然后再通过这个减去或者加上一定的天数,就是这个星期的开始日期和结束日期。function getWeekStartAndEnd() { const oneDayTime = 1000 * 60 * 60 * 24; // 一天里一共的毫秒数 const today = new Date(); const todayDay = today.getDay(); // 获取今天是星期几,假设是周3 const startDate = new Date( today.getTime() - oneDayTime * (todayDay - 1) ); const endDate = new Date(today.getTime() + oneDayTime * (7 - todayDay)); return { startDate, endDate }; } const week = getWeekStartAndEnd(); console.log(week.startDate, week.endDate); 是不是很完美?但,这里有一个很大的 bug!注意:如果今天是周日,那么todayDay就会是 0,若还是按照上面的思路,则星期一的日期会变成下周一的日期,星期日的日期会变成下周日的日期。因此,这里我们需要特殊处理下,当 todayDay 为 0 时,就将其赋值为 7。同时,我们还可以传入一个时间戳,获取特定某一天所在的星期。 最终的解决方案 # function getWeekStartAndEnd(timestamp) { const oneDayTime = 1000 * 60 * 60 * 24; // 一天里一共的毫秒数 const today = timestamp ? new Date(timestamp) : new Date(); const todayDay = today.getDay() || 7; // 若那一天是周末时,则强制赋值为7 const startDate = new Date( today.getTime() - oneDayTime * (todayDay - 1) ); const endDate = new Date(today.getTime() + oneDayTime * (7 - todayDay)); return { startDate, endDate }; } 扩展 # 如果我要输出今天所在星期,这一周里所有的日期,该怎么办呢?很简单,先获取到这一周里的第一天,然后第一天加上oneDayTime*i的时间戳,就是第 i 天的日期,或者在前一天的基础上加上 oneDayTime 也可以。function getAllWeekToday() { const oneDayTime = 1000 * 60 * 60 * 24; const today = new Date(); const todayDay = today.getDay() || 7; // 若那一天是周末时,则强制赋值为7 const startDate = new Date( today.getTime() - oneDayTime * (todayDay - 1) ); let dateList = [startDate]; for (let i = 1; i < 7; i++) { dateList.push(new Date(startDate.getTime() + oneDayTime * i)); } return dateList; }
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
nextjs 如何将静态资源发布到 CDN
nextjs 是基于 react 的服务端同构指出框架,在使用的过程中也多多少少遇到过几个问题,其中最大的问题就是静态资源的发布了。 1. 如何基于文件内容进行 hash 命名 # Next.js uses a constant generated at build time to identify which version of your application is being served. This can cause problems in multi-server deployments when next build is ran on every server. In order to keep a static build id between builds you can provide the generateBuildId function: 按照官网上的说法,每次发布都会生成新的 hash 路径,即使当前没有任何的变动。例如某次发布的路径是/_next/static/tZonUgEY-GPCEExGbFapL/pages/index.js,那么下次的 hash 必然不是这个值。这样导致的一个问题是:如果在多台机器上发布并 build 时,会导致每次 build 产生的值不同。如果想固定某个值或者使用某个值,一个是可以先 build 完成后后再分发,或者,可以在next.config.js中自定义generateBuildId:// 来自官网上的例子 // next.config.js module.exports = { generateBuildId: async () => { return "my-build-id"; }, }; npm 上也有提供相应的安装包,可以使用当前 git 提交的 hash 值作为 buildId:next-build-id。可是这种存在的一个问题就是:即使文件没有发生变动,或者我只修改了首页的代码,发布完成后,pages 下所有的资源都需要重新加载,有用户建议使用内容的 hash 值作为每个资源的路径,但官方好像好像不太情愿,说实现起来比较困难,详情可以看这个 issue: use content hash in pages chunk name。在这条 issue 中,有用户自己实现一个插件,不过我还没用过,有兴趣的同学可以尝试下。 2. 路径的拼接规则 # 静态资源上传到 CDN,这是存在目前存在的最大的问题,虽然在next.config.js中可以配置assetPrefix字段,但实际使用起来还是非常困难。打包后的 js 和 css,引用路由均为/_next/static开头:如图片中所示,带有 data-next-page 属性的,实际上访问的是.next/server/static/[hash]/pages/_app.js;不带这个属性的,访问的路径是.next/static/runtime/webpack-[hash].js我们以 2019/09/16 提交的 nextjs 源码为例:pages_document,里面有全局脱水数据的注入,页面相关的 js 和静态资源的 js 的拼接:// 页面相关的js // assetPrefix为我们在next.config.js中配置的前缀 // ${buildId}即为每次打包生成的hash值,在本地环境下值为development // _devOnlyInvalidateCacheQueryString: 变动的时间戳,正式环境中为空, _devOnlyInvalidateCacheQueryString: process.env.NODE_ENV !== 'production' ? '?ts=' + Date.now() : '' src={assetPrefix + encodeURI(`/_next/static/${buildId}/pages${getPageFile(page)}`) + _devOnlyInvalidateCacheQueryString} // 静态资源的js src={`${assetPrefix}/_next/${file}${_devOnlyInvalidateCacheQueryString}`} 全局脱水数据的注入 上面的页面编译后的路径是.next/server/static/{hash}/pages/_document.js,这些 js 读取的路径是分别由 2 个 json 文件控制的。 sever/pages-manifest.json:加载页面相关的 js,nextjs 是服务端渲染+客户端渲染两种方式,刷新页面时使用的服务端渲染(使用server/static/{hash}/pages/中的文件),切换路由时使用的是客户端渲染(使用static/{hash}/pages/中的文件),这里加载的 js,是用于在路由切换时使用客户端渲染的方式; static/build-manifest.json:加载静态资源的 js,使用static/里除 hash 路径外的资源; 我们了解这些,主要是为了理解 js 的路径是怎样拼接完成的。 3. 如何发布静态资源到 CDN # 静态资源发布到 CDN 其实很简单,只要把.next/static下目录的资源上传上去即可。最困难的是如何替换代码中的路径。把这个目录下的静态文件上传到 CDN 后,生成的地址会变成: 从第 2 部分中能看到,代码中使用assetPrefix作为静态资源的前缀时,只是单纯的拼接到了最前面而已,拼接后的地址是: 中间多出了/_next/static的路径,最后的结果是页面需要加载的资源和上传的资源路径不一致,就会各种 404。这里我的解决方案很简单粗暴,读取编译后的文件,然后执行 node 程序,将里面的字符替换掉:const fs = require("fs"); const glob = require("glob"); const list = glob.sync(".next"); list.forEach((file) => { let data = fs.readFileSync(file, "utf8"); if (file.indexOf("_document.js") > -1) { data = data.replace(/\/_next\//g, "/").replace(/static\/" \+ buildId/g, '" + buildId'); fs.writeFileSync(file, data); console.log(file, "success"); } else if (file.indexOf("build-manifest.json") > -1) { data = data.replace(/static\//g, ""); fs.writeFileSync(file, data); console.log(file, "success"); } else if (data.indexOf("/_next/static") > -1) { data = data.replace(/\/_next\/static\//g, "/"); fs.writeFileSync(file, data); console.log(file, "success"); } }); 这样就能就可以保证项目的 CDN 地址和真正上传的地址是一致的了。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
十大经典排序算法(javascript实现)
0 算法概述 # 0.1 算法分类 # 十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 0.2 算法复杂度 # 0.3 相关概念 # 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。 空间复杂度:是指算法在计算机 内执行时所需存储空间的度量,它也是数据规模n的函数。 1 冒泡排序(Bubble Sort) # 冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 1.1 算法描述 # 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 针对所有的元素重复以上的步骤,除了最后一个; 重复步骤1~3,直到排序完成。 1.2 动图演示 # 1.3 代码实现 # function bubbleSort(arr) { const len = arr.length; for (let i = 0; i < len - 1; i++) { for (let j = 0; j < len - 1 - i; j++) { if (arr[j] > arr[j + 1]) { // 相邻元素两两对比 let temp = arr[j + 1]; // 元素交换 arr[j + 1] = arr[j]; arr[j] = temp; } } } return arr; } 2 选择排序(Selection Sort) # 选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 2.1 算法描述 # n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下: 初始状态:无序区为R[1..n],有序区为空; 第i趟排序(i=1, 2, 3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区; n-1趟结束,数组有序化了。 2.2 动图演示 # 2.3 代码实现 # function selectionSort(arr) { const len = arr.length; let minIndex, temp; 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; // 将最小数的索引保存 } } temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } return arr; } 2.4 算法分析 # 表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。 3 插入排序(Insertion Sort) # 插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 3.1 算法描述 # 一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下: 从第一个元素开始,该元素可以认为已经被排序; 取出下一个元素,在已经排序的元素序列中从后向前扫描; 如果该元素(已排序)大于新元素,将该元素移到下一位置; 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; 将新元素插入到该位置后; 重复步骤2~5。 3.2 动图演示 # 3.3 代码实现 # function insertionSort(arr) { const len = arr.length; let preIndex, current; for (let 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; } 3.4 算法分析 # 插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。 4 希尔排序(Shell Sort) # 1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。 4.1 算法描述 # 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述: 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1; 按增量序列个数k,对序列进行k 趟排序; 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 4.2 动图演示 # 4.3 代码实现 # function shellSort(arr) { const len = arr.length; for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) { // 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行 for (let i = gap; i < len; i++) { let j = i; let current = arr[i]; while (j - gap >= 0 && current < arr[j - gap]) { arr[j] = arr[j - gap]; j = j - gap; } arr[j] = current; } } return arr; } 4.4 算法分析 # 希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。 5 归并排序(Merge Sort) # 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。 5.1 算法描述 # 把长度为n的输入序列分成两个长度为n/2的子序列; 对这两个子序列分别采用归并排序; 将两个排序好的子序列合并成一个最终的排序序列。 5.2 动图演示 # 5.3 代码实现 # 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 > 0 && right.length > 0) { if (left[0] 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; } 8 计数排序(Counting Sort) # 计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 8.1 算法描述 # 找出待排序的数组中最大和最小的元素; 统计数组中每个值为i的元素出现的次数,存入数组C的第i项; 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加); 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。 8.2 动图演示 # 8.3 代码实现 # 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; } 8.4 算法分析 # 计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。 9 桶排序(Bucket Sort) # 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。 9.1 算法描述 # 设置一个定量的数组当作空桶; 遍历输入数据,并且把数据一个一个放到对应的桶里去; 对每个不是空的桶进行排序; 从不是空的桶里把排好序的数据拼接起来。 9.2 图片演示 # 9.3 代码实现 # 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; } 9.4 算法分析 # 桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。 10 基数排序(Radix Sort) # 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。 10.1 算法描述 # 取得数组中的最大数,并取得位数; arr为原始数组,从最低位开始取每个位组成radix数组; 对radix进行计数排序(利用计数排序适用于小范围数的特点); 10.2 动图演示 # 10.3 代码实现 # var counter = []; function radixSort(arr, maxDigit) { var mod = 10; var dev = 1; for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { for (var j = 0; j < arr.length; j++) { var bucket = parseInt((arr[j] % mod) / dev); if (counter[bucket] == null) { counter[bucket] = []; } counter[bucket].push(arr[j]); } var pos = 0; for (var j = 0; j < counter.length; j++) { var value = null; if (counter[j] != null) { while ((value = counter[j].shift()) != null) { arr[pos++] = value; } } } } return arr; } 10.4 算法分析 # 基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。
2024年10月20日
3 阅读
0 评论
0 点赞
1
...
34
35
36
...
213