开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
js 常用必备算法_上
扁平化
数组扁平化就是将一个多维数组转换为一个一维数组,通过递归实现数组扁平化。 Array.isArray() 用于确定传递的值是否是一个 Array
Array.isArray([1, 2, 3]);
// true
Array.isArray({foo: 123});
// false
Array.isArray("foobar");
// false
Array.isArray(undefined);
// false
array.concat(arr)
concat() 方法用于连接两个或多个数组。 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
function flatten(arr) {
let result=[]
for (let i=0,len=arr.length;i<len;i++) {
if (Array.isArray(arr[i])) {
result=result.concat(flatten(arr[i]))
} else {
result.push(arr[i])
}
}
return result
}
去重
数组去重,有多种方式,通过 Es6 Set(),实现去重,set 和 map 类似,但不能保存重复的数据
function unique(arr) {
let appeard=new Set()
return arr.filter(item=>{
//创建一个可以唯一标识对象的字符串id
let id=item+JSON.stringify(item)
if (appeard.has(id)) {
return false
} else {
appeard.add(id)
return true
}
})
}
浅拷贝
浅拷贝会在栈中开辟另一块空间,并将被拷贝对象的栈内存数据完全拷贝到该块空间中,即基本数据类型的值会被完全拷贝,而引用类型的值则是拷贝了“指向堆内存的地址”。有…扩展运算符、Array.from、Object.assign()方法
function copy(obj) {
let result=Array.isArray(obj)?[]:{}
Object.keys(obj).forEach(key=>result[key]=obj[key])
return result
}
otherStar={...star}
Object.assign({},star)
深拷贝
不仅会在栈中开辟另一块空间,若被拷贝对象中有引用类型,则还会在堆内存中开辟另一块空间存储引用类型的真实数据。 万能转换器:JSON.parse(JSON.stringify(obj))深拷贝已有对象,它可以深拷贝多层级的,不用担心嵌套问题。
function copy(obj,appeard=new Map()) {
if (!(obj instanceof Object)) return obj//如果是原始数据类型
if (appeard.has(obj)) return appeard.get(obj)//如果已经出现过
let result=Array.isArray(obj)?[]:{}
appeard.set(obj,result);//将新对象放入map
//遍历所有属性进行递归拷贝
[...Object.keys(obj),...Object.getOwnPropertySymbols(obj)]
.forEach(key=>result[key]=copy(obj[key],appeard))
return result
}
JSON.stringify
只能处理纯 JSON 数据
有几种情况会发生错误
包含不能转成 JSON 格式的数据
循环引用
undefined,NaN, -Infinity, Infinity 都会被转化成 null
RegExp/函数不会拷贝
new Date()会被转成字符串
new=JSON.parse(JSON.stringify(old))
遍历
广度优先和深度优先算法 对于算法来说 无非就是时间换空间 空间换时间 深度优先不需要记住所有的节点, 所以占用空间小, 而广度优先需要先记录所有的节点占用空间大 深度优先有回溯的操作(没有路走了需要回头)所以相对而言时间会长一点 深度优先采用的是堆栈的形式, 即先进后出 广度优先则采用的是队列的形式, 即先进先出
插入排序
循环遍历原始数据,把原始数组内的每一个逐个插入到新数组内 在插入的时候,按照一定的顺序插入。
function sort(arr) {//原地
for (let i in arr) {//选一个元素
while (i>0&&arr[i]<arr[i-1]) {//向前移动到合适的位置
[arr[i],arr[i-1]]=[arr[i-1],arr[i]]
i--
}
}
}
归并排序
归并排序其实可以类比二分法,二分法其实就是二等分的意思,就是不断和新序列的中间值进行比较。
function sort(arr) {
if (arr.length===1) return arr
//分成两部分
let mid=Math.floor(arr.length/2)
let [part1,part2]=[sort(arr.slice(0,mid)),sort(arr.slice(mid))]
//对比+合并
let result=[]
while (part1.length>0&&part2.length>0)
result.push((part1[0]<part2[0]?part1:part2).shift())
return [...result,...part1,...part2]
}
快速排序
选择数组中的一个值作为基准,将数组中小于该值的数置于该数之前,大于该值的数置于该数之后,接着对该数前后的两个数组进行重复操作直至排序完成。
function sort(arr) {
if (arr.length<=1) return arr
//选基准值
let mid_pos=arr.length>>1
let mid=arr.splice(mid_pos,1)[0]
let left=[],right=[]
//和基准值比较,分别插入left,right数组
arr.forEach(item=>(item<=mid?left:right).push(item))
return [...sort(left),mid,...sort(right)]//递归调用排序
}
二分查找
二分查找就是将需要查找的元素不断地与数组中间的元素进行比较,数组不断地拆分为两段(查找元素小于中间值在前半段查找,大于中间值在后半段进行查找)
function search(arr,target) {//循环写法,不断移动左右指针,缩小范围
let left=0,right=arr.length-1
while (left<=right) {
const mid_pos=Math.floor((left+right)/2)
const mid_val=arr[mid_pos]
if (target===mid_val) {
return mid_pos
} else if (target>mid_val) {
left=mid_pos+1
} else {
right=mid_pos-1
}
}
return -1
}
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情