数据结构—队列
队列队列和栈一样,也是一种对数据的”存”和”取”有严格要求的线性存储结构。与栈结构不同的是,队列的两端都”开口”,要求数据只能从一端进,从另一端出,如图1 所示:
图 1 队列存储结构
通常,称进数据的一端为 “队尾”,出数据的一端为 “队头”,数据元素进队列的过程称为 “入队”,出队列的过程称为 “出队”。
不仅如此,队列中数据的进出要遵循 “先进先出” 的原则,即最先进队列的数据元素,同样要最先出队列。拿图 1 中的队列来说,从数据在队列中的存储状态可以分析出,元素 1 最先进队,其次是元素 2,最后是元素 3。此时如果将元素 3 出队,根据队列 “先进先出” 的特点,元素 1 要先出队列,元素 2 再出队列,最后才轮到元素 3 出队列。
栈和队列不要混淆,栈结构是一端封口,特点是”先进后出”;而队列的两端全是开口,特点是”先进先出”。
因此,数据从表的一端进,从另一端出,且遵循 “先进先出” 原则的线性存储结构就是队列。
队列的实现队列存储结构的实现有以下两种方式:
顺序队列:在顺序表的基础上实现的队列结构;
链队列:在链表的基础上实现的队列结构;
两者的区别仅是顺序表和链表 ...
数据结构—栈
图 1 栈存储结构示意图
从图 1 我们看到,栈存储结构与之前所学的线性存储结构有所差异,这缘于栈对数据 “存” 和 “取” 的过程有特殊的要求:
栈只能从表的一端存取数据,另一端是封闭的,如图 1 所示;
在栈中,无论是存数据还是取数据,都必须遵循”先进后出”的原则,即最先进栈的元素最后出栈。拿图 1 的栈来说,从图中数据的存储状态可判断出,元素 1 是最先进的栈。因此,当需要从栈中取出元素 1 时,根据”先进后出”的原则,需提前将元素 3 和元素 2 从栈中取出,然后才能成功取出元素 1。
因此,我们可以给栈下一个定义,即栈是一种只能从表的一端存取数据且遵循 “先进后出” 原则的线性存储结构。
通常,栈的开口端被称为栈顶;相应地,封口端被称为栈底。因此,栈顶元素指的就是距离栈顶最近的元素,拿图 2 来说,栈顶元素为元素 4;同理,栈底元素指的是位于栈最底部的元素,图 2 中的栈底元素为元素 1。
图 2 栈顶和栈底
进栈和出栈基于栈结构的特点,在实际应用中,通常只会对栈执行以下两种操作:
向栈中添加元素,此过程被称为”进栈”(入栈或压栈);
从栈中提取出指定元素,此过程被称为 ...
数据结构—静态链表
静态链表,也是线性存储结构的一种,它兼顾了顺序表和链表的优点于一身,可以看做是顺序表和链表的升级版。
使用静态链表存储数据,数据全部存储在数组中(和顺序表一样),但存储位置是随机的,数据之间”一对一”的逻辑关系通过一个整形变量(称为”游标”,和指针功能类似)维持(和链表类似)。
例如,使用静态链表存储 {1,2,3} 的过程如下:
创建一个足够大的数组,假设大小为 6,如图 1 所示:
图 1 空数组
接着,在将数据存放到数组中时,给各个数据元素配备一个整形变量,此变量用于指明各个元素的直接后继元素所在数组中的位置下标,如图 2 所示:
图 2 静态链表存储数据
通常,静态链表会将第一个数据元素放到数组下标为 1 的位置(a[1])中。
图 2 中,从 a[1] 存储的数据元素 1 开始,通过存储的游标变量 3,就可以在 a[3] 中找到元素 1 的直接后继元素 2;同样,通过元素 a[3] 存储的游标变量 5,可以在 a[5] 中找到元素 2 的直接后继元素 3,这样的循环过程直到某元素的游标变量为 0 截止(因为 a[0] 默认不存储数据元素)。
类似图 2 这 ...
数据结构—顺序表和链表区别
顺序表和链表的优缺点(区别、特点)详解顺序表和链表由于存储结构上的差异,导致它们具有不同的特点,适用于不同的场景。本节就来分析它们的特点,让读者明白 “在什么样的场景中使用哪种存储结构” 更能有效解决问题。
通过系统地学习顺序表和链表我们知道,虽然它们同属于线性表,但数据的存储结构有本质的不同:
顺序表存储数据,需预先申请一整块足够大的存储空间,然后将数据按照次序逐一存储,数据之间紧密贴合,不留一丝空隙,如图 1a) 所示;
链表的存储方式与顺序表截然相反,什么时候存储数据,什么时候才申请存储空间,数据之间的逻辑关系依靠每个数据元素携带的指针维持,如图 1b) 所示;
基于不同的存储结构,顺序表和链表有以下几种不同。
开辟空间的方式顺序表存储数据实行的是 “一次开辟,永久使用”,即存储数据之前先开辟好足够的存储空间,空间一旦开辟后期无法改变大小(使用动态数组的情况除外)。
而链表则不同,链表存储数据时一次只开辟存储一个节点的物理空间,如果后期需要还可以再申请。
因此,若只从开辟空间方式的角度去考虑,当存储数据的个数无法提前确定,又或是物理空间使用紧张以致无法一次性申请到足 ...
数据结构—链表
链表,别名链式存储结构或单链表,用于存储逻辑关系为 “一对一” 的数据。与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。
例如,使用链表存储 {1,2,3},数据的物理存储状态如图 1 所示:
图 1 链表随机存储数据
我们看到,图 1 根本无法体现出各数据之间的逻辑关系。对此,链表的解决方案是,每个数据元素在存储时都配备一个指针,用于指向自己的直接后继元素。如图 2 所示:
图 2 各数据元素配备指针
像图 2 这样,数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构。
链表的节点从图 2 可以看到,链表中每个数据的存储都由以下两部分组成:
数据元素本身,其所在的区域称为数据域;
指向直接后继元素的指针,所在的区域称为指针域;
即链表中存储各数据元素的结构如图 3 所示:
图 3 节点结构
图 3 所示的结构在链表中称为节点。也就是说,链表实际存储的是一个一个的节点,真正的数据元素包含在这些节点中,如图 4 所示:
图 4 链表中的节点
因此,链表中每个节点的具体实现,需要使用 C ...
数据结构—顺序表
顺序表,全名顺序存储结构,是线性表的一种。通过《线性表》一节的学习我们知道,线性表用于存储逻辑关系为“一对一”的数据,顺序表自然也不例外。
不仅如此,顺序表对数据的物理存储结构也有要求。顺序表存储数据时,会提前申请一整块足够大小的物理空间,然后将数据依次存储起来,存储时做到数据元素之间不留一丝缝隙。
例如,使用顺序表存储集合 {1,2,3,4,5},数据最终的存储状态如图1 所示:
图 1 顺序存储结构示意图
由此我们可以得出,将“具有 ‘一对一’ 逻辑关系的数据按照次序连续存储到一整块物理空间上”的存储结构就是顺序存储结构。
通过观察图 1 中数据的存储状态,我们可以发现,顺序表存储数据同数组非常接近。其实,顺序表存储数据使用的就是数组。
顺序表的初始化使用顺序表存储数据之前,除了要申请足够大小的物理空间之外,为了方便后期使用表中的数据,顺序表还需要实时记录以下 2 项数据:
顺序表申请的存储容量;
顺序表的长度,也就是表中存储数据元素的个数;
提示:正常状态下,顺序表申请的存储容量要大于顺序表的长度。
因此,我们需要自定义顺序表,C 语言实现代码如下:
12 ...
数据结构
数据结构三要数数据逻辑结构逻辑结构是指数据元素之间的逻辑关系,即从逻辑关系上描述数据。它与数据的存储无关,是独立于计算机的。数据的逻辑结构分为线性结构和非线性结构,线性表是典型的线性结构;集合、树和图是典型的非线性结构。数据的逻辑结构分类见图 1-1。
集合结构中的数据元素之间除了 “同属于一个集合”的关系外,别无其他关系。
线性结构中的数据元素之间只存在一对一的关系。即线性表:顺序表(一维数组)、链表、栈、队列
树形结构中的数据元素之间存在一对多的关系。普通树、二叉树、线索二叉树等
图状结构或网状结构结构中的数据元素之间存在多对多的关系。
数据的存储结构存储结构是指数据结构在计算机中的表示(又称映像),也称物理结构。它包括数据元素的表示和关系的表示。数据的存储结构是逻辑结构用计算机语言的实现,它依赖于计算机语言。数据的存储结构主要有:顺序存储、链式存储、索引存储和散列存储。
顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元里,元素之间的关系由存储单元的邻接关系来体现。其优点是可以实现随机存取,每个元素占用最少的存储空间;缺点是只能使用相邻的一整块 ...
js事件循环
最近在看关于 js 的事件循环机制,(很多公司必问的面试题)看了几篇文章后准备总结出来分享给大家
众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心,,可是浏览器又能很好的处理异步请求,那么到底是为什么呢?
浏览器执行线程
在解释事件循环之前首先先解释一下浏览器的执行线程:浏览器是多进程的,浏览器每一个 tab 标签都代表一个独立的进程,其中浏览器渲染进程(浏览器内核)属于浏览器多进程中的一种,主要负责页面渲染,脚本执行,事件处理等其包含的线程有:GUI 渲染线程(负责渲染页面,解析 HTML,CSS 构成 DOM 树)、JS 引擎线程、事件触发线程、定时器触发线程、http 请求线程等主要线程
关于执行中的线程:主线程:也就是 js 引擎执行的线程,这个线程只有一个,页面渲染、函数处理都在这个主线程上执行。工作线程:也称幕后线程,这个线程可能存在于浏览器或 js 引擎内,与主线程是分开的,处理文件读取、网络请求等异步事件。
任务队列( Event Queue )
所有的 ...
js引擎解析过程
语法检查语法检查是 JavaScript 解析器的工作之一,包括 Î词法分析和语法分析
词法分析把 JavaScript 代码(字符创)逐字转换为标记流
例如:
1// a = (b - c);
转换为:
12345678NAME "a"EQUALSOPEN_PARENTHESISNAME "b"MINUSNAME "c"CLOSE_PARENTHESISSEMICOLON
语法分析语法分析:JavaScript 语法分析器在经过词法分析后,将记号流按照 ECMAScript 标准把词法分析所产生的记号生成语法树 AST。
运行阶段预解析
将 JavaScript 引擎将语法检查正确后生成的语法树复制到当前执行上下文中。
JavaScript 引擎会对语法树当中的变量声明、函数声明以及函数的形参进行属性填充( 声明提升)。
执行上下文包括:变量对象、作用域链、this
变量对象(Variable Object):由变量声明(var declaration)、函数声明(function declaration)、参数( ...
js原型链
先看第一行我们定义的 show 函数在 Foo.prototype 中,当我们执行 f1.show()时,js 发现 f1 本身没有 show 这个属性,所以它就到 f1 的原型(也就是__proto__指向的对象)去找,找到了就可以调用。
注:每个对象都有一个方法 hasOwnProperty()来检查对象本身是否有某个属性,如果有则返回 true;如果这个属性在它的原型链上或原型链上都没有,则返回 false;
图片第一行告诉了我们 4 点:
所有函数都有一个 prototype 指针,指向原型对象,如图中的 Foo 的 prototype 指针。prototype 指针的意义是,当我们使用这个构造函数 new 出新对象的时候,新对象的原型是谁。
构造函数的 prototype 所指向的原型对象有一个 constructor 指针,指回构造函数。如图中 Foo.prototype 的 constructor 指针指向 Foo。constructor 指针有助于我们找到一个对象的构造函数是谁。
__proto__每个对象都有,js 在 new 一个对象的时候,会将它的__pr ...