软考算法(一)
线性表
定义
线性表是具有相同数据类型 的n(n>=0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,则一般表示为: L = ( a 1 , a 2 , a 3 , . . . , a i , a i + 1 , . . . , a n ) L = (a_1,a_2,a_3,...,a_i,a_i+_1,...,a_n) L=(a1,a2,a3,...,ai,ai+1,...,an)
- a~i~是线性表中"第i个"元素线性表中的位序
- a~1~是表头元素;a~n~是表尾元素
- 除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅有一个直接后继。
顺序表
单链表
循环链表
双向链表
性能分析
性能类别 | 具体项目 | 顺序存储 | 链式存储 |
---|---|---|---|
空间性能 | 存储密度 | =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),更优 |
线性表插入删除操作
- 顺序存储
插入元素前一要移动元素以挪出空的存储单元,然后再插入元素。删除元素同样需要移动元素,以填充被删除元素的存储单元 - 链式存储
①单链表删除节点:
当删除a2节点时,首先我们要引入一个q指针,q指针指向我们的a2节点(为了不丢掉a2节点中存储的数据),再用前一个节点a1指针域中的指针指向a2节点的下一个节点a3,这样就达到了一组删除操作。
②单链表插入节点
在a1和a2之间进行插入操作,引入一个s节点,指向要插入的x节点,接下来要先将x节点指针域中的指针指向a2节点,然后再将a1指针域中的指针指向下一个节点x,如果先将a1指针指向要插入的x节点,那么原本a1后面的a2节点等的数据就会损失。所以一定是先执行将x节点指针域中的指针指向a2节点。
③双向链表删除节点
引入p指针指向即将要进行删除的a2节点,然后用a1节点的后指针指向a2的下一个节点a3完,然后再用a3节点的前指针指向a1,完成连接
④双向链表插入节点
插入一个节点x,还是要引入一个指针q指向即将要插入的节点x,要先进行后面的连接,让x的next指针指向下一个节点a2,再把a2节点的前指针指回x节点,先连后面再连前面,和单链表的插入操作相同
栈和队列
线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,则一般表示为:
L = ( a 1 , a 2 , . . . , a i , a i + 1 , . . . , a n ) L=(a1,a2,...,ai,ai+1,...,an) L=(a1,a2,...,ai,ai+1,...,an)
栈
栈 (Stack )是只允许在一端进行插入或删除操作的线性表。
队列
队列 是一种先进先出(FIFO)的线性表,它只允许在表的一端插入元素,而在表的另一端删除元素。在队列中,允许插入元素的一端称为队尾(Rear),允许删除元素的一端称为队头(Front)。
循环队列
循环队列 是指将它的存储空间进行连接,让队列变成了一个环。循环队列有两个指针,头指针head和尾指针tail,往右插入数据时,tail不断的往后调,在删除数据时,head不断往后调。
循环队列队空条件:head=tail
循环队列队满条件:(tail+1)%size=head
串、数组、矩阵和广义表
串
串是仅由字符构成的有限序列,是取值范围受限的线性表。一般记为S = 'a1 a2 ~~~ an',其中S是串名,a1 a2 an是串值。
- 空串:长度为0的串,空串不包含任何字符。
- 空格串:由一个或多个空格组成的串。
- 子串 :由串中任意长度的连续字符构成的序列。含有子串的串称为主串。子串在主串中的位置指子串首次出现时,该子串的第一个字符在主串中的位置。空串是任意串的子串。
- 串相等:指两个串长度相等且对应位置上的字符也相同。
- 串比较:两个穿比较大小时以字符的ASCII码值作为依据。比较操作从两个串的第一个字符开始进行,字符的ASCII码值大者所在的串为大;若其中一个串先结束,则以串长较大者为大。
串的基本操作
- 赋值操作StrAssign(&T,chars):生成一个其值等于chars的串T。这通常涉及为串分配内存,并将chars的内容复制到新串中。
- 连接操作Concat(s,t):将串t接续在串s的尾部,形成一个新串。
- 求串长StrLength(s):返回串s的长度。
- 串比较StrCompare(s,t):比较两个串的大小。
- 求子串SubString(,start,len):返回串s中从start开始的、长度为len的字符序列。
串的存储结构
(1)串的顺序存储:定长存储结构
(2)串的链式存储:块链
子串的定位操作通常称为串的模式匹配,它是各种串处理系统中最重要的运算之一。子串也称为模式串。
数组
数组是一个固定长度的存储相同数据类型的数据结构,数组中的元素被存储在一段连续的内存空间中。
数组的存储地址计算
- 一维数组a[n]
a [ i ] 的存储地址为: a + i ∗ l e n a[i]的存储地址为:a+i*len a[i]的存储地址为:a+i∗len - 二维数组a[m][n]
a [ i ] [ j ] 的存储地址(按行存储)为: a + ( i ∗ n + j ) ∗ l e n a[i][j]的存储地址(按行存储)为:a+(i*n+j)*len a[i][j]的存储地址(按行存储)为:a+(i∗n+j)∗len
a [ i ] [ j ] 的存储地址(按列存储)为: a + ( j ∗ m + i ) ∗ l e n a[i][j]的存储地址(按列存储)为:a+(j*m+i)*len a[i][j]的存储地址(按列存储)为:a+(j∗m+i)∗len
例:已知5行5列的二维数组a中的各元素占两个字节,求元素a[2][3]按行优先存储的存储地址
由题意可知:m = 5,n = 5, len = 2,按行优先存储,那么a[2][3]的存储地址为:a+(2 5+3)2=a+26
矩阵------稀疏矩阵
稀疏矩阵是矩阵中的一种特殊类型。在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵。与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。通常认为,当矩阵中非零元素的总数比上矩阵所有元素总数的值小于等于0.05时,该矩阵即可被视为稀疏矩阵,该比值也称为这个矩阵的稠密度。
上三角矩阵
在矩阵中下标分别为i和j的元素,对应的一维数组的下标计算公式为:(2n-i+1)*i/2+j
下三角矩阵
在矩阵中下标分别为i和j的元素,对应的一维数组的下标计算公式为:(i+1)*i/2+j
广义表
广义表是n个表元素组成的有限序列,是线性表的推广。
通常用递归的形式进行定义,记做:LS=( a 0 a_{0} a0, a 1 a_{1} a1,..., a n a_{n} an)。
注:其中LS是表名, a i a_{i} ai是表元素,它可以是表(称做子表),也可以是数据元素(称为原子)。其中n是广义表的长度(也就是最外层包含的元素个数),n = 0的广义表为空表;而递归定义的重数就是广义表的深度,直观的说,就是定义中所含括号的重数(原子的深度为0,空表的深度为1)
基本运算:取表头head(Ls)和取表尾tail(Ls)。
若有 L S 1 = ( a , ( b , c ) , ( d , e ) ) ,则 h e a d ( L S 1 ) = a t a i l ( L S 1 ) = ( ( b , c ) , ( d , e ) ) 若有LS1=(a,(b,c),(d,e)),则\\head(LS1)=a\\tail(LS1)=((b,c),(d,e)) 若有LS1=(a,(b,c),(d,e)),则head(LS1)=atail(LS1)=((b,c),(d,e))
ps:如果要将LS1中的b元素取出,则该怎么操作
基本操作有取表头和取表尾,而表中的元素也可以看做是广义表,那么我们先取一次表尾,得到子表((b,c),(d,e)),再取一次表头,得到它的子表(b,c),然后再取一次表头得到我们想要的元素b,即:head(head(tail(LS1))) 这样一个三层操作。
ps:如果记不住公式,可用代入法