Javascript数据结构与算法: 数据结构与算法简介

在学习数据结构与算法之前,我们得先清楚什么是数据结构?什么是算法?

  • 数据结构:数据的组织结构,用来组织、存储数据。
  • 算法:解决问题的方法或者过程。

为了更好的理解,我们可以把程序比作做菜。数据结构就是食材和调料,算法则是不同烹饪方式。不同的食材和调料,不同的烹饪方式,有着不同的排列组合。同样的东西,由不同的人做出来,味道自然也是千差万别。

为啥要学习算法和数据结构?

还是拿做菜为例,我们做菜讲究的色香味俱全。程序设计也是如此,对于解决问题,我们追求的是:选择合适的数据结构,使用花费时间更少、占用空间更小的算法。

数据结构

数据结构:数据的组织结构,用来组织、存储数据。

数据结构可以分为逻辑结构和物理结构。

逻辑结构

逻辑结构:数据元素的相互关系。

根据元素之间的相互关系,通常我们可以将数据的逻辑结构分为以下四种:

集合结构

集合结构:集合结构中的数据元素是无序的,并且每个数据元素都是唯一的,集合中没有相同的数据元素。

像javascript中的ES6中的Set、Map都可以看做是一个集合结构(严格意义来讲Map属于字典结构,但是字典结构属于一种键值对的集合,所以Map也是集合结构的一种)。

线性结构

线性结构: 数据元素(除了第一个和最后一个元素),左侧和右侧分别只有一个数据与其相邻。线性结构类型包括:数组、链表,以及由它们衍生出来的栈、队列、哈希表。

树形结构

树形结构:最简单的树形结构是二叉树。这种结构可以简单的表示为:根, 左子树, 右子树。 左子树和右子树又有自己的子树。当然除了二叉树,树形结构类型还包括:多叉树、字典树等。

图形结构

图形结构是一种比树形结构更复杂的非线性结构,用于表示物件与物件之间的关系。一张图由一些小圆点(称为 「顶点」「结点」 )和连结这些圆点的直线或曲线(称为 「边」)组成。

在图形结构中,任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的。图形结构类型包括:无向图、有向图、连通图等。

物理结构

物理结构:数据的逻辑结构在计算机中的存储方式。

计算机内有多种存储结构,采用最多的是这两种结构:「顺序存储结构」「链式存储结构」

顺序存储结构

将数据元素存放在一片地址连续的存储单元里,数据元素之间的逻辑关系通过数据元素的存储地址来直接反映。

这种结构的优点是:简单、易理解,且实际占用最少的存储空间。缺点是:需要占用一片地址连续的存储单元;并且存储分配要事先进行;另外对于一些操作的时间效率较低(移动、删除元素等操作)。

链式存储结构

将数据元素存放在任意的存储单元里,存储单元可以连续,也可以不连续。

链式存储结构中,一般将每个数据元素占用的若干单元的组合称为一个链结点。每个链结点不仅要存放一个数据元素的数据信息,还要存放一个指出这个数据元素在逻辑关系的直接后继元素所在链结点的地址,该地址被称为指针。换句话说,数据元素之间的逻辑关系是通过指针来间接反映的。

这种结构的优点是:存储空间不必事先分配,在需要存储空间的时候可以临时申请,不会造成空间的浪费;一些操作的时间效率远比顺序存储结构高(插入、移动、删除元素)。缺点是:

  • 不仅数据元素本身的数据信息要占用存储空间,指针也需要占用存储空间,链式存储结构比顺序存储结构的空间开销大。
  • 因为链表不像数组那样拥有下标值,查找某个数据元素信息,只能从头部开始一个一个查找,这种线性的查找方式,显然比数组通过下标值查找数据元素要慢。

算法

算法: 指的就是解决问题的方法。

展开来讲,算法是某一系列运算步骤,它表达解决某一类计算问题的一般方法,对这类方法的任何一个输入,它可以按步骤一步一步计算,最终产生一个输出。它不依赖于任何一种语言,可以用 自然语言、编程语言(Javascript、Python、C、C++、Java 等)描述 ,也可以用 伪代码、流程图 来表示。

下面我们举几个例子来说明什么是算法:

  • 示例1:
txt 复制代码
问题描述:
从上海到北京,应该怎么去?

解决方法:
1.坐飞机:费用高但时间短。
2.做长途汽车:费用低但时间长。
3.做高铁:时间与费用刚好合适。
  • 示例2:
txt 复制代码
问题描述:
如何计算1 + 2 + 3 + 4 + ... + 100的值?

解决方法:
1.用计算器从1开始,依次加到100,得出结果为5050。
2.根据高斯求和公式,和 = (首项 + 末项) * 项数 / 2, 直接得出结果:(1 + 100) * 100 / 2 = 5050;

以上两个示例中的解决方法都可以看做是算法。从上海去北京的解决方法可以看做是算法,对 1∼1001 \sim 1001∼100 的数进行求和的计算方法也可以看做是算法。并且从这两个示例中可以看出对于一个特定的问题,往往有着不同的算法。

算法的基本特性

算法其实就是一系列的运算步骤,这些运算步骤可以解决特定的问题。除此之外,算法 应必须具备以下特性:

  1. 输入:对于待解决的问题,都要以某种方式交给对应的算法。在算法开始之前最初赋给算法的参数称为输入。比如示例1中的输入就是出发地和目的地的参数(北京,上海)。一个算法可以有多个输入,也可以没有输入。比如示例2是对固定问题的求解,就可以看做没有输入。
  2. 输出:算法是为了解决问题存在的,最终总需要返回一个结果。所以至少需要一个或多个参数作为算法的输出。比如示例1中的输出就是最终选择的交通方式,示例2中的输出就是和的结果。
  3. 有穷性:算法必须在有限的步骤内结束,并且应该在一个可接受的时间内完成。比如示例1,如果我们选择五一从上海到北京去旅游,结果五一纠结了三天也没决定好怎么去北京,那么这个旅游计划也就泡汤了,这个算法自然也是不合理的。
  4. 确定性:组成算法的每一条指令必须有着清晰明确的含义,不能令读者在理解时产生二义性或者多义性。就是说,算法的每一个步骤都必须准确定义而无歧义。
  5. 可行性:算法的每一步操作必须具有可执行性,在当前环境条件下可以通过有限次运算实现。也就是说,每一步都能通过执行有限次数完成,并且可以转换为程序在计算机上运行并得到正确的结果。

算法追求的目标

研究算法的作用,就是为了使解决问题的方法变得更加高效。对于给定的问题,我们往往会有多种算法来解决。而不同算法的 成本 也是不同的。总体而言,一个优秀的算法至少应该追求以下两个目标:

  1. 所需运行时间更少(时间复杂度更低)
  2. 占用内存空间更小(空间复杂度更低)

假设计算机执行一条命令的时间为1纳秒(并不科学),第一种算法需要执行100纳秒,第二种算法则需要执行3纳秒。如果不考虑占用内存空间的话,很明显第二种算法比第一种算法要好很多。

假设计算机一个内存单元的大小为一个字节,第一种算法需要占用3个字节大小的内存空间,第二种算法则需要占用100个字节大小的内存空间,如果不考虑运行时间的话,很明显第一种算法比第二种算法要好很多。

现实中算法,往往是需要同时从运行时间、占用空间两个方面考虑问题。当然,运行时间越少,占用空间越小的算法肯定是越好的,但总是会有各种各样的因素导致了运行时间和占用空间不可兼顾。比如,在程序运行时间过高时,我们可以考虑在空间上做文章,牺牲一定量的空间,来换取更短的运行时间。或者在程序对运行时间要求不是很高,而设备内存又有限的情况下,选择占用空间更小,但需要牺牲一定量的时间的算法。

当然,除了对运行时间和占用内存空间的追求外,一个好的算法还应该追求以下目标:

  1. 正确性:正确性是指算法能够满足具体问题的需求,程序运行正常,无语法错误,能够通过典型的软件测试,达到预期的需求。
  2. 可读性:可读性指的是算法遵循标识符命名规则,简洁易懂,注释语句恰当,方便自己和他人阅读,便于后期修改和调试。
  3. 健壮性:健壮性指的是算法对非法数据以及操作有较好的反应和处理。

这3个目标是算法的基本标准,是所有算法所必须满足的。一般我们对好的算法的评判标准就是上边提到的 所需运行时间更少(时间复杂度更低)占用内存空间更小(空间复杂度更低)

相关推荐
Jiaberrr11 分钟前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ2 小时前
html+css+js实现step进度条效果
javascript·css·html
john_hjy3 小时前
11. 异步编程
运维·服务器·javascript
风清扬_jd3 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
yanlele3 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
It'sMyGo3 小时前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
xgq4 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
李是啥也不会4 小时前
数组的概念
javascript