数据结构-数组与广义表

一、数组的定义与运算

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 应用场景

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

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

相关推荐
骑驴看星星a4 分钟前
P10416 [蓝桥杯 2023 国 A] XYZ
算法·职场和发展·蓝桥杯
朴拙数科5 分钟前
Stable Diffusion秋叶整合包V4独立版Python本地API连接指南
开发语言·python·stable diffusion
又过一个秋10 分钟前
【sylar-webserver】重构日志系统
linux·c++·算法·重构
苹果酱056711 分钟前
Vue3 源码解析(六):响应式原理与 reactive
java·vue.js·spring boot·mysql·课程设计
朝新_23 分钟前
【数据结构】第四弹——LinkedList与链表
数据结构·链表
小川_wenxun28 分钟前
线程池的介绍
java·开发语言
傍晚冰川32 分钟前
【单片机 &C语言】单片机学习过程中常见C库函数(学习笔记)
c语言·笔记·stm32·单片机·学习·阿里云
慕仲卿33 分钟前
从零开始训练视觉多模态模型:10 步骤详解
算法
浅陌pa35 分钟前
01、单片机简介
c语言·stm32·单片机·嵌入式硬件