时间复杂度分析当问题规模数据增大时,重复执行的次数也会增加,所以需要关心次数增加的数量级处决。这也是分析时间复杂度的意义,时间复杂度是衡量算法快速预估方法的一个非常重要的方法。常见的时间复杂度:O(1):常阶复杂度,这个复杂度无论数据规模如何增长,计算时间都是常数。constincrement=n=>n++O(n):线性复杂度,线性增长。//最典型的例子就是线性搜索constlinearSearch=(arr,target)={for(leti=0;i{console.time('bubbleSort需要时间');让len=arr.length;for(leti=0;iarr[j+1]){[arr[j],arr[j+1]]=[arr[j+1],arr[j]]}}}console.timeEnd('冒泡排序耗时');returnarr}冒泡排序改进方案:方案一:设置一个标记变量pos,记录每次访问的最后一次交换位置,那么在下一次访问之后,序列就不能再访问了。constbubbleSort_pos=arr=>{console.time('bubbleSort_pos需要时间')leti=arr.length-1;while(i>0){让pos=0;for(varj=0;jarr[j+1]){pos=j;[arr[j],arr[j+1]]=[arr[j+1],arr[j]];}}我=位置;}console.timeEnd('bubbleSort_postime-consuming')returnarr;}方案二:传统冒泡一次只能求一个最大值或最小值,我们可以考虑使用正向和反向冒泡,一个最大值和一个最小值即可一次获得,从而减少了近一半的排序次数。constbubbleSort_ovonic=arr=>{console.time('bubbleSort_ovonic需要时间')letlow=0;让height=arr.length-1;让tmp,j;while(lowarr[j+1]){[arr[j],arr[j+1]]=[arr[j+1],arr[j]];}}-高度;for(j=height;j>low;--j){//反转气泡,找到最小值if(arr[j]{if(arr.length<=1){returnarr};让pivotIndex=Math.floor(arr.length/2);让pivot=arr.splice(pivotIndex,1)[0];//确定基准letleft=[],right=[];for(leti=0;itj,tk=1根据增量序列的个数k,对序列进行k次排序。每个排序序列根据对应的增量ti分成长度。是m的多个子序列,然后对每个子列表进行直接插入排序。只有当增量因子为1时,整个序列才被视为一个表,表的长度就是整个序列的长度。constshellSort=arr=>{console.time('shellSort需要时间')letlen=arr.length,gap=1,temp;while(gap0;gap=Math.floor(gap/5)){for(leti=gap;i=0&&arr[j]>temp;j-=gap){arr[j+gap]=arr[j];}arr[j+gap]=temp;}}console.timeEnd('shellSortWhen');returnarr;}归并排序归并排序不受输入数据的影响,时间复杂度始终为O(nlogn),但代价是需要额外的内存空间。归并排序也是分治法的经典体现。首先,对子序列进行排序,然后对子序列的段进行排序。如果将两个有序列表合并为一个有序列表,则称为2-waymerge。实现过程如下:将一个长度为n的序列分成两个长度为n/2的子序列,对两个子序列进行归并排序,将两个排序后的子序列合并为最终的排序序列。constmerge=(left,right)=>{让结果=[];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());返回结果;}constmergeSort=arr=>{让len=arr.length;如果(len<2)返回arr;让middle=Math.floor(len/2),left=arr.slice(0,middle),right=arr.slice(middle);返回合并(mergeSort(左),mergeSort(右));}常用搜索算法线性搜索线性搜索比较简单,只需要简单的遍历即可。constlinearSearch=(arr,target)=>{for(leti=0;iheight找不到该值为止被搜索并结束。constbinarySearch=(arr,target)=>{letheight=arr.length-1;让低=0;while(low<=height){letmiddle=Math.floor((low+height)/2)if(targetarr[middle]){low=middle+1}else{returnmiddle}}return-1}时间复杂度分析:最佳情况O(logn),最坏情况O(logn),平均情况O(logn)。参考资料:damonare。二叉树的遍历有四种方式:前序遍历、中序遍历、后序遍历和层序遍历。先序遍历:先访问根节点,再先序遍历左子树,再先序遍历右子树。中序遍历:先中序遍历左子树,再访问根节点,最后遍历右子树。后序遍历:从左到右,先遍历左子树再遍历节点,最后访问根节点。层序遍历:从根节点开始,从上到下逐层遍历,在同一层按从左到右的顺序逐个访问节点。实现二叉树的层序遍历一般有两种树遍历策略:深度优先遍历(DFC),顾名思义,深度优先遍历以深度为优先级,从某一片叶子开始,然后返回到根到另一个分支,细分为前序遍历、中序遍历和后序遍历广度优先遍历(BFC)广度优先按高度顺序逐层访问整棵树,高层节点会先被访问低层节点//实现constlevelOrder=function(root){constres=[];conststack=[{index:0,node:root}];while(stack.length>0){const{index,node}=stack.pop();如果(!节点)继续;res[索引]=res[索引]?[...res[index],node.val]:[node.val];stack.push({index:index+1,node:node.right});stack.push({index:index+1,node:node.left});}返回资源;};