数据结构 第四章 串、数组和广义表 学习笔记

本文介绍了串、数组和广义表三种数据结构的基础知识和优化存储方法。串的定义、存储和匹配算法(BF、KMP、哈希)被详细阐述,特别是字符串匹配的效率提升。数组的特殊矩阵压缩存储如对称、三角和对角矩阵的优化技巧也进行了讲解。最后,广义表的概念、操作及两种存储结构(头尾链表和扩展线性链表)被讨论,强调了其在存储复杂数据结构时的重要性。
摘要由CSDN通过智能技术生成

目录

一、串

4.1 串的定义

4.2 串的存储

4.3 串的匹配

4.3.1 BF算法(暴力)

4.3.2 KMP算法

4.3.3 字符串哈希

4.4 注意

二、数组

4.1 数组的类型定义

4.2 数组的存储

4.3 特殊矩阵的压缩存储

4.3.1 对称矩阵

4.3.2 三角矩阵

4.3.3 对角矩阵

三、广义表

4.1 广义表的定义

4.2 广义表的操作

4.3 广义表的存储

4.3.1 头尾链表的存储结构

4.3.2 扩展线性链表的存储结构 

一、串

4.1 串的定义

(string)(或字符串)是由零个或多个字符组成的有限序列,一般记为

s=a_{1}a_{2}a_{3}...a_{n}(n\geqslant 0)

其中s为串的名字,其中元素可以是字母、数字或其他字符;传中字符的数目n称为串的长度,零个字符的串称为空串,其长度为0。

在C语言中,我们常常用char s[ ]的形式来表示一个串,而在C++中当调用了头文件#include<string>时就可以使用已经封装好的string来表示字符串。

4.2 串的存储

串的存储有两种方式,顺序存储链式存储,由于串作为一种一对一的逻辑结构(也就是线性结构),它的声明和存储模式就是一种线性表,而线性表的存储和操作已经在第二章讲的差不多了,就不再在这里赘述了。

4.3 串的匹配

说到串,最经典的一类题就是字符串匹配问题了,在这里放一道例题和三种解法:

4.3.1 BF算法(暴力)

这种算法最为直观,简单来说就是运用双指针对每一位进行比较,这时,时间复杂度为O(n*m)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 100;
const int mod = 1e9 + 7;
void solve()
{
	string x,y;
	cin>>x>>y;
	int len=y.length();
	x=x+x;
	for(int i=0;i<len;i++)
	{
		for(int j=0;x[j];j++)
		{
			if(x[j]==y[i])
			{
				bool f=0;
				for(int k=i,p=j;k<i+len;k++,p++)
				{
					if(p>=x.length())
					{
						f=1;
						break;
					}
					if(x[p]!=y[k])
					{
						f=1;
						break;
					}
				}
				if(!f)
				{
					cout<<"Yes\n";
					return;
				}
			}
		}
	}
	cout<<"No\n";
}
signed main()
{	
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
}

4.3.2 KMP算法

简单来说就是在BF算法的基础上加了一点记忆化搜索,减少了重复查找一段已经确认相同的子串,使得复杂度降为O(n+m)

4.3.3 字符串哈希

就是将每一段字符串看作一个高进制的数字(哈希值),然后通过匹配哈希值的方式来查找相同子串,复杂度为O(n-m),但是有时出题人可能卡哈希(即两个不同的字符串,在经过取模后哈希值相同),因此经常需要用到双哈希(据wls说双哈希也有人卡,他曾用过三哈希)。

4.4 注意

区分一下子串和子序列的概念:子串指的是串中连续的某一段;子序列则指的是需要按照串的序列但是不一定要连续的串。

另外,在串中的比较我们通常说的是字典序比较。在字典中,我们查询一个单词或者一个字往往都要以它的单词(或拼音)在26个字母中的排序来查找,这也就是字典序的由来,当串中不仅仅包括字母时,它的比较往往遵循ACII表每个字符的对应值来进行比较。

在串中,空串指的是长度为0的串,而不是有空格的串,在串中,空格也被看作一个符号。

二、数组

4.1 数组的类型定义

数组是由类型相同的数据元素构成的有序集合,每个元素称为数组元素,每个元素受n个线性关系的约束(这里的n指的是数组的维度不是数组长度)。

4.2 数组的存储

之前在第一章也说了,由于数组本身自带了这种一对一的逻辑关系(线性结构),且数组一般不发生插入和删除操作,所以都采用顺序存储的方式,这样可以更加直观的表达元素之间的关系。

而正是因为这一种顺序存储的方式,我们可以在O(1)的时间内完成对数组内任意位置元素的访问(又称随机存取结构),具体完成方式即是第一章所说的计算地址的方式。

4.3 特殊矩阵的压缩存储

由于矩阵在日常生活中较为常用,而很多特殊矩阵有很多相同元或是仅仅需要存储部分位置的元素,为了节省空间,于是便有了压缩存储

4.3.1 对称矩阵

由于对称矩阵元素关于对角线对称(即满足a_{ij}=a_{ji}),那么我们可以用一个一维数组来存储,数组每个位置存储元素位置关系如下:

k=\left\{\begin{matrix} \frac{i*(i-1)}{2}+j-1(i\geqslant j)\\ \frac{j*(j-1)}{2}+i-1(i\geqslant j) \end{matrix}\right.

4.3.2 三角矩阵

几乎与对称矩阵存储方式一样,以主对角线划分,存在上三角矩阵和下三角矩阵,除了对角线的另一半元素只要相同,那么我们就可以将相同那一半元素只用一个存储单位存储,另一半按照对称矩阵的公式存储。

1)上三角

k=\left\{\begin{matrix} \frac{(i-1)*(2n-i+2)}{2}+j-i(i\leqslant j)\\\frac{n*(n+1)}{2} (i>j) \end{matrix}\right.

2)下三角

k=\left\{\begin{matrix} \frac{i*(i-1)}{2}+j-1(i\geqslant j)\\\frac{n*(n+1)}{2} (i<j) \end{matrix}\right.

4.3.3 对角矩阵

对角矩阵所有非零元都能几种在以主对角线为中心的带状区域

总而言之,能用压缩存储的矩阵往往为稀疏矩阵,以上为三种比较典型的例子。

三、广义表

4.1 广义表的定义

广义表是线性表是线性表的推广,也称为列表,广义表一般记作

LS=(a_{1},a_{2}...,a_{n})

在广义表中,我们往往认为表中的每个既可以是广义表也可以是一个元素,而我们常常用大写字母代表广义表,小写字母代表单个元素。

4.2 广义表的操作

由于广义表的结构复杂且多变,所以广义表主要只有两个操作:取表头和表尾。

表头可以是单个元素也可以是一个广义表,但是表尾是去除表头之外其余元素组成的表,即表尾一定为一个广义表。

注意:广义表中()代表空表,长度为0,(())代表长度为1,有一个元素为空表,此时表头表尾都是空表()。

4.3 广义表的存储

由于广义表每个元素存储的元素并不统一,并不适用顺序存储,主要用两种链式存储。

4.3.1 头尾链表的存储结构

由前面的定义我们可以发现,只要确定了一个表的表头和表尾,那么一个表也就确定了,并且由于表中元素只有原子和广义表两种,因此需要两种结点:表结点和原子结点。

4.3.2 扩展线性链表的存储结构 

唯一区别在于所有结点都是由三个域组成:指示表头的指针域,指示表尾的指针域和值域。

广义表的深度是指广义表中展开后所含括号的层数,广义表的长度是指广义表中所 含元素的个数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值