Javascript数据结构与算法
什么是数据结构与算法
可能你之前经常在很多地方都看到有人讨论数据结构和算法
,但是它到底是什么一直云里雾里 因为似乎我们学习编程的过程中,没有必要了解这些,我们只是在学习一门语言的基本语法/高级语法/做出界面效果/实现复杂逻辑就可以了 数据结构和算法?它是什么?I don’t care? 如果我们只是想了解语言的应用层面
,那么数据结构和算法显得没有那么重要 但是如果我们希望了解语言的设计层面
,那么数据结构和算法就非常的重要 Java的线性结构列表中,有ArrayList和LinkedList,怎么选择? — 死记住规则,你也可以很好的选择,但是如果你了解它们底层的数据结构就会非常清晰的知道如何选择 数据结构的民间定义 (1) 数据结构是数据对象,以及存在于该对象的实例和组成实例的数据元素之间的各种联系,这些联系可以通过定义相关的函数给出来 —《数据结构、算法与应用》 (2)数据结构是ADT(抽象数据类型 Abstract Data Type)的物理实现 — 《数据结构与算法分析》 (3)数据结构(data structure)是计算机存储、组织数据的方式。通常情况下,精心选择的数据结构可以带来最有效率的算法 — 中文维基百科 从自己的角度认识数据结构 (1)数据结构就是在计算机中存储和组织数据的方式 (2)我们知道,计算机中数据量非常庞大,任何以高效的方式组织和存储呢? (3)这好比一个庞大的图书馆中存放了大量的书籍,我们不仅仅要把书放进去,还应该在合适的时候快速的将其取出来 常见的数据结构 (1)每一种都有其对应的应用场景,不同的数据结构
的不同操作
性能是不同的 (2)有的查询性能很快,有的插入速度很快,有的是插入头和尾速度很快 (3)有的做范围查找很快,有的允许元素重复,有的不允许重复等 (4)在开发中任何选择,要根据具体的需求来选择 什么是算法(Algorithm) (1)我们可能已经接触过几种排序算法,并不知道不同的算法执行效率是不一样的 (2)解决问题的过程中,不仅仅数据的存储方式会影响效率,算法的优劣也会影响着效率 算法定义:解决问题的办法/步骤逻辑 (1)一个有限指令集,每条指令的描述不依赖于语言 (2)接受一些输入,有些情况下不需要输入 (3)产生输出 (4)一定在有限步骤之后终止
线性结构
数组
JS中的数据就是API的调用,因为JS对数组的封装已经非常完善了 普通语言的数组封装(比如Java的ArrayList) (1)常见语言的数据不能存放不同类型的数据,因此在封装时通常存放在数据中的是Object类型 (2)常见语言的数组容量不会自动改变,需要进行扩容操作 (3)常见语言的数组进行中间插入和操作性能比较低
数组使用的API
链表
链表原理
自定义链表
双向链表
栈
栈也是一种非常常见的数据结构,并且在程序中的应用非常广泛 数组 (1)我们知道数组是一种线性结构,并且可以在数组的任意位置插入和删除数据 (2)但是有时候,我们未来实现某些功能,必须对这种任意性
加以限制
(3)而栈
和队列
就是比较常见的受限的线性结构
栈(Stack),它是一种受限的线性表,后进先出(LIFO
) (1)其限制是仅允许在表的一端
进行插入和删除元素,这一端称为栈顶
,相对地,把另一端称之为栈底 (2)LIFO(Last In First Out)表示就是后进入的元素,第一个弹出栈空间,类似于自动托盘,最后放上的托盘,往往先拿出去使用 (3)向一个栈中插入新元素称之为进栈
、入栈
或压栈
,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素 (4)从一个栈中删除元素称之为出栈
或退栈
或弹栈
,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素 栈的面试题:有6个元素6,5,4,3,2,1顺序进栈,即6进栈后5再进栈(理解本题是:不要求一次性进栈),问下面那个不是合法的出站序列?(C ) A
. 5 4 3 6 1 2 B
. 4 5 3 2 1 6 C
. 3 4 6 5 2 1 D
. 2 3 4 1 5 6
自定义栈
实现栈结构有两种比较常见的方式:基于数组
实现 + 基于链表
实现
栈常见的操作
push(e) :压栈,向栈顶中添加新元素pop() :弹栈,移除栈顶元素并返回被移除的元素peek() :返回栈顶元素,不对栈做任何修改isEmpty() :判断栈是否为空栈size() :返回栈中元素的个数toString() :将栈结构的内容以字符串形式返回
栈的封装
< script>
function Stack ( ) {
this . items = [ ] ;
}
Stack. prototype. push = function ( e) {
this . items. push ( e) ;
}
Stack. prototype. pop = function ( ) {
return this . items. pop ( ) ;
}
Stack. prototype. peek = function ( ) {
return this . items[ this . items. length - 1 ] ;
}
Stack. prototype. isEmpty = function ( ) {
return this . items. length === 0 ;
}
Stack. prototype. size = function ( ) {
return this . items. length;
}
Stack. prototype. toString = function ( ) {
let resultString = "" ;
for ( let i = 0 ; i < this . items. length; i++ ) {
resultString += this . items[ i] + " " ;
}
return resultString;
}
let s = new Stack ( ) ;
s. push ( 10 ) ;
s. push ( 1 ) ;
s. push ( 20 ) ;
s. push ( 2 ) ;
console. log ( s. toString ( ) ) ;
console. log ( s. size ( ) ) ;
console. log ( s. isEmpty ( ) ) ;
while ( s. size ( ) ) {
console. log ( s. pop ( ) ) ;
}
< / script>
栈的应用
十进制转二进制
现实生活中我们主要使用的是十进制,但是计算科学中,二进制是非常重要的,因为计算机里面所有内容都是用二进制数字表示的,没有十进制和二进制相互转换的能力,与计算机交流很困难
let dec = 101 ;
let s0 = new Stack ( ) ;
do {
s0. push ( dec % 2 ) ;
dec = parseInt ( dec / 2 ) ;
} while ( dec) ;
let bin = "" ;
while ( s0. size ( ) ) {
bin += s0. pop ( ) ;
}
console. log ( bin) ;
队列
队列(Queue):受限的线性结构,先进先出FIFO
(First In First Out) (1)受限之处在于它只允许在表的前端(front)
进行删除操作 (2)在表的后端(rear)
进行插入操作
自定义队列
队列的实现和栈一样,有两种方案: 基于数组
实现 + 基于链表
实现
队列常见的操作
enqueue(e) :进队操作,向队列尾部添加一个或多个元素dequeue() :删除队列中头部的元素并返回被删除的元素front() :返回队列头部元素但队列不做任何操作!取出最先被添加的元素isEmpty() :判断队列是否为空size() :返回队列中包含的元素个数toString() :将队列中的内容,转成字符串形式
队列的封装
< script>
function Queue ( ) {
this . items = [ ] ;
}
Queue. prototype. enqueue = function ( e) {
this . items. push ( e) ;
}
Queue. prototype. dequeue = function ( ) {
return this . items. shift ( ) ;
}
Queue. prototype. front = function ( ) {
return this . items[ 0 ] ;
}
Queue. prototype. isEmpty = function ( ) {
return this . items. length === 0 ;
}
Queue. prototype. size = function ( ) {
return this . items. length;
}
Queue. prototype. toString = function ( ) {
let resultString = "" ;
for ( let i = 0 ; i < this . items. length; i++ ) {
resultString += this . items[ i] + " " ;
}
return resultString;
}
let queue = new Queue ( ) ;
queue. enqueue ( 10 )
queue. enqueue ( 1 ) ;
queue. enqueue ( 20 ) ;
queue. enqueue ( 2 ) ;
while ( queue. size ( ) ) {
console. log ( queue. dequeue ( ) ) ;
}
< / script>
优先级队列
队列的应用
打印队列 (1)有5份文档需要打印,这些文档会按照次序
放入到打印队列
中 (2)打印机会一次从队列中取出文档,优先放入的文档
,优先被取出
,并且对该文档进行打印 (3)以此类推,直到队列中不再有新的文档 线程队列 (1)在开发中,为了让任务可以进行处理,通常会开启多个线程
(2)但是,我们不能让大量的线程同时运行处理任务,那样会占用过多的资源 (3)这个时候如果有需要开启线程处理任务的情况,我们就会使用线程队列
(4)线程队列会依照次序
来启动线程并且处理对应的任务
哈希表
哈希表理论
认识哈希表
认识哈希化
地址的冲突
哈希表效率
自定义哈希表
哈希函数
哈希表实现
哈希扩容
树结构
树相关的概念
树的基本概念
二叉树的概念
二叉搜索树
图结构
排序&搜索