JS中的广度与深度优先遍历
数组和链表傻傻分不清
-
数组静态分配内存,链表动态分配内存; -
数组在内存中连续,链表不连续; -
数组元素在栈区,链表元素在堆区; -
数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n); -
数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1);
什么是堆?什么是栈?js内存机制是什么?
任何一种语言都有数据类型的分类,某种语言是如何存放和分配这些数据的,这就是内存管理。那栈和堆与内存有什么关联呢? 首先要理解的是栈和堆也就是栈内存和堆内存, 它们都存放于内存中.
堆内存
用于存储Js中的复杂数据类型,当我们创建一个对象或数组或new一个实例的时候,就会在堆内存中开辟一段空间给它,用于存放。堆内存可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,但缺点是,由于要在运行时动态分配内存,存取速度较慢。
栈内存
用于存储Js中的简单数据类型及对象的引用指针, 该指针指向的是堆内存中对应的值 栈内存的特点是后进先出, 可以直接存取的,而堆内存是不可以直接存取的内存。对于我们的对象来数就是一种大的数据类型而且是占用空间不定长的类型,所以说对象是放在堆里面的,但对象名称是放在栈里面的,这样通过对象名称就可以使用对象了。
什么是深度优先和广度优先
其实简单来说 深度优先就是自上而下的遍历搜索 广度优先则是逐层遍历, 如下图所示
1.深度优先
2.广度优先
两者的区别
对于算法来说 无非就是时间换空间 空间换时间
-
深度优先不需要记住所有的节点, 所以占用空间小, 而广度优先需要先记录所有的节点占用空间大 -
深度优先有回溯的操作(没有路走了需要回头)所以相对而言时间会长一点
深度优先采用的是堆栈的形式, 即先进后出
广度优先则采用的是队列的形式, 即先进先出
具体代码
const data = [{
name: 'a',
children: [{
name: 'a1',
children: [{
name: 'a11'
},{
name: 'a12'
}]
},
{
name: 'a2',
children: [{
name: 'a21'
},{
name: 'a22'
}]
},
{
name: 'a3',
children: [{
name: 'a31'
},{
name: 'a32'
}]
},
],
},
{
name: 'b',
children: [{
name: 'b1',
children: [{
name: 'b11'
},{
name: 'b12'
}]
},
{
name: 'b2',
children: [{
name: 'b21'
},{
name: 'b22'
}]
},
{
name: 'b3',
children: [{
name: 'b31'
},{
name: 'b32'
}]
},
],
}
];
// 深度遍历, 使用递归
function getName(data) {
const result = [];
data.forEach(item => {
const map = data => {
result.push(data.name);
data.children && data.children.forEach(child => map(child));
}
map(item);
})
return result.join(',');
}
console.log(getName(data));
// a,a1,a11,a12,a2,a21,a22,a3,a31,a32,b,b1,b11,b12,b2,b21,b22,b3,b31,b32
// 广度遍历, 创建一个执行队列, 当队列为空的时候则结束
function getName2(data) {
let result = [];
let queue = data;
while (queue.length > 0) {
[...queue].forEach(child => {
queue.shift();
result.push(child.name);
child.children && (queue.push(...child.children));
});
}
return result.join(',');
}
console.log(getName2(data));
// a,b,a1,a2,a3,b1,b2,b3,a11,a12,a21,a22,a31,a32,b11,b12,b21,b22,b31,b32