前端JS常用八大数据结构

基础知识篇

前端算法入门 – 数据结构

在这里插入图片描述
数据结构指的是“一组数据的存储结构”,算法指的是“操作数据的一组方法”。
数据结构是为算法服务的,算法是要作用再特定的数据结构上的。

最常用的数据结构预算法:

数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Tire树
算法: 递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法

基础知识篇

1.什么叫算法?

算法就是计算或解决问题的步骤。

2.算法和程序有什么区别?

区别在于,程序是以计算机能够理解的编程语言编写的,可以在计算机上运行,而算法是以人类能够理解的数学方式来描述的,用于编程之前。但算法和编程没有具体边界。

3.如何选择算法?

同样的问题,不同的开发者解法不同,不同的编程语言,写法不同,为算法设立评判标准的目的在于选择最优标准的算法。评判算法的优劣有两个标准:一是从运行到计算出结果需要耗费空间的大小,另一个是从运行到计算出结果需要花费多少时间。分别称为, 空间复杂度 、 时间复杂度 。通常,复杂度越低,耗费内存越少,执行越快,也更容易被人理解。一般, 最为重视的是算法的运行时间 。

3.1 时间复杂度

  1. 是什么?

    执行当前算法所“花费的时间”

  2. 干什么?

    在写代码的过程中,就可以大概知道代码运行的快与慢

  3. 表示

    大O表示法 《解析数论》

    O表示有很多,例举几个:O(1)、O(n)、O(n^2)、O(logn)…

3.2 空间复杂度

  1. 是什么?

    执行当前算法需要占用多少内存空间

  2. 表示法

    O(1)、O(n)、O(n^2)…

多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。包括,
O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n2)(平方阶)、O(n3)(立方阶)
非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。包括,
O(2^n)(指数阶)、O(n!)(阶乘阶)

在这里插入图片描述

4.如何反映算法的运行时间?

算法不同、设备不同、数据量不同都会导致算法时间有差异,通过理论计算出的运行时间是一个多项式,而我们需要能最直观的了解到时间随数据量变化的关系,常常会忽略掉非重要项,得到一个最简单的并且最能反映运行时间趋势的表达式,我们把:忽略掉不重要项、能最简表示运行时间随数据量变化关系写成O(n)的形式,其中O是大写,表示忽略重要项以外的内容,读音同order;n表示参与算法的数据量。

前端算法 – 常见的八种数据结构

在这里插入图片描述

基础数据结构

数据结构就是关系,没错,就是数据元素相互之间存在的一种或多种特定关系的集合。

传统上,我们把数据结构分为逻辑结构和物理结构。
逻辑结构:是指数据对象中数据元素之间的相互关系,也是我们今后最需要关注和讨论的问题。
物理结构:是指数据的逻辑结构在计算机中的存储形式。

在这里插入图片描述

1.数组(Array)

数组是最简单、也是使用最广泛的数据结构。数组是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。

数组:查询快,增删慢
查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找某一个元素
增删慢:数组的长度是固定的,我们想要增加/删除一个元素,必须创建一个新的数组,把原数组的数据复制过来

2.栈(Stack)

栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。

栈: 先进后出(入口出口在同一侧)

在这里插入图片描述

 let arr = [];

      arr.push(1);
      arr.push(2);
      arr.push(3); //顺序插入
      console.log(arr);
      arr.pop(); //删除对尾
      arr.shift(); //删除队头
      console.log(arr);
    <script type="text/javascript">
      var isValid = function (s) {
        var stack = [];
        for (let i = 0; i < s.length; i++) {
          const start = s[i];
          if (s[i] == "(" || s[i] == "{" || s[i] == "[") {
            stack.push(s[i]);
          } else {
            const end = stack[stack.length - 1];
            if (
              (start == ")" && end == "(") ||
              (start == "]" && end == "[") ||
              (start == "}" && end == "{")
            ) {
              stack.pop();
            } else {
              return false;
            }
          }
        }
        return stack.length == 0;
      };
      console.log(isValid("(){}"));
      console.log(isValid("({)}"));
      console.log(isValid("({})"));
    </script>

3.队列(Queue)

队列与栈一样,也是一种线性表,不同的是,队列可以在一端添加元素,在另一端取出元素,也就是:先进先出。从一端放入元素的操作称为入队,取出元素为出队。

队列:先进先出(入口出口在两侧,分开的)
在这里插入图片描述

      let arr = [];

      arr.push(1);
      arr.push(2);
      arr.push(3); //顺序插入
      console.log(arr);
      arr.pop(); //删除对尾
      arr.shift(); //删除队头
      console.log(arr);

4.链表(Linked List)

链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。

链表:查询慢,增删快
查询慢:链表地址不是连续的,每次查询都要从头开始
增删快:增加/删除一个元素,对链表的整体结构没有影响,所以增删快
链表入门

一、什么是链表

1. 多个元素存储的列表
2. 链表中的元素在内存中不是顺序存储的,而是通过"next"指针联系在一起的。

***js中的原型链 原理就是 链表结构

二、链表和数组的区别

1. 数组:有序存储的,在中间某个位置删除或者添加某个元素,其他元素要跟着动。

2. 链表中的元素在内存中不是顺序存储的,而是通过"next"指针联系在一起的。

三、链表

单向链表
双向链表
![在这里插入图片描述](https://img-blog.csdnimg.cn/cd19514091fc4e1791f5cf37726efec9.png)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


let a = {key:'aaa'};
let b = {key:'bbb'};
let c = {key:'ccc'};
let d = {key:'ddd'};

a.next = b;
b.next = c; 
c.next = d;
d.next = null;

console.log( a );


//遍历链表
let obj = a;
while( obj && obj.key ){
	console.log( obj.key );
	obj = obj.next;
}

//链表中插入某个元素
let m = {key:'mmmmm'};
c.next = m;
m.next = d;
console.log( a );

//删除操作
c.next = d;

5.字典

jsES6中的map方法
阮一峰ES6 入门教程map

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false
对象  :  键值对存储的(对象---键[key]都是字符串类型或者会转换成字符串类型)

字典  :  键值对存储的  map来表示的,map的键不会转换类型,可以存在任何数据类型

力扣01两数之和

<script type="text/javascript">
var twoSum = function(nums, target) {
    let map = new Map();
    for( let i=0;i<nums.length;i++){
        num = target - nums[i];
        if( map.has(num) ){
            return [map.get(num),i];
        }
        map.set(nums[i],i);
    }
};
</script>

5.散列表(Hash) 哈希表

在js中没有哈希表,哈希表是字典一种实现。

区别一:如果找key对应的value需要遍历key,那么想要省去遍历的过程,用哈希表来表示。

区别二:排列顺序

	字典是根据添加的顺序进行排列的
	哈希表不是添加的顺序进行排列的

散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。

Hash表是一种特殊的数据结构,它同数组、栈、链表等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。

哈希表是基于键值对的一种数据存储结构,key值不可以重复,value可以重复,后面添加的重复的key值的时候,会把之前key值对应的value给覆盖掉,JavaScript中的对象具有天然的哈希特性。

js模拟哈希表

<script type="text/javascript">
class HashTable{
	constructor(){
		this.table = [];
	}
	hashCode( key ){
		let hash = 0;
		for( let i =0;i<key.length;i++){
			hash += key.charCodeAt(i);
		}
		return hash;
	}	
	put( key , val ){
		let hashKey = this.hashCode(key);
		this.table[ hashKey ] = val;
	}
	get( key ){
		let hashKey = this.hashCode(key);
		return this.table[hashKey];
	}
}

let hashTable = new HashTable();
hashTable.put('person','章三');
console.log( hashTable );
console.log(  hashTable.get('person') );

</script>

6.树(Tree)

树:一种分层数据的抽象模型 ----简单来说:分层级关系

树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是二叉树。

 <script type="text/javascript">
      const tree = {
        val: "a",
        children: [
          {
            val: "b",
            children: [
              { val: "d", children: [] },
              { val: "e", children: [] },
            ],
          },
          {
            val: "c",
            children: [
              { val: "f", children: [] },
              { val: "g", children: [] },
            ],
          },
        ],
      };

      //   深度优先遍历
      //   const fun1 = (root) => {
      //     console.log(root.val);
      //      写法一
      //     root.children.forEach((item) => {
      //       fun1(item);
      //     });
      //      写法二
      //     root.children.forEach(fun1);
      //   };

      //   fun1(tree);

      //   广度优先遍历
      const fun2 = (root) => {
        const arr = [root];
        while (arr.length > 0) {
          const o = arr.shift();
          console.log(o.val);
          o.children.forEach((item) => {
            arr.push(item);
          });
        }
      };

      fun2(tree);
    </script>

7.堆(Heap)

堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质: 堆中某个节点的值总是不大于或不小于其父节点的值; 堆总是一棵完全二叉树。
在这里插入图片描述

最小堆的实现

    <script type="text/javascript">
      class MinHeap {
        constructor() {
          this.heap = [];
        }
        // 换位置
        swap(i1, i2) {
          const temp = this.heap[i1];
          this.heap[i1] = this.heap[i2];
          this.heap[i2] = temp;
        }
        // 找父节点
        getParentIndex(index) {
          return Math.floor((index - 1) / 2);
        }
        // 上前移操作
        up(index) {
          // 如果是0就不移动了
          if (index == 0) return;
          const parentIndex = this.getParentIndex(index);
          //   如果父元素大于当前元素,就开始移动
          if (this.heap[parentIndex] > this.heap[index]) {
            this.swap(parentIndex, index);
            this.up(parentIndex);
          }
        }
        // 获取左侧子节点
        getLeftIndex(index) {
          return index * 2 + 1;
        }
        // 获取右侧子节点
        getRightIndex(index) {
          return index * 2 + 2;
        }
        // 下(后)移动
        down(index) {
          const leftIndex = this.getLeftIndex(index);
          const rightIndex = this.getRightIndex(index);
          if (this.heap[leftIndex] < this.heap[index]) {
            this.swap(leftIndex, index);
            this.down(leftIndex);
          }
          if (this.heap[rightIndex] < this.heap[index]) {
            this.swap(rightIndex, index);
            this.down(rightIndex);
          }
        }
        // 添加元素
        insert(value) {
          this.heap.push(value);
          this.up(this.heap.length - 1);
        }
        // 删除堆顶
        pop() {
          this.heap[0] = this.heap.pop();
          this.down(0);
        }
        // 获取堆顶
        peek() {
          return this.heap[0];
        }
        // 数量
        size() {
          return this.heap.length;
        }
      }

      let arr = new MinHeap();
      arr.insert(5);
      arr.insert(4);
      arr.insert(6);
      arr.insert(1);
      arr.pop();
      console.log(arr);
      console.log(arr.size());
      console.log(arr.peek());
    </script>

8.图(Graph)

图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

算法中必备知识

1. 递归

递归就是自己调自己,递归在前端里面算是一种比较常用的算法
在这里插入图片描述

  1. 使用递归函数需要注意什么
    1,可以终止递归的条件【如果没有这个条件就会进入死循环】
    2,可以是递归函数一直地柜下去的条件【如果没有这个条件,那么递归函数将会递归不下去】

  2. 实例

  function fn(n) {
        if (n <= 2) {   //可以终止递归的条件
          return 1;
        }
        return fn(n - 1) + fn(n - 2);  //可以是递归函数一直地柜下去的条件
      }
      //  1.  f(4)  +  f(3)           
      //  2.  f(3)+f(2) +  f(2) +f(1)
      //  3.  f(2)+f(1)+f(2) +  f(2)+f(1)
      //  4.  1   + 1   + 1     +  1   + 1
      console.log(fn(5));  // 5 

2. JS中的任务队列

在这里插入图片描述

在这里插入图片描述

	<script type="text/javascript">
		Promise.resolve('3333').then(res=>{
			console.log( res );
			setTimeout(()=>{
				console.log('Promise setTimeout')
			},0)
		})
		
		setTimeout(()=>{
			console.log( 111 );
			Promise.resolve('setTimeout Promise').then(res=>{
				console.log( res );
			})
		},0)
		console.log( 222 );
		</script>

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值