数据结构---数组
数组
数组可以看成是线性表的推广,其特点是结构中的元素本身可以是具有某种结构的数据,但属于同一数据类型,数组一旦被定义, 它的维数和维界就不再改变。
抽象数据类型数组定义
数组的顺序存储
用一组连续的存储单元存储数组的数据元素
以行序为主序的二维数组
假设每个数据元素占 L 个存储单元, 则二维数组 A[O.. m-1, 0 .. n-1] (即下标从 0 开始, 共有m行n列)中任一元素 aij的存储位置
n维数组
基本操作的实现
1.初始化
void InitArray(Array& p, int m, int n)//初始化二维数组
{
if (m < 1 || n < 1)
{
cout << "输入有误!请输入正确的数组大小" << endl;
return;
}
p.elem = new int[m * n];//动态开辟了m*n个长度的数组空间
p.m = m;//确定行数
p.n = n;//确定列数
}
2.销毁数组
void DestoryArray(Array& p)//销毁数组
{
delete[]p.elem;//释放之前开辟的空间
p.elem = NULL;
p.m = 0;//0行
p.n = 0;//0列
cout << "数组已经销毁!" << endl;
}
3.存取数组元素
int ValueArray(Array& p, int a, int b)//存取元素
{
if (a<0 || a>p.m || b<0 || b>p.n)
{
cout << "存取时参数不合法,请重新输入!" << endl;
return 0;
}
return p.elem[a * p.n + b];//二维数组在存储时仍是一片连续的空间,所以计算出所要存储的值所占空间的位置即可
}
4.修改数组元素
int AssignArray(Array& p, int a, int b, int x)//修改数组元素
{
if (a<0 || a>p.m || b<0 || b>p.n)
{
cout << "修改时参数不合法,请重新输入!" << endl;
return 0;
}
else
{
int y = p.elem[a * p.n + b];
p.elem[a * p.n + b] = x;//把要修改为的值放入要修改的位置
return y;
}
}
特殊矩阵的压缩存储
对称矩阵
特点:aij=aji(1=<i;j<=n)
方法:为每一对对称元分配一个存储空间,只存储下或上三角(包括主对角线)的数据元素,存储空间(n^2--->n(n+1)/2)
任意元素的存储位置:基地址+该元素前面所有元素所占的空间(等差求和)
三角矩阵
特点:上三角矩阵是指矩阵下三角(不包括对角线)中的元均为常数c或零的n阶矩阵, 下三角矩阵与之相反。
方法:重复元素共享一共元素存储空间,共占用n(n+1)/2+1个存储空间
下三角矩阵
sa[k]和矩阵元aij之间的对应关系为
对角矩阵
特点:对角矩阵 所有的非零元都集中在以主对角线为中心的带状区域中,即除了主对角线上和直接在对角线上、下方若干条对角线上的元之外,所有其他的元皆为零。
方法:以对角顺序存储
稀疏矩阵
特点:非零元素非常少
方法:
1.三元组顺序表
2.十字链表
每一个非零元素用一个结点表示,除了(row,col,value)还有两个域
- right:用于链接同一行中下一个非零元素
- down:用于链接同一列中下一个非零元素
广义表
广义表是线性表的推广,也称为列表,记作LS = (a1, a2, · · ·, an )
ai可以是单个元素(原子)也可以是广义表(子表),显然是递归定义
表头:若表非空,则其第一个元素a1就是表头(可以是原子,也可以是子表)
表尾:除表头外其他元素组成的表(不是最后一个元素,而是一个子表,所以要用()把除表头外的其他元素括起来)
推论:
- 广义表的元素可以是子表,而子表的元素还可以是子表……
- 广义表可为 其他广义表所共享(不必列出子表的值,直接用子表的名称来表示)。
- 广义表可以是一个递归的表,即广义表也可以是 其本身的一个子表。
存储结构
1.头尾链表的存储结构
表结点(标志域,指示表头的指针域,指示表尾的指针域)可以表示广义表,原子结点(标识域和值域)可以表示原子
2.拓展线性链表的存储结构
无论是原子结点还是表结点均由标志域,指示表头的指针域,指示表尾的指针域表示