数据结构

 

数据结构概念

数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及它们之间的关系和操作等相关问题的学科,是相互之间存在一种或多种特定关系的数据元素的集合。

数据: 描述客观事物的符号,是计算机中可以操作的对象,能被计算机识别,并可以输入给计算机处理的符号集合。
结构: 指数据集合中各个组成部分相互搭配和排列的方式,也就是数据关系。
程序设计 = 数据结构 + 算法

 

逻辑结构和物理结构

逻辑结构: 数据对象中数据元素之间的相互关系。是数据结构研究的重点问题。
 1. 集合结构: 集合中数据元素除了同属于一个集合外,它们相互之间没有其他关系,各个数据元素之间是相互独立、平等的。
 2. 线性结构: 集合中数据元素之间是一对一的关系。
 3. 树形结构: 集合中数据元素之间存在一种一对多的层次关系。
 4. 图形结构: 集合中数据元素之间是多对多的关系。

物理结构: 数据的逻辑结构在计算机中的存储形式。描述的是不同逻辑结构的数据元素在计算机中的存储结构问题。
 1. 顺序存储结构:把数据元素依次存放在地址连续的存储单元里。例如数组的存储。
 2. 链式存储结构: 把数据元素存放在任意连续或者不连续的存储单元里。一般是用一个指针存放数据元素的地址,通过地址找到相关联数据的位置。当前元素知道它上一个和下一个元素的地址,而不知道第三个元素的地址。
逻辑结构是面向问题的,物理结构是面向计算机的。

 

算法

算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
算法的特性: 输入、输出、有穷性、确定性和可行性。
算法的设计要求: 正确性、可读性、健壮性、高效和低存储量。
算法的效率: 实现算法的函数中的常数和其他次要项常常可以忽略,而应该主要关注主项(最高阶项)的阶数(指数),这个指标就是算法复杂度。主要关注的是算法的执行次数跟数据量N的关系。


时间复杂度

算法的执行时间与算法中语句的执行次数成正比。一个算法的执行次数称为算法的时间频度,记为T(n)。当n趋于无穷大时,若函数O(f(n))是与T(n)同数量级的函数,则O(f(n))称为算法的时间复杂度。
算法复杂度推导:在运行次数函数中,只保留最高阶项,如果最高阶项是n,则时间复杂度就是O(n)。时间复杂度描述的是算法执行次数随数据量n变化(增长)的关系。要分析算法的复杂度,关键就是要分析循环结构的运行情况。
常数阶:若算法的执行次数跟数据量n没有关系,则这个算法的时间复杂度是O(1)。
线性阶:若算法的执行次数跟数据量n成正比关系,则这个算法的时间复杂度是O(n)。
平方阶:若算法的执行次数跟数据量n成平方关系,则这个算法的时间复杂度是O(n^2)。

 

线性表

线性表是零个或多个数据元素的有限序列(存在顺序关系)。强调有顺序关系和有限性。如排队关系、月份表等。
线性表除第一个元素a1外,每个元素有且只有一个直接前驱元素,除了最后一个元素,每个元素有且只有一个直接后继元素。
线性表涉及的主要操作:初始化、插入元素、删除元素、位置查询、长度查询、非空判断、清空。
线性表通过地址标号来存入和取出数据,时间消耗是固定的常数,所以线性表的存取时间性能为O(1)。

线性表的插入操作
1. 如果插入位置不合理,则抛出异常;
2. 如果线性表长度大于等于数组长度,则抛出异常或者动态增加容量。
3. 把第i个位置之后的所有元素都后移一个位置;
4. 将元素插入i处,表长加1。

线性表的删除操作
1. 如果删除位置不合理,抛出异常;
2. 取出删除元素;
3. 将删除位置之后的每个元素前移一个位置;表长减1。

线性表的顺序存储结构和链式存储结构
线性表顺序存储结构特点:
1. 存储、读取数据的时间复杂度是O(1),插入、删除元素的时间复杂度是O(n),比较适合元素个数不多,插入删除操作少的场合。
2. 当线性表长度变化较大时,难以确定存储空间大小。易造成存储空间的碎片。
链式存储结构中每个结点包含一个数据域和一个指针域,数据域中存放当前结点的数据,指针域存放指向的下一个数据的指针。
链表中第一个结点的存储位置叫做头指针,最后一个结点的指针指向空。
有的链表存在头结点(数据区为空或写入链表长度等信息,指针指向链表中第一个元素)。
链表读取元素的时间复杂度是O(n),插入和删除元素的时间复杂度是O(1)。

 

循环链表

将单链表中终端结点的指针端由空指针指向头结点,使整个单恋表形成一个闭环,这种头尾相接的单链表称为单循环链表,简称循环链表。
循环链表解决来单链表不能从当中一个结点出发,访问到全部结点的问题。循环链表中判断循环结束的判定条件是结点指针是不是指向来起始指针。

单循环链表中的尾指针
带头结点的单循环链表中一般会设置尾指针而不是头指针,这是因为使用尾巴指针查找尾结点和头结点的时间复杂度都是O(1),而使用头指针的复杂度分别是O(1)和O(n)。并且使用尾指针在合并两个单循环链表上也比头指针简单方便。

双向链表
双向链表是在单链表的每个结点中, 再设置一个指向它前驱结点的指针域。
结点中的第一个指针域指向直接前驱,中间是结点数据域,后一个指针域指向直接后驱。所以在插入和删除时,需要分别改变两个指针变量。

 

数据结构中的栈

栈是一种先进去后出来(后进先出)的数据结构,也就是限定仅在表尾进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),栈是一种后进先出(Last In First Out)的线性表,简称LIFO结构。
例如浏览器中的后退功能,文档或图像编辑软件如Word等的撤销操作,都是用栈的方式实现的。
栈的插入操作,叫入栈,栈的删除操作,叫出栈(都只能在栈顶操作)。
最先进栈的元素就只能最后出吗?答案是否定的。如果是一系列元素一次性通过入栈操作写入,则最先进去的元素一定是最后出栈的,但是如果是在入栈过程中涉及到元素出栈操作,则并非是最先进去最后出来的,也可以做到最先进去最先出来。
在栈中一般定义一个top变量来指示栈顶元素在数组中的位置。当栈中只存在一个元素时,top=0 ,所以把空栈的判定条件定义为 top=-1 。
链栈中通常将栈顶元素作为链表的头部,一般也不需要头结点了。

栈在递归调用在的应用:在递归调用的前行阶段,对于每一层递归,函数的局部变量、参数值及返回地址都被压入栈中; 在退回截断,位于栈顶的局部变量、参数值和返回地址被弹出,依次恢复调用状态。

栈在四则运算表达式求值中的应用
后缀表达式是指所有的符号都是要在运算数字的后边出现的四则运算表达式。
使用栈计算后缀表达式的结果的规则: 从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
中缀表达式(我们使用的标准四则运算表达式)转后缀表达式规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于或等于栈顶符号则栈顶元素依次出栈并输出,并将当前符号进栈,直到最终输出后缀表达式为止。

 

队列

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先进先出(First In First Out)的线性表,简称FIFO,允许插入的一端称为队尾,允许删除的一端称为队头。应用如打车排队、操作排队、键盘输入等。
循环队列:为了避免数组插入和删除时需要移动数据,引入了循环队列,使得队头和队尾可以在数组中循环变换,解决了移动数据的时间消耗,使得插入和删除的时间复杂度由O(n)缩小到了O(1)。循环队列是事先申请好内存空间,中间不释放。
链队列:删除和插入(只能在队头删除,队尾插入)时间复杂度也是O(1),每个结点需要一个指针域,比循环队列多了一些空间开销,但是每次可以动态申请释放内存。    

 

字符串

字符串(string)是由零个或多个字符组成的有限序列。 线性表中更关注的是单个元素的操作,如查找、插入或删除元素,但在字符串中更多的是查找子字符串的位置、替换子字符串等操作。
字符串的顺序存储结构:顺序存储结构是用一组地址连续的存储单元来存储字符串中的字符序列。字符串的存储空间可以在程序执行过程中动态分配得到。如malloc函数分配位于“堆”上的空间。
字符串的链式存储结构:字符串的链式存储结构中,一般考虑一个结点存放多个字符,以减少指针域比较多带来的空间浪费。
链式存储在字符串连接上具有优势,但一般链式存储不如顺序存储灵活,性能也没有顺序存储结构好。
子串在字符串中的定位操作统称称为串的模式匹配,是字符串中最重要的操作之一。串的模式匹配方法有:朴素的模式匹配算法、KMP模式匹配算法(避免一部分重复匹配操作)、改进的KMP模式匹配算法。


树(Tree)是由n个结点组成的有限集合。任意n>=1的树具有以下特征:
1. 有且仅有一个特定的称为根(Root)的结点;
2. n>1时其余结点可分为m个互不相交的有限集 T1、T2,,Tm,其中每个集合本身又是一棵树,称为根的子树(SubTree)
树的结点包含一个数据元素和若干个指向其子树的分支。结点拥有的子树数(分支数)称为结点的度(Degree)。
度为0的结点称为叶结点(Leaf)或终端结点。
度不为0的结点称为分支结点,或内部结点(除根结点外)。
树的度是树内各结点的度的最大值,也就是内部结点的最大分支数。
结点的层次从根结点开始,根结点是第一层,其子结点是第二层,依次类推,树中结点的最大层次称为树的深度或高度。
有序树和无序树:若树中结点的各子树的排列从左到右是有次序不能互换的,则该树是有序树,否则是无序树。

树的存储结构
双亲表示法
以一组连续空间存储树的结点,同时在每个结点中,增加一个指示器指示其双亲结点在数组中的下标。所以一个是数据域,一个是指针域(数组的下标)。其中指针域可以不止有双亲,还可以有右兄弟的指针,或者还可以添加长子的指针。
孩子表示法
把每个结点的孩子结点排列起来, 以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。
孩子兄弟表示法
任意一棵树,它的结点的第一个孩子如果存在就是惟一的,它的右兄弟如果存在也是唯一的,所以可以设计两个指针,分别指向该结点的第一个孩子和该结点的右兄弟。当然也可以增加一个指向该结点的双亲结点地址。

 

二叉树

二叉树(Binary Tree)是n个结点的有限集合,该集合由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。特点:
1. 每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
2. 左右子树是有顺序的。
3. 即使只有一个子树,也需要区分它是左子树还是右子树。

特殊二叉树
斜树、满二叉树、完全二叉树(属于满二叉树的一种,要求每个子结点都有左右子树)

二叉树的性质
1. 二叉树的第i层上最多有2^(i-1)个结点。
2. 深度为k的二叉树最有有2^k-1个结点。

二叉树的遍历
二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次(仅仅一次)。
前序遍历:根结点 ---> 左子树 ---> 右子树。


中序遍历:左子树---> 根结点 ---> 右子树。

后序遍历:左子树 ---> 右子树 ---> 根结点。

层序遍历:从树的第一层根结点开始访问,而后从上到下逐层遍历,同一层中从左到右访问。


赫夫曼树(哈夫曼树)和赫夫曼编码

给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
构建哈夫曼树: 先把序列按从小到大排列,每次取出最小的前两个作为一棵树,类推递归。 例子: https://jingyan.baidu.com/article/a501d80c16dfa0ec620f5e70.html
哈夫曼编码: 研究哈夫曼树这种最优树是为了解决数据压缩的最优化问题。
对于一个字符串来说,里边每个字符出现的概率是不一样的,相当于权值不一样,可以用哈夫曼树解决。具体方法是:按照权值(出现概率)不同,把所有字符按照依据哈夫曼树排列,然后把哈夫曼树上所有左分支改为0,所有右分支改为1(即权值改为0和1),之后用从根结点到叶子所经过的路径上的0和1来编码叶子上的字符。

 

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为G(V,E),G表示一个图,V是图G中顶点的集合,E是图G中边的集合。图中的顶点的概念相当于线性表中的元素的概念。
无向边: 若图中两个顶点之间的边没有方向,则这条边是无向边,这个图是无向图。
有向边: 若图中两个顶点之间的边有方向,则这条边是有向边,这个图是有向图。
无向完全图: 无向图中任意两个顶点之间都存在边,则图是无向完全图。
有向完全图: 有向图中任意两个顶点之间都存在方向互为相反的两条弧,则图是有向完全图。
连通图: 如果从图中任意两个顶点之间是连通的,则图是连通图。
强连通图: 在有向图中,如果任意两点之间存在双向的连通通路,则图是强连通图。


图的存储结构
邻接矩阵
用两个数组的组合来表示图,一个一维数组存储图中顶点信息,一个二维数组(或称为邻接矩阵)存储图中的边或弧的信息。无向图的邻接矩阵是一个对称矩阵,无向图的邻接矩阵一般不是对称矩阵(强连通图情况下是对称矩阵)。

邻接表
邻接表是一种数组和链表结合的存储方式。仍以一个一维数组存储图中的顶点。包括顶点表和边表结点。
顶点表用于存储顶点的数据和一个指针域指向连接的第一个顶点;
边表结点用于存储邻接点在顶点表中的下标和该邻接点指向边表中下一个结点的指针。


十字链表
十字链多用在有向图中,十字链表整合了邻接表和逆邻接表,将邻接表的顶点表改为: 一个数据、一个入边表指针和一个出边表指针。将边表结点表改为: 弧起点下标、弧终点下标、入边表指针(指向终点相同的下一条边)和另一个边表指针(指向起点相同的下一条边)。
十字链表在有向图结构中应用广泛,容易查找到顶点v为弧尾和为弧首的顶点,容易求出顶点的出度和入度。
邻接多重表
邻接多重表多用在无向图中,解决了邻接表在插入和删除边等操作上操作复杂的问题。邻接多重表在邻接表的基础上增加了一个当前结点的前向结点的指针域。
边集数组
边集数组由两个一维数组构成,一个是存储顶点的信息,一个是存储边的信息,其中边数组每个数据元素由一条边的起点下标、终点下标和权值组成。边集数组更加关注边的集合,适合对边处理的场合,不适合对顶点的相关操作。

图的遍历
深度优先遍历
深度优先遍历遵循一定规则(如每次都走右手边结点),从某一顶点出发,直到最后走完所有依据该规则可以走的终点,之后原路返回,返回路途中依次检查当前结点上是否还有未走过的结点,如有就走过去再回来,知道返回起点。
深度优先遍历是一个递归过程,根一棵树的前序遍历类似。

广度优先遍历
广度优先遍历类似树的层序遍历,从上到下,按层次依次搜索遍历。

最小生成树
把构造连通网的最小代价生成树称为最小生成树。最小生成树是唯一的。
普里姆(Prim)算法查找最小生成树
从图的一个起点a开始,把a加入集合U,然后寻找与a有关联的边中,权重最小的那条边并把这条边的终点b添加到集合U中;
在新组成的集合U中的所有元素中查找权重最小的那条边并把终点加入结合U;
以此类推,直到所有顶点都加入到了结合U中。
最小生成树的时间复杂度为:O(n^2)
克鲁斯卡尔(Kruskal)算法查找最小生成树
算法思路:
(1)将图中的所有边都去掉。
(2)将边按权值从小到大的顺序添加到图中,保证添加的过程中不会形成环
(3)重复上一步直到连接所有顶点,此时就生成了最小生成树。这是一种贪心策略。
注意在添加过程中不要形成环!

 

最优二叉树和最小生成树

最优二叉树(哈夫曼树)是用来进行数据传输、编码压缩等,最小生成树用来设计水管、电路等连接各个结点所需的最短距离等用途。

 

最短路径
最短路径是指图上的两个顶点之间经过的边上的权值之后最小的路径。
迪杰斯特拉算法(Dijkstra算法)
迪科斯彻算法常用于路由算法或者作为其他图算法的一个子模块。
Dijkstra算法采用的是一种贪心的策略,先求出离源点最近距离的结点,然后考察与该结点连通的所有结点距离源点的距离是否比直接连接要短,每次计算都是在上一次计算的基础上进行的。直到求出所有距离。
迪科斯彻算法并非是一下就求出两点间的最短路径,而是一步一步求出他们之间顶点的最短路径,求解过程都是基于已经求出的最短路径的基础上。
弗洛伊德(Floyd)算法
从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

 

查找

查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合。
关键字(Key)是数据元素中某个数据项的值,又称键值。若一个关键字可以惟一的标识一个记录,则称此关键字为主关键字。
查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(记录)。
顺序查找:又叫线性查找,是最基本最简单的查找方式,从表中的第一个记录开始,逐个匹配查找,直到最后一个。
有序表查找
1.折半查找: 对于数据排列是有序的(按大到小或者按小到大)查找,可以采用折半查找的方法优化查找算法。时间复杂度是)(log(n)).
2. 插值查找:不是采用折半方法,而是根据要查找的关键字key与查找表中最大最小记录的关键字比较后得出一个查找值,这种方法叫插值查找,时间复杂度也是O(log(n))。但是比折半查找要优。
3. 斐波那契查找:斐波那契查找利用了黄金分割原理。

线性索引查找
索引是为了加快查找速度而设计的一种数据结构。索引就是把一个关键字与它对应的记录相关联的过程,一个索引由若干个索引项构成,每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。索引技术是组织大型数据库以及磁盘文件的一项重要技术。
稠密索引: 指在线性索引中,将数据集中每个记录都对应一个索引项。并且索引项一定是按照关键码有序的排列。所以属于有序索引。
分块索引:稠密索引的索引项与数据集的记录个数相同,空间代价很大,为了减少索引项,引入了分块索引。块间有序,块内无序。分块索引的索引项结构分3个数据项: 最大关键码、块中记录的个数、块首元素指针。
倒排索引:倒排索引中,记录号表存储具有相同次关键字的所有记录的记录号,这样的索引就是倒排索引。倒排索引不是由记录来确定属性值,而是由属性值来确定记录的位置,所以称为倒排索引,主要用于网站等根据关键字检索。倒排索引的查找记录非常快。
二叉排序树: 又称为二叉查找树。若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它根结点的值。它的左、右子树也分别是二叉排序树。
构造二叉排序树,不是为了排序,而是为了提高查找、插入和删除关键字的速度。
平衡二叉树: 是一种二叉排序树,其中每个结点的左子树和右子树的高度差最多等于1。

多路查找树(B树)
多路查找树其每一个结点的孩子数可以多于两个,且每一个结点处可以存储多个元素。
2-3树:树中每一个结点都具有2个或3个孩子(结点)。其中一个2结点包含一个元素和两个孩子,一个3结点包含两个元素和3个孩子。


2-3-4树:这种树添加来4结点,4结点包含3个元素和4个孩子。
B树:B树是一种平衡的多路查找树,2-3树和2-3-4树都是B树的特例。结点最大的孩子数目称为B树的阶,2-3是3阶的B树,2-3-4是4阶的B树。
B树的数据结构是为了内外存的数据交互而设计的。
B+树是应文件系统所需而设计的一种B树的变形。在B+树中,出现在分支结点中的元素会被当作它们在该分支结点位置的中序后继者(叶子结点)中再次列出,并且每一个叶子结点都会保存一个指向后一叶子结点的指针。

散列表查找(哈系表,Hash table)
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据查找的key,可以直接通过函数f对应出key所在的位置,不再需要一一比对。这里f称为散列函数,又称为哈希(Hash)函数。采用散列技术将记录存储在一块连续的存储空间中,这块空间就称为散列表或哈希表。

 

排序

冒泡排序:冒泡排序是一种交换排序,基本思路: 两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。冒泡排序的时间复杂度是O(n^2)。
简单选择排序:通过n-i次关键字间的比较,从 n-i+1 个记录中选出关键字最小的记录,并和第i个记录交换。简单选择排序时间复杂度是O(n^2)。
直接插入排序:直接插入排序的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。如玩扑克牌时候的排序。直接插入排序的时间复杂度是O(n^2)。
希尔排序:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。希尔排序不是一种稳定的算法(即假使数组中前后各有两个6,如果排序能保证前边的6一直在前边,则是稳定排序,如果排序算法有可能把前边的6排到后边,则是不稳定排序算法),时间复杂度是O(n^(3/2))。
堆排序:堆是具有以下性质的完全二叉树: 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。 堆排序(Heap Sort)就是利用堆(如大顶堆)进行排序的方法,基本思想是: 将待排序的序列构成一个大顶堆(此时,整个序列的最大值就是堆顶的根结点),将根结点移走,然后将剩余的n-1个序列重新构成一个堆,再取出根结点,以此类推。可见堆排序是利用了堆这种特殊的完全二叉树结构,每次取出序列的最大值(或最小值)完成排序。堆排序的时间负责度是O(nlogn)。
归并排序: 利用归并的思想实现。假设初始序列含有n个记录,两两归并排序,然后得到n/2的子序列,再两两归并,直到得到序列n的完全排序。归并排序比较占内存,但效率高且是稳定算法。归并排序的时间复杂度是O(n+logn)。 非递归方法实现的归并排序时间复杂度是O(n),所以尽量考虑使用非递归方法。
快速排序: 希尔排序相当于是直接插入排序的升级,堆排序相当于简单选择排序的升级,快速排序相当于冒泡排序的升级。快速排序的基本思路: 通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。快速排序的时间复杂度是O(nlogn),是一种不稳定的排序。尽量采用非递归的快速排序。


数据结构和内存中的堆和栈

数据结构中的堆和栈
堆:  堆是数据结构中一种完全二叉树结构,堆中某个节点的值总是不大于或不小于其父节点的值。堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。常用于堆排序等,特点是排序和查找速度快。

栈:栈是数据结构中一种后进先出,只可以在栈顶进行操作的线性结构。

队列: 先进先出的存储方式,只可以在一头插入,一头删除。

内存中的堆和栈
堆:一般由程序员分配与释放。 若不主动释放,程序结束时可能由OS回收。

栈: 由编译器自己主动分配释放 。存放函数的參数值,局部变量的值等。

参考资料: 程杰 《大话数据结构》

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值