前前言
hello 大家好,我是来自推啊前端团队的刘爽,今天给大家带来【数据结构与算法】的第一篇,基础介绍。
程序 = 数据结构 + 算法
什么是数据结构
在日常生活中数据结构主要体现在把一堆杂乱无章的数据按照一定结构整理,以便于能够快速的找到对应内容。比如说你有一个万能的电话本,里面有任何人的电话并且记录着此人的详细信息,但是记录的顺序是无序的,没有任何规律。这时候如果想要找到法外狂徒“张三”的信息,必须一个一个找。如果我们把记录的顺序以联系人的拼音顺序排列,这时候查找是不是就方便很多。
在这个例子中其实就能够体现出数据结构是什么,数据结构决定了数据的顺序和位置关系。 在计算机领域,数据结构包含以下几个方面:
- 数据元素之间的逻辑关系,即逻辑结构
- 数据计算
- 数据元素和元素之间关系在计算机的存储方式,也称作数据的物理结构
常见的数据结构
数据的逻辑结构与数据存储的位置无关,是描述元素之间的关系,通常根据数据的逻辑结构划分为**「线性数据结构」和「非线性数据结构」**,下图所表示就是基本的数据结构,非线性数据结构是比较复杂的数据结构,本文只介绍前 6 种基本的数据结构,旨在对基本的数据结构有一些印象,可能以后还会遇到「红黑树」「字典树」「跳表」等数据结构。
数组
数组是一种常见的数据结构,所有的编程语言都有数组,在java等强类型的编程语言中,数组的定义是将相同类型的元素存储于连续内存空间的数据结构,可以通过索引快速的访问到数组的元素。而在 JavaScript 中数组是一种特殊的对象,并且数组所存储的元素类型也是可以不同的,所以效率上并没有其他语言中数组高。
const arr = [] // 创建一个空数组
const arr1 = new Array(5) // 创建一个长度为5的数组
const arr2 = new Array(0,'0',true,{a:1},[1]) // 数组可以存储任何数据类型
typeof arr1 // object
Arrag.isArray(arr1) // true
链表
链表在内存的存储空间不是连续的,他是节点的集合,每个节点都是独立的对象,并且该节点还保存着下一个节点的引用地址。通常使用 val 表示当前节点值,next 表示下个节点地址,如果next 指向null 则是链表最后一个节点
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
// 定义节点,此时这几个节点在内存是不连续的,节点之间也是毫无关联的
const p0 = new ListNode(0)
const p1 = new ListNode(1)
const p2 = new ListNode(2)
// 使用 next 把上面节点关联起来,next 也被称作 链
p0.next = p1
p1.next = p2
p0 是链表的 头节点,节点值是 0 后续节点是 p1。p2 是链表的 尾结点,节点值是2,没有后续节点所以指向 null
栈
栈是一个「先进后出」的数据结构,可以使用数组实现栈,栈的两种主要操作是入栈和出栈,入栈是把元素压入到栈顶,出栈是将栈顶元素弹出。栈只能够访问栈顶元素,如果该元素不在栈顶,必须先拿掉该元素上面的元素。
const stack = []
// 入栈
stack.push(0)
stack.push(1)
// 出栈
stack.pop() // 1
stack.pop() // 0
队列
队列和栈是两个十分相似的数据结构,队列与栈的行为刚好相反「先进先出」,同样使用数组来实现。队列的操作同样有两种主要操作入队和出队,入队是将元素添加到队列队尾,出队是将队首元素弹出。
const queue = []
// 入栈
queue.push(0)
queue.push(1)
// 出栈
queue.shift() // 0
queue.shift() // 1
树
树是一种复杂的非线性数据结构,有边连接节点组成,可以根据子节点的数量区分为“多叉树”和“二叉树”。每个节点除了保存值之外,还存储者子节点信息,以二叉树为例,节点有左子节点和右子节点
function TreeNode(val,left,right){
this.val = (val===undefined ? 0 : val)
this.left = (left === undefined ? null:left)
this.right = (right === undefined ? null:right)
}
// 定义几个节点
const t0 = new TreeNode(0)
const t1 = new TreeNode(1)
const t2 = new TreeNode(2)
const t3 = new TreeNode(3)
// 把节点关联起来
t0.left = t1
t0.right = t2
t1.right = t3
下图描述了树的基本术语,最上面的节点称作根节点,如果一个节点下有一个或多个节点那么该节点称作父节点,相对应的下面的节点称作子节点,如果一个节点下面一个子节点也没有,那么该节点称作叶子结点。
哈希表
哈希表也称作为散列表,也是一种非线性数据结构,哈希表通过一个哈希函数对每一个键计算出一个唯一的索引。通过索引的方式快速访问键所对应的值。
举一个例子描述一下这个过程,
学校举行田径比赛,一共有三名同学参加,编号分别是1,2,3。比赛结束了,想要通过编号快速的查到选手的成绩。我们可以把这三名选手的成绩放到一个数组里面,1号选手成绩放在数组索引为1 的位置,依次类推。
在这个例子中可以理解为 哈希函数把选手编号计算为数组的索引,这样就能够快速的获取对应选手的成绩。由于编号是数字可能不怎么明显。假如说选手的编号是A,B,C 呢。这样就很好理解,把选手的 编号 通过 哈希函数 转化为对应的数组下标,函数函数返回的值就是 哈希值。
结尾
以上便是基本数据结构的介绍,作为前端coder,之前一直会认为,即使不学数据结构与算法,即便使用数组也可以很好的完成工作。其实如果不去学数据结构与算法,你就永远没办法感受到他的好处,赶快动手学起来吧!