线性表 :
线性表 是具有相同数据类型的 n (n >= 0) 个数据元素的有限序列,其中 n 为表长,当 n = 0 时线性表是一个空表;若用 L 命名线性表,则其一般表示为:L = (a1 , a2 , ... ai , ai+1 , ... an)
上述中,ai 是线性表中的 " 第 i 个 " 元素线性表中的位序;a1 是表头元素;an是表尾元素;
除了第一个元素外,每个元素有且仅有一个直接前驱;出最后一个元素外,每个元素有且仅有一个直接后继;
线性表有以下 3 大特点:
1.逻辑结构
2.存储(物理)结构
顺序表:
链 表:
双向链表:
循环链表
静态链表:
3.插入删除操作
顺序表:数组 就是顺序表,如下图所示 ->
单链表:头指针 -> 头结点(每个节点有一个数据位,和一个指针位)-> 下一个节点 ... ->尾结点 -> null 如下如所示->
循环链表:头指针 -> 头结点(每个节点有一个数据位,和一个指针位)-> 下一个节点 ... ->尾结点 -> 头指针 如下如所示->
双向链表:每个节点有一个数据位,和一个前驱指针位,和一个后继指针位;每个节点都可以通过前驱指针和后继指针找到与自己相邻的两个元素 如下如所示->
性能类别 | 具体项目 | 顺序存储 | 链式存储 |
---|---|---|---|
空间性能 | 存储密度 | = 1 ,更优 | < 1 |
容量分配 | 事先确定 | 动态改变,更优 | |
时间性能 | 查找运算 | O(n / 2) | O(n / 2) |
读运算 | O(1),更优 | O( [ n + 1 ] /2 ),最好情况为 1 ,最坏情况为 n | |
插入运算 | O(n / 2),最好情况为0,最坏情况为 n | O (1),更优 | |
删除运算 | O([n - 1] / 2) | O (1),更优 |
线性表 - 插入和删除操作:
顺序存储:插入元素前要移动元素,以挪出空的存储单元,然后再插入元素;删除元素时同样需要移动元素,以填充被删除的元素的存储单元;
链式存储:链式存储的插入和删除操作相较于顺序存储,优势在于不需要移动元素,只需要改变指针的指向即可完成插入和删除操作;
栈和队列
栈定义:
栈(Stack)是 只允许在一端进行插入或删除操作 的 线性表;
队列定义:
队列是一种先进先出 (FIFO)的线性表,他只允许在表的一端插入元素,而在表的另一端删除元素;在队列中,允许插入元素的一端成为队尾(Rear),允许删除元素的一端称为队头(Front);
循环链表:
例题:输出受限的双端队列是指元素可以从队列的两端输入,但只能从队列的一端输出,如下图所示,若有 e1 ,e2 ,e3 ,e4 依次进入输出受限的双端队列,则得不到的输出队列为 ( D ) 注释:下图的意思是,左右两边都能进,但是只能从左边出;
A. e4 、 e3 、 e2 、 e1
B. e4 、 e2 、 e1 、 e3
C. e4 、 e3 、 e1 、 e2
D. e4 、 e2 、 e3 、e1
串、数组、矩阵和广义表
串:
串(字符串)是仅由字符构成的有限序列,是取指范围受限的线性表;一般记为 S = ‘ a1 a2 ~~~ an ’,其中 S 是串名, a1 a2 a3 是串值;
1.空串:长度为零的串,空串不包含任何字符;
2.空格串:由一个或多个空格组成的串;
3.子串:由串中任意长度的连续字符构成的序列;含有子串的串成为主串;子串在主串中的位置是指子串首次出现时,该子串的第一个字符在主串中的位置;空串是任意串的子串;
4.串相等:指两个串长度相等且对应位置上的字符也相同;
5.串比较:两个串比较大小时以字符的 ASCII 码值作为依据;比较操作从两个串的第一个字符开始进行,字符的 ASCII 码值大者所在的串为大;若其中一个串先结束,则以串长较大者为大;
1.对串进行的基本操作有以下几种:
(1)赋值操作StrAssign ( s , t ) :将串 t 的值赋给串 s;
(2)连接操作Concat ( s , t ) :将串t接续在串s的尾部,形成一个新串;
(3)求串长StrLength ( s ) :返回串 s 的长度;
(4)串比较StrCompare ( s , t ) : 比较两个串的大小;
(5)求子串SubString ( s , tart , len):返回串s中从start开始的、长度为 len 的字符序列;
2、串的存储结构
(1) 串的顺序存储:定长存储结构;
(2) 串的链式存储:块链;
子串的定位操作通常称为串的 模式匹配,它是各种串处理系统中最重要的运算之一。子串也称为模式串;
数据类型 | 存储地址计算 |
一维数组 a [ n ] | a [ i ] 的存储地址为:a + i * len (注释:a 表示起始位置地址) |
二维数组 a [ m ] [ n ] | a [ i ] [ j ] 的存储地址(按行存储)为:a + ( i * n + j ) * len a [ i ] [ j ] 的存储地址(按列存储)为:a + (i * m + j ) * len (注释:a 表示起始位置地址) |
例题:已知 5行5列 的二维数组 a 中的个元素占两个字节,求元素 a [ 2 ] [ 3 ] 按行优先存储的存储地址是多少?
解题:
已知:m = 5,n = 5,i= 2,j = 3,len = 2,并且按行优先
直接套上述表格中的公式求得:a + ( 2 * 5 + 3 ) * 2 = a+26
最终答案为:a + 26 (注释:a表示起始位置地址)
稀疏矩阵:
设有如下所示的下三角矩阵 A [0...8, 0...8 ],将该三角矩阵的非零元素(即行下标不小于列下标的所有元素)按行优先压缩存储在数组M [ 1 ... m ] 中,则元素 A [ i , j ] ( 0 <= i <= 8 )存储在数组 M 的( A )中;
解题:将三角矩阵中的点一个个带入选项中,由于是按照行优先存储(指的是一行一行存储,按照从上到下,从左到右依次存储),所以将(0,0)带入选项应该得到 M[ 1 ](题目中说明从 1 开始 -> M [ 1... m ],)也就是 1;如果带入一个点后仍未能确定答案,则继续带入检验即可;
广义表:
广义表是n个表元素组成的有限序列,是线性表的推广;通常用递归的形式进行定义,记做:LS=(ao,a1……, an);
注:其中 LS 是表名,ai 是表元素,它可以是表(称做子表),也可以是数据元素(称为原子);其中 n 是广义表的长度 ( 也就是最外层包含的元素个数 ) ,n=0 的广义表为空表;而递归定义的重数就是广义表的深度,直观地说,就是定义中所含括号的重数 ( 注意:原子的深度为0,空表的深度为 1 ) ;
基本运算:取表头head(Ls)和取表尾tail(Ls)。
广义表:LS1 = ( a,( b,c ) ,( d ,e ) )
取表头:head ( Ls1 ) = a
取表尾:tail ( Ls1 ) = ( ( b , c ) , ( d , e ) ) 【注释:取表尾操作 -> 除去第一个元素,剩下的所有元素组合成的广义表称为取表尾操作】
例1:有广义表 -> Ls1 = ( a , ( b ,c ) ,( d,e ) ) 则其长度为多少,深度为多少?
长度为 3 (因为有三个元素) 深度为 2(因为有两重括号)
例2,有广义表 -> Ls1 = ( a , ( b ,c ) ,( d,e ) ) 要将其中的 b 字母取出,应该如何操作?第一步:取表尾 -> tail ( Ls1 ) 可以得到 ( ( b ,c ) ,( d,e ) )
第二步:取表头 -> head (( ( b ,c ) ,( d,e ) ) ) 可以得到 ( b ,c )
第三步:取表头 -> head ( ( b ,c ) ) 可以得到 b
所以综上所述,完整的操作为 :head ( head ( tail ( Ls1 ) ) )