数组和矩阵以及广义表

1.数组

  • 数组是定长线性表在维度上的扩展,即线性表中的元素又是一个线性表。N维数组是一种"同构"的数据结构,其每个数据元素类型相同、结构一致。

  • 其可以表示为行向量形式或者列向量形式线性表,单个关系最多只有一个前驱和一个后继,本质还是线性的。

  • 数组结构的特点:数据元素数目固定;数据元素类型相同;数据元素的下标关系具有上下界的约束且下标有序

  • 数组数据元素固定,一般不做插入和删除运算,适合于采用顺序结构

数组存储地址的计算,特别是二维数组,要注意理解,假设每个数组元素占用存储长度为len,起始地址为a,存储地址计算如下(默认从0开始编号)

1. 一维数组

项目 说明 公式
定义 a[n],包含 n 个元素
元素 a[0], a[1], ..., a[n-1]
首地址 a(假设为基地址)
元素大小 len(每个元素占用的字节数)
地址计算 元素 a[i] 的地址 a + i × len

2. 二维数组

基本定义

  • 数组定义:a[m][n](m行,n列)
  • 元素总数:m × n
  • 索引范围:a[0][0]a[m-1][n-1]

地址计算表格

存储方式 元素地址公式 说明
按行存储 (C/C++/Java/Python等) a + (i × n + j) × len 先行后列,一行接一行
按列存储 (Fortran/Matlab等) a + (j × m + i) × len 先列后行,一列接一列

参数说明:

  • a: 数组首地址(a[0][0]的地址)
  • i: 行索引(0 ≤ i < m)
  • j: 列索引(0 ≤ j < n)
  • len: 每个元素占用的字节数

3. 示例对比

假设:a[3][4](3行4列),len = 4字节a = 1000

元素 按行存储地址计算 按列存储地址计算
a[1][2] 1000 + (1×4 + 2)×4 = 1000 + 6×4 = 1024 1000 + (2×3 + 1)×4 = 1000 + 7×4 = 1028
a[2][1] 1000 + (2×4 + 1)×4 = 1000 + 9×4 = 1036 1000 + (1×3 + 2)×4 = 1000 + 5×4 = 1020

4. 存储示意图

按行存储(行主序)

复制代码
内存布局:a[0][0], a[0][1], a[0][2], a[0][3],
          a[1][0], a[1][1], a[1][2], a[1][3],
          a[2][0], a[2][1], a[2][2], a[2][3]

按列存储(列主序)

复制代码
内存布局:a[0][0], a[1][0], a[2][0],
          a[0][1], a[1][1], a[2][1],
          a[0][2], a[1][2], a[2][2],
          a[0][3], a[1][3], a[2][3]

5. 重要注意事项

  1. 下标从0开始:以上公式假设数组下标从0开始
  2. 边界检查 :实际使用中需要确保 0 ≤ i < m, 0 ≤ j < n
  3. 语言差异
    • 行主序语言:C, C++, Java, Python (numpy), JavaScript
    • 列主序语言:Fortran, MATLAB, R, Julia
  4. 高维数组:三维及以上的数组可以类似推导

三维数组示例 a[x][y][z]

  • 按行存储:a + (i×y×z + j×z + k) × len
  • 按列存储:a + (k×x×y + j×x + i) × len

2.矩阵

  • 特殊矩阵:矩阵中的元素(或非0元素)的分布有一定的规律。常见的特殊矩阵有对称矩阵、三角矩阵和对角矩阵。

  • 稀疏矩阵:在一个矩阵中,若非零元素的个数远远少于零元素个数,且非零元素的分布没有规律。

  • 存储方式为三元组结构,即存储每个非零元素的(行,列,值)。

对于考试真题,将矩阵求按行(或按列)存储在一维数组,求矩阵i,j和一维数组下标k关系,可以代入特定值,比如i=0,j=0,k=x等,到题目给出关系式,验证是否正确。

3.广义表

您的描述非常准确和全面!您已经清晰地定义了广义表的核心概念和特性。让我在您的基础上做一些补充和归纳:

核心要点总结

1. 广义表 vs 线性表

  • 线性表:元素都是原子(不可再分)
  • 广义表:元素可以是原子或子表(可再分)
  • 线性表是广义表的特例(所有元素都是原子时)

2. 基本概念

  • 长度:最外层元素的个数
  • 深度:括号嵌套的最大层数
  • 空表 :长度为0的表,记为 ()
  • 原子:不可再分的基本数据元素

3. 重要特性

递归性

  • 广义表本身可以是另一个广义表的子表
  • 广义表可以被其自身的子表共享
  • 广义表可以是一个递归的表

存储结构

通常采用链式存储,每个结点有两个域:

  • tag域:标识是原子(0)还是子表(1)
  • union域:存储原子值或指向子表的指针
  • next域:指向下一个元素

4. head() 和 tail() 操作详解

表头 head(LS)

  • 非空广义表的第一个元素
  • 可以是原子或子表
  • 示例:head((a,b,c)) = a

表尾 tail(LS)

  • 除第一个元素外,剩余元素构成的表
  • 总是一个表(即使只有一个元素)
  • 示例:tail((a,b,c)) = (b,c)

5. 重要示例

text 复制代码
A = ()                    # 空表,长度=0,深度=1
B = (e)                   # 长度=1,深度=1
C = (a, (b, c, d))        # 长度=2,深度=2
D = (A, B, C)             # 长度=3,深度=3
E = (a, E)                # 递归表,长度=2,深度=∞

6. 特殊广义表

  1. 纯表:所有元素都是原子(等价于线性表)
  2. 再入表:允许元素被共享
  3. 递归表:允许直接或间接递归引用

7. 应用领域

  • LISP/Scheme等函数式语言:程序和数据都用广义表表示
  • 符号计算:处理数学表达式
  • 人工智能:知识表示、模式匹配
  • 数据库:嵌套关系的表示

深度 vs 长度

长度 (Length)

  • 定义:最外层元素的个数
  • 计算方法:数最外层逗号分隔的元素个数 + 1
  • 示例
    • (a, b, c) → 长度 = 3
    • ((a, b), c, (d, e)) → 长度 = 3(虽然有三个元素,第一个和第三个是子表)
    • () → 长度 = 0

深度 (Depth)

  • 定义:括号嵌套的最大层数(原子的深度为0)
  • 计算方法:从最外层到最内层原子的括号层数
  • 示例
    • (a, b, c) → 深度 = 1
    • ((a, b), c) → 深度 = 2
    • (((a))) → 深度 = 3

对比示例

广义表 长度 深度 说明
() 0 1 空表特殊:深度为1
(a) 1 1 只有原子
(a, b, c) 3 1 多个原子
((a, b)) 1 2 一个子表,包含两个原子
(a, (b, c)) 2 2 第一个是原子,第二个是子表
((a, (b)), c) 2 3 嵌套更多层
((((a)))) 1 4 多层嵌套

重要区别

  1. 长度关注"广度":同一层有多少元素
  2. 深度关注"深度":最多嵌套了多少层

特殊情况

空表 ()

  • 长度 = 0(没有元素)
  • 深度 = 1(这是定义规定的)

递归表

text 复制代码
L = (a, L)  # 长度=2,深度=∞(无限)

计算技巧

计算深度

复制代码
深度 = 1 + max(各元素的深度)
空表深度 = 1
原子深度 = 0

计算长度

复制代码
长度 = 最外层逗号数 + 1
(不包括子表内部的逗号)

总结

  • 长度 = 水平方向有多少个元素
  • 深度 = 垂直方向最多有多少层嵌套

它们分别描述了广义表在水平和垂直两个维度上的大小,是完全正交的两个概念。

相关推荐
苦藤新鸡2 小时前
41.有序数组(二叉搜索树)转平衡二叉树
数据结构·力扣
毅炼4 小时前
hot100打卡——day14
java·数据结构·算法·leetcode·ai·深度优先·哈希算法
DLGXY4 小时前
数据结构——双向循环链表的建立、添加、遍历(十三)
数据结构·链表
C雨后彩虹4 小时前
优雅子数组
java·数据结构·算法·华为·面试
漫随流水4 小时前
leetcode回溯算法(46.全排列)
数据结构·算法·leetcode·回溯算法
睡一觉就好了。5 小时前
直接选择排序
数据结构·算法·排序算法
芬加达5 小时前
leetcode221 最大正方形
java·数据结构·算法
知无不研5 小时前
实现一个整形栈
c语言·数据结构·c++·算法
红豆诗人7 小时前
数据结构--顺序表
数据结构·顺序表