【数据结构】期中总结(线性结构、栈与队列、字符串、树)

注:基于101《数据结构》教材

绪论

数据结构的三个要素:数据的逻辑结构、数据的存储结构及操作定义与实现。
数据的四种逻辑结构:集合、线性结构、树形结构、图形结构。
抽象数据类型:使用者无需知道数据元素的类型,只需知道数据元素间的逻辑关系,是与数据元素及在数据元素上的实现无关的数据类型。
数据的操作:包括操作的定义和实现。
操作定义是对现实问题的抽象,独立于计算机;
操作实现依赖于计算机和程序设计语言。

影响时间复杂度的因素:

  1. 硬件性能
  2. 编程语言及生成代码的质量
  3. 问题和数据规模
  4. 算法设计效率

空间复杂度:
空间消耗包括程序代码所占空间、数据所占空间及中间过程使用的辅助空间,空间复杂度指算法使用的辅助空间与数据规模的关系。

复杂度计算:
顺序组合取复杂度最大值,嵌套、多层取复杂度相乘

线性结构

线性表的定义:由同一类型的数据元素构成的有序序列的线性结构【注意是逻辑结构,物理上不存在】
线性表的逻辑结构:数据元素之间线性的序列关系
线性表的物理结构:线性表在计算机中的存储方式,主要有两种:顺序存储结构和链式存储结构

顺序表

又称顺序表,逻辑顺序与物理顺序相同,都是位置相邻;
可以静态分配(空间事先固定,溢出会导致程序崩溃),也可以动态分配(用malloc函数,空间占满后另外开辟一块更大的存储空间并替换原来的)
特点:随机访问(随机存取),查找O(1);存储密度高;逻辑上相邻元素物理上也相邻,插入删除需移动大量元素
基本操作(增删改查)注意判断合法性,顺序表可能出现表满溢出的情况

链表

节点之间相邻的概率极小。
缺点:浪费存储空间;
存储结构:非随机存取。
创建链表推荐使用头结点,优点是统一了插入和删除操作。
进行插入、删除时,都需要先找到操作对象的前一个元素,判断合法性后申请或释放对应空间,复杂度都为 O ( n ) O(n) O(n).
静态链表:用数组存放线性表中的元素,给每个数组元素增加一个域,用于指示下一个元素的位置。(数组和链表的结合体)
块状链表:用双向链表维护总长度不超过 n n n的线性表各元素,分为若干个包含 n \sqrt{n} n 个元素的块。(时间复杂度: O ( n ) O(\sqrt{n}) O(n ))
广义表:递归定义的线性结构,其中的元素不仅可以是单元素也可以是另一个广义表。
长度:最外层包含的元素个数;
深度:包含括号的重数。
空表长度为0,深度定为1;原子深度为0。
任何一个非空广义表都可以分为表头(原子)和表尾(广义表,最外层一定有括号
广义表的深度是无穷值,长度是有限值。

多维数组

行优先存放, n n n维数组各维大小为 ( s 1 , s 2 , . . . s n ) (s_1,s_2,...s_n) (s1,s2,...sn),第一个元素的地址是 l ( 0 , 0 , … , 0 ) l_{(0,0,…,0)} l(0,0,,0),元素占用空间为 s i z e size size个字节,则下标为 ( i 1 , i 2 , … , i n ) (i_1,i_2,…,i_n) i1,i2,in的元素位置是
l ( 0 , 0 , … , 0 ) + ( i 1 ∗ s 2 ∗ s 3 ∗ . . . ∗ s n + i 2 ∗ s 3 ∗ . . . ∗ s n + . . . + i n ) ∗ s i z e l_{(0,0,…,0)}+(i_1*s_2*s_3*...*s_n+i_2*s_3*...*s_n+...+i_n)*size l(0,0,,0)+(i1s2s3...sn+i2s3...sn+...+in)size
例题1:
假设有二维数组 A6×8,每个元素用相邻的 6 个字节存储,存储器按字节编址。已知 A 的起始存储位置(基地址)为 1000,分别计算 a [ 3 ] [ 6 ] a_{[3][6]} a[3][6]按行存储和列存储的地址。
答案:1) 1000+6*(3*8+6) 2) 1000+6*(6*6+3) 注意行优先和列优先对应的不同排列方式
数组的下标表示该元素在该维度前的数目,计算地址用基址+偏移量
例题2:
假设按低下标优先存储整数数组A9x3x5x8时第一个元素的字节地址是100,每个整数占四个字节。问下列元素的存储地址是什么?(1)a0000(2)a1111(3)a3125(4)a8247
答案:
LOC(a0000)=100
LOC(a1111)=100+ (3×5×8×1+ 5×8×1+ 8×1+ 1)×4=776
LOC(a3125)=100+ (3×5×8×3+ 5×8×1+ 8×2+ 5)×4=1784
LOC(a8247)=100+ (3×5×8×8+ 5×8×2+ 8×4+ 7)×4=4416
正确理解低下标优先存储:不是指每个维度的元素数目多少,而是下标从左往右的次序
套公式 l = l ( 0 , 0 , … , 0 ) + ( i 1 ∗ s 2 ∗ s 3 ∗ . . . ∗ s n + i 2 ∗ s 3 ∗ . . . ∗ s n + . . . + i n ) ∗ s i z e l=l_{(0,0,…,0)}+(i_1*s_2*s_3*...*s_n+i_2*s_3*...*s_n+...+i_n)*size l=l(0,0,,0)+(i1s2s3...sn+i2s3...sn+...+in)size即可。
压缩空间存储:上(下)三角矩阵
对于下三角矩阵:
设单个元素所占空间为 s i z e size size,则 a [ i ] [ j ] a_{[i][j]} a[i][j]的存储位置 l i j l_{ij} lij与矩阵首个元素 a [ 0 ] [ 0 ] a_{[0][0]} a[0][0]的地址 l 00 l_{00} l00的关系是:
l i j = l 00 + ( i ( i + 1 ) / 2 + j ) × s i z e , i ≥ j l_{ij} = l_{00} + (i(i+1)/2+j) × size,i≥j lij=l00+(i(i+1)/2+j)×sizeij
对角矩阵:所有非0元集中在以主对角线为中心的带状区域中。关键是见了数组元 S A [ k ] SA_{[k]} SA[k]与矩阵元 a i j a_{ij} aij的对应关系
三对角矩阵:
k = 2 ( i − 1 ) + j − 1 , ( ∣ i − j ∣ ≤ 1 ) k = 2 ( i - 1 ) + j - 1,(| i - j | ≤ 1) k=2(i1)+j1,(ij1)
稀疏矩阵:0元素数目远多于非0元素数目,存储非0项
顺序存储:三元组表 ( r o w , c o l , v a l u e ) (row,col,value) (row,col,value)
链式存储:十字链表 ( r o w , c o l , v a l u e ) (row,col,value) (row,col,value),通过行指针right和列指针down串联各行各列
矩阵转置算法,复杂度 O ( M . n u + M . t u ) O(M.nu+M.tu) O(M.nu+M.tu)

Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T)
{
	T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
	if (T.tu) {
		for (col=1; col<=M.nu; ++col) num[col] = 0;
		for (t=1; t<=M.tu; ++t) // M中每列非零元个数
		num[M.data[t].j]++;
		// 求第col列中第一个非零元在T.data中的序号
		cpot[1] = 1;
		for (col=2; col<=M.nu; ++col)
		cpot[col] = cpot[col-1] + num[col-1];
		for (p=1; p<=M.tu; ++p) 
		{ /* 转置矩阵元素 */
			col = M.data[p].j;
			q = cpot[col];
			T.data[q].i = M.data[p].j;
			T.data[q].j = M.data[p].i;
			T.data[q].e = M.data[p].e;
			cpot[col]++;
		}
	} 
	return OK;
}

十字链表
该部分考察计算题的可能性较大,同时要掌握基础概念

栈与队列

给定一个入栈序列,序列长度为N,出栈顺序总数为 C 2 N N N + 1 \frac{C_{2N}^{N}}{N+1} N+1C2NN.

顺序栈

溢出:分为上溢(栈满进栈)和下溢(栈空出栈
特点:应用广泛,存储开销低,根据栈顶的相对位移定位栈内元素(虽然栈只允许在栈顶操作)

链式栈

时间效率和顺序栈相似,
空间效率上顺序栈结构紧凑,但必须事先确定长度;链式栈长度可变,增加结构性开销

顺序队列

溢出:上溢(队满进队),下溢(队空出队),假溢出(队尾指针达到最大值但队前端有空闲位置,入队时溢出)
用两个指针Q.front和Q.rear维护队列,其中Q.rear有实指和虚指两种形式
普通队列->循环队列
实现顺序队列时要注意的点:

  1. 若存储ksize个,则需要开辟ksize+1个空间(浪费一个存储空间区分空和满)
  2. 入队时先判断队列是否满,改变且仅改变尾指针, queue.rear = (queue.rear + 1)%queue.capacity // 循环后继
  3. 出队时先判断队列是否空,改变且仅改变头指针,queue.front = (queue.front +1) % queue.capacity

环形队列

队列空:Q.rear == Q.front
队列满:(Q.rear+1) mod M == Q.front

链式队列

顺序队列存储空间固定,链式队列不固定,但都不允许访问队列内部元素

可以用两个底部相连的栈模拟双端队列(插入删除在线性表两端进行)
超队列:删除在一端进行,插入在两端进行
超栈:插入在一端进行,删除在两端进行

栈的应用

后缀表达式求值
依次读入后缀表达式,若为操作数则压入栈中,若为运算符则从栈中两次取出栈顶,运算后压入结果
最终若表达式正确,栈中仅由的一个值即为结果
中缀表达式转后缀表达式
依次读入中缀表达式,若为操作数则直接输出到序列,若为开括号则入栈,若为闭括号先判断栈是否为空(为空则异常),若非空则弹出栈顶元素直至遇到开括号;若为运算符,则在(栈非空 and 栈顶不是开括号 and 栈顶运算符的优先级不低于输入的运算符的优先级)条件下循环,弹出栈顶元素并放到后缀表达式序列中,循环结束后将输入的运算符压入栈内。

单调栈、单调队列

单调栈:栈中元素具有单调性的栈。
单调队列:队列中元素有单调性,入队时要检查单调性,不满足的元素被删除

字符串

存储结构有顺序和链式两种,字符串一般都有结束符,在c和cpp中是'\0',不计入字符串长度但占存储空间。
要熟悉基本的字符串函数
concat:前后拼接 replace:char *replace (char *source, char *target, char *dest);
substr:char* substr(char* str, int start, int len); index:char *index(const char *s, char c);
strsmp:int strcmp ( const char * str1, const char * str2 )[返回值>0:字符串1>字符串2]
strcpy:char * strcpy ( char * destination, const char * source );
例题1: 若串S1=‘ABCDEFG’, S2=‘9898’ ,S3=‘###’,S4=‘012345’,执行
concat(replace(S1,substr(S1,length(S2),length(S3)),S3),substr(S4,index(S2,‘8’),length(S2)))
其结果为 ABC###G1234
例题2: 摘自严蔚敏《数据结构》习题集
ans
注意replace函数会将所有在主串中出现的指定子串都替换!

KMP算法求next和nextval数组

BV16a411D7Us

树与二叉树

树
描述

满二叉树

由度为0和2的结点构成的二叉树,树中没有度为1的结点

完全二叉树

从第1层到第𝑑−2层全是度为2的中间结点;第𝑑层的结点都是叶结点,度为0;在第𝑑−1层,各结点的度从左向右单调非递增排列,同时度为1的结点要么没有,要么只有一个且该结点的左子树非空。

完美二叉树

d-1层所有结点度都为2.

二叉树的性质

  1. 设非空二叉树中度为𝒊∈[𝟎,𝟐]的结点数为 n i n_i ni ,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
  2. i i i层最多有 2 i − 1 2^{i-1} 2i1个结点
  3. 高度为d的二叉树最多有 2 d − 1 2^{d}-1 2d1个结点
  4. 一棵二叉树是完美二叉树的充要条件:有 2 d − 1 2^{d}-1 2d1个结点

性质
树中结点数等于所有结点度的和+1
整理范围:绪论->树的性质

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值