数据结构(一)

48 阅读4分钟

前端对算法的初印象

数组

在js代码中我们常用的定义数组的方式:

const arr = [];
const arr = [1,2,3]

算法中常常不知道数组中有什么元素,或者需要填充一些相同的元素;所以常用的定义数组的方式:

// 指定数组长度并填充元素
const arr=new Array(5).fill(1)

数组常用的遍历方法,如:for、forEach、map

for和forEach在工作中用的比较多,都是遍历所有子元素,过程中能得到每个元素和元素的索引

map一般用于对数组的再加工,会返回新数组

对于数据量很大的循环来说,for循环是性能最好的

二维数组

指数组嵌套数组

每一行代表一个一维数组,每一行每一列代表一个具体的值;二维数组像是一个面,他的排列又像是一个矩阵,所以二维数组又叫矩阵

image.png

二维数组的初始化:const arr = new Array(5).fill([])

使用fill填充二维数组的问题是:fill的参数是引用类型的话,在修改其中任一参数时其他的参数都会被修改,如arr[0][0]=1,这时所有列都会变为[1];如果直接将arr[0]=[1,2,3]这样arr[0]是不会受影响的

推荐使用for循环来初始化二维数组

for(let i=0;i<arr.length;i++){
  arr[i]=[]
}

多维数组的遍历:几维数组遍历就需要嵌套几层

数组的更多操作:​juejin.cn/post/712722…

栈和队列

他们都是特别的数组,主要区别在于他们的增删不同,数组的增删

增:unshift、push、splice(1,0,2)(在数组索引1的位置添加元素2)

删:shift、pop、splice(1,1)

splice:如果是新增返回空数组,如果是删除返回删除的数组;splice操作会改变源数组

栈:后进先出;增:push;删:pop

特点:就像往一个盒子里放书,只允许从队尾添加,也只能从队尾取出,都是操作队尾,所以使用push和pop

栈顶元素,也就是数组的最后一个元素,也是最先能取出的元素

const stack = [];
stack.push("HTML");
stack.push("CSS");
stack.push("JS");
while (stack.length) {
  // 获取栈顶(盒子最上面)的书本
  const item = stack[stack.length - 1];
  console.log(`栈顶书本是:${item}`);
  stack.pop();
}

队列

队列:先进先出;增:push;删:shift

特点:就像排队点餐,只允许从队尾添加,从头部移除;所以支持的操作是push和shift

const queue = [];
queue.push("张三");
queue.push("李四");
queue.push("王五");
while (queue.length) {
  const item = queue[queue.length - 1];
  console.log(`栈顶元素是:${item}`);
  queue.shift();
}

链表

特点:与数组相似,都是线性且有序的列表;不同的是数组中的各个点是连续的内存,因此可以根据索引来访问;但是链表中的点可以是离散的,也就是元素之间在内存上没有联系,所以不能遍历,他们直接可以通过指针域和数据域来关联;所以链表通过next来访问;为了确保每个点都能访问到,所以一般用head指针专门指向我们链表的开始位置

{
   // 数据域  
   val:1,
   // 指针域
   next:{
       val:2,
       next:{}
   }  
}

创建链表:

function ListNode(val){
      this.val = val;
      this.next = null;
 }
 const node = new ListNode(1);
 node.next = new ListNode(2);

链表元素的添加:

1、如果是在尾部插入,直接改变最后一个元素的next指向就行

2、如果需要在两个节点之间插入节点,需要修改两个节点的next指针;一个是前驱节点的next指针,使之指向目标节点;二是修改目标节点的指针,使之指向前驱节点的next

链表元素的删除:

删除某个节点,是将目标节点的前驱节点的next指向目标节点的后继;所以在删除链表时重要的是找到目标节点的前驱节点

链表和数组的区别:

数组:如果要删除数组中的一个节点,那么该节点之后的所有节点都需要移动位置,新增也是一样;假设数组长度为n,新增删除一个数组的时间复杂度为o(n)

链表:因为链表的存储本来就是散列的,所以新增和删除链表是不需要移动其他节点的;所以对链表的增删操作的复杂度都是o(1)

JS中如果数组存储的都是数字(字符串等同一数据类型),那么这个数组内存是连续的;如果一个数组中存储的数据类型不相同,那么此时数组内存就不是连续的;所以JS中的数组和常规数组还是有区别的

数组因为是连续内存,可以直接使用索引访问;但是链表的访问必须遍历整个链表

树的特性:包含一个根节点、一个或多个节点、一个或多个叶子节点;一个节点开叉出多少子树称为节点的度

树的高度:叶子节点的高度记为1,每向上一层高度加1,树中节点的最大高度称为树的高度