数据结构-数组与广义表

一、数组的定义与运算

1.1 数组的定义

数组是一个线性数据结构,由一组具有相同数据类型的元素组成。这些元素在内存中是连续存储的,可以通过索引快速访问。数组可以是一维的(如线性数组)、二维的(如矩阵)或多维的。

1.2 数组的基本运算

数组的基本运算包括:

  1. 查找 :通过索引访问数组中的元素。

  2. 插入:在数组中插入一个新元素(需要移动元素)。

  3. 删除:从数组中删除一个元素(需要移动元素)。

  4. 更新:修改数组中某个位置的元素值。

1.3 数组运算的图解

以下是一个简单的数组插入操作的图解:

复制代码
初始数组:[1, 2, 3, 4, 5]
插入元素6到索引2的位置:
步骤1:移动索引2及之后的元素
步骤2:在索引2的位置插入6
结果数组:[1, 2, 6, 3, 4, 5]

二、数组的顺序存储与实现

2.1 数组的顺序存储

数组的顺序存储是指将数组的元素按照一定的顺序(如行优先或列优先)存储在内存中。对于多维数组,通常采用行优先存储(如C语言)或列优先存储(如Fortran)。

2.2 数组的实现

以下是数组在不同语言中的实现:

2.2.1 C语言实现

bash 复制代码
​
#include <stdio.h>

#define MAX_SIZE 100

int main() {
    int arr[MAX_SIZE] = {0}; // 定义一个数组
    int n = 5; // 数组长度
    int i;

    // 初始化数组
    for (i = 0; i < n; i++) {
        arr[i] = i + 1; // 将数组元素初始化为1到5
    }

    // 查找数组元素
    printf("数组元素: ");
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 插入元素
    int insertValue = 6;
    int insertIndex = 2;
    for (i = n; i > insertIndex; i--) {
        arr[i] = arr[i - 1]; // 移动元素
    }
    arr[insertIndex] = insertValue; // 插入新元素
    n++; // 数组长度加1

    // 输出插入后的数组
    printf("插入后的数组: ");
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

​

2.2.2 C++实现

cpp 复制代码
​
#include <iostream>
using namespace std;

int main() {
    int arr[] = {1, 2, 3, 4, 5}; // 定义并初始化数组
    int n = 5; // 数组长度

    // 查找数组元素
    cout << "数组元素: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    // 插入元素
    int insertValue = 6;
    int insertIndex = 2;
    int *newArr = new int[n + 1]; // 创建新数组
    for (int i = 0; i < insertIndex; i++) {
        newArr[i] = arr[i]; // 复制前半部分
    }
    newArr[insertIndex] = insertValue; // 插入新元素
    for (int i = insertIndex; i < n; i++) {
        newArr[i + 1] = arr[i]; // 复制后半部分
    }
    delete[] arr; // 释放旧数组
    arr = newArr; // 更新数组指针
    n++; // 数组长度加1

    // 输出插入后的数组
    cout << "插入后的数组: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    delete[] arr; // 释放数组
    return 0;
}

​

2.2.3 Java实现

java 复制代码
​
public class ArrayExample {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5}; // 定义并初始化数组
        int n = 5; // 数组长度

        // 查找数组元素
        System.out.print("数组元素: ");
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();

        // 插入元素
        int insertValue = 6;
        int insertIndex = 2;
        int[] newArr = new int[n + 1]; // 创建新数组
        for (int i = 0; i < insertIndex; i++) {
            newArr[i] = arr[i]; // 复制前半部分
        }
        newArr[insertIndex] = insertValue; // 插入新元素
        for (int i = insertIndex; i < n; i++) {
            newArr[i + 1] = arr[i]; // 复制后半部分
        }
        arr = newArr; // 更新数组引用
        n++; // 数组长度加1

        // 输出插入后的数组
        System.out.print("插入后的数组: ");
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

​

2.2.4 Python实现

python 复制代码
​
# 定义数组
arr = [1, 2, 3, 4, 5]
n = len(arr)  # 数组长度

# 查找数组元素
print("数组元素:", arr)

# 插入元素
insert_value = 6
insert_index = 2
arr.insert(insert_index, insert_value)  # 使用Python内置的insert方法
n += 1  # 数组长度加1

# 输出插入后的数组
print("插入后的数组:", arr)

​

三、特殊矩阵的压缩存储

3.1 规律分布的特殊矩阵

特殊矩阵是指具有某种规律分布的矩阵,如对称矩阵、三角矩阵等。这些矩阵可以通过压缩存储来节省空间。

3.1.1 对称矩阵

对称矩阵是一个方阵,其元素满足 aij​=aji​。对称矩阵可以压缩存储为一个一维数组,只存储上三角或下三角的元素。

3.1.2 三角矩阵

三角矩阵是一个方阵,其上三角或下三角的元素均为常数(如0)。三角矩阵也可以压缩存储为一个一维数组。

3.2 稀疏矩阵

稀疏矩阵是一个大多数元素为0的矩阵。稀疏矩阵可以通过三元组表或十字链表进行压缩存储。

3.2.1 三元组表

三元组表是一种压缩存储稀疏矩阵的方法,只存储非零元素的行号、列号和值。

3.2.2 十字链表

十字链表是一种链式存储结构,每个非零元素用一个节点表示,节点包含行指针和列指针。

3.3 稀疏矩阵的图解

以下是一个稀疏矩阵的三元组表示图解:

复制代码
原始矩阵:
1 0 0 0
0 2 0 0
0 0 3 0
0 0 0 4

三元组表:
行 | 列 | 值
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
4 | 4 | 4

四、广义表

4.1 广义表的概念

广义表(Generalized List)是一种递归的数据结构,可以看作是线性表的推广。广义表中的元素可以是原子(单个数据项)或子表(另一个广义表)。

广义表的定义形式为: LS=(a1​,a2​,...,an​) 其中,ai​ 可以是原子或子表。

4.2 广义表的存储结构

广义表的存储结构通常采用头尾表示法或孩子兄弟表示法。

4.2.1 头尾表示法

头尾表示法将广义表分为头部和尾部。头部可以是原子或子表,尾部是剩下的元素组成的子表。

4.2.2 孩子兄弟表示法

孩子兄弟表示法将广义表中的每个元素视为一个节点,节点包含数据域、第一个孩子的指针和下一个兄弟的指针。

4.3 广义表的操作实现

广义表的基本操作包括求表头、表尾、插入、删除等。

4.4 广义表的图解

以下是一个广义表的头尾表示法图解:

复制代码
广义表:A = (a, (b, c), d)
头:a
尾:((b, c), d)

4.5 广义表的代码实现

4.5.1 C语言实现

bash 复制代码
​
#include <stdio.h>
#include <stdlib.h>

// 定义广义表节点
typedef struct GList {
    int isAtom; // 是否为原子
    int atom;   // 原子值
    struct GList *head; // 头指针
    struct GList *tail; // 尾指针
} GList;

// 创建原子节点
GList* createAtom(int value) {
    GList *node = (GList*)malloc(sizeof(GList));
    node->isAtom = 1;
    node->atom = value;
    node->head = NULL;
    node->tail = NULL;
    return node;
}

// 创建子表节点
GList* createSublist(GList *head, GList *tail) {
    GList *node = (GList*)malloc(sizeof(GList));
    node->isAtom = 0;
    node->head = head;
    node->tail = tail;
    return node;
}

// 打印广义表
void printGList(GList *list) {
    if (list == NULL) {
        printf("()");
        return;
    }
    if (list->isAtom) {
        printf("(%d)", list->atom);
    } else {
        printf("(");
        printGList(list->head);
        printf(", ");
        printGList(list->tail);
        printf(")");
    }
}

int main() {
    // 创建广义表 A = (a, (b, c), d)
    GList *a = createAtom(1); // a
    GList *b = createAtom(2); // b
    GList *c = createAtom(3); // c
    GList *d = createAtom(4); // d

    GList *bc = createSublist(b, createSublist(c, NULL)); // (b, c)
    GList *A = createSublist(a, createSublist(bc, createSublist(d, NULL))); // (a, (b, c), d)

    printf("广义表A: ");
    printGList(A);
    printf("\n");

    return 0;
}

​

4.5.2 C++实现

cpp 复制代码
​
#include <iostream>
using namespace std;

// 定义广义表节点
struct GList {
    bool isAtom; // 是否为原子
    int atom;    // 原子值
    GList *head; // 头指针
    GList *tail; // 尾指针

    GList() : isAtom(false), head(nullptr), tail(nullptr) {}
};

// 创建原子节点
GList* createAtom(int value) {
    GList *node = new GList;
    node->isAtom = true;
    node->atom = value;
    return node;
}

// 创建子表节点
GList* createSublist(GList *head, GList *tail) {
    GList *node = new GList;
    node->isAtom = false;
    node->head = head;
    node->tail = tail;
    return node;
}

// 打印广义表
void printGList(GList *list) {
    if (list == nullptr) {
        cout << "()";
        return;
    }
    if (list->isAtom) {
        cout << "(" << list->atom << ")";
    } else {
        cout << "(";
        printGList(list->head);
        cout << ", ";
        printGList(list->tail);
        cout << ")";
    }
}

int main() {
    // 创建广义表 A = (a, (b, c), d)
    GList *a = createAtom(1); // a
    GList *b = createAtom(2); // b
    GList *c = createAtom(3); // c
    GList *d = createAtom(4); // d

    GList *bc = createSublist(b, createSublist(c, nullptr)); // (b, c)
    GList *A = createSublist(a, createSublist(bc, createSublist(d, nullptr))); // (a, (b, c), d)

    cout << "广义表A: ";
    printGList(A);
    cout << endl;

    return 0;
}

​

4.5.3 Java实现

java 复制代码
​
public class GList {
    private boolean isAtom; // 是否为原子
    private int atom;       // 原子值
    private GList head;     // 头指针
    private GList tail;     // 尾指针

    // 构造函数
    public GList() {
        isAtom = false;
        head = null;
        tail = null;
    }

    // 创建原子节点
    public static GList createAtom(int value) {
        GList node = new GList();
        node.isAtom = true;
        node.atom = value;
        return node;
    }

    // 创建子表节点
    public static GList createSublist(GList head, GList tail) {
        GList node = new GList();
        node.isAtom = false;
        node.head = head;
        node.tail = tail;
        return node;
    }

    // 打印广义表
    public void print() {
        if (this == null) {
            System.out.print("()");
            return;
        }
        if (isAtom) {
            System.out.print("(" + atom + ")");
        } else {
            System.out.print("(");
            head.print();
            System.out.print(", ");
            tail.print();
            System.out.print(")");
        }
    }

    public static void main(String[] args) {
        // 创建广义表 A = (a, (b, c), d)
        GList a = createAtom(1); // a
        GList b = createAtom(2); // b
        GList c = createAtom(3); // c
        GList d = createAtom(4); // d

        GList bc = createSublist(b, createSublist(c, null)); // (b, c)
        GList A = createSublist(a, createSublist(bc, createSublist(d, null))); // (a, (b, c), d)

        System.out.print("广义表A: ");
        A.print();
        System.out.println();
    }
}

​

4.5.4 Python实现

python 复制代码
​
class GList:
    def __init__(self, is_atom=False, atom=None, head=None, tail=None):
        self.is_atom = is_atom
        self.atom = atom
        self.head = head
        self.tail = tail

    def __str__(self):
        if self.is_atom:
            return f"({self.atom})"
        else:
            return f"({self.head}, {self.tail})"

# 创建原子节点
def create_atom(value):
    return GList(is_atom=True, atom=value)

# 创建子表节点
def create_sublist(head, tail):
    return GList(is_atom=False, head=head, tail=tail)

# 主函数
if __name__ == "__main__":
    # 创建广义表 A = (a, (b, c), d)
    a = create_atom(1)  # a
    b = create_atom(2)  # b
    c = create_atom(3)  # c
    d = create_atom(4)  # d

    bc = create_sublist(b, create_sublist(c, None))  # (b, c)
    A = create_sublist(a, create_sublist(bc, create_sublist(d, None)))  # (a, (b, c), d)

    print("广义表A:", A)

​

五、总结核心知识点

5.1 时间性能分析

数据结构 查找 插入 删除 更新
数组 O(1) O(n) O(n) O(1)
广义表 O(n) O(n) O(n) O(n)

5.2 空间性能分析

数据结构 空间复杂度
数组 O(n)
广义表 O(n)

5.3 应用场景

数据结构 适用场景
数组 需要快速查找和固定大小的场景
广义表 需要处理嵌套结构的场景

通过以上内容,我们详细讲解了数组和广义表的定义、存储结构、操作实现以及性能分析。希望这些内容能够帮助你更好地理解和使用这两种数据结构。

相关推荐
bing_158几秒前
Spring Boot 项目中什么时候会抛出 FeignException?
java·spring boot·后端
写代码写到手抽筋9 分钟前
C++性能优化之访存优化(未完)
开发语言·c++
lingxiao1688812 分钟前
双目立体视觉
图像处理·算法·机器学习·计算机视觉
JNU freshman16 分钟前
和为target问题汇总
算法
2401_8590490820 分钟前
MSPM0--Timer(一口一口喂版)
arm开发·单片机·mcu·算法
Dovis(誓平步青云)21 分钟前
基于面向对象设计的C++日期推算引擎:精准高效的时间运算实现与运算重载工程化实践
开发语言·c++·经验分享·笔记
HORSE RUNNING WILD24 分钟前
解决 PicGo 上传 GitHub图床及Marp中Github图片编译常见难题指南
css·python·github
寂空_26 分钟前
【算法笔记】ACM数论基础模板
c++·笔记·算法
Java&Develop31 分钟前
springboot + mysql8降低版本到 mysql5.7
java·spring boot·后端
sg_knight34 分钟前
从单体架构到微服务:架构演进之路
java·spring boot·spring·spring cloud·微服务·云原生·架构