数据结构-数组与广义表

一、数组的定义与运算

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

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

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

相关推荐
CryptoPP8 分钟前
使用WebSocket实时获取印度股票数据源(无调用次数限制)实战
后端·python·websocket·网络协议·区块链
树叶@9 分钟前
Python数据分析7
开发语言·python
wydaicls12 分钟前
十一.C++ 类 -- 面向对象思想
开发语言·c++
白宇横流学长14 分钟前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
fat house cat_41 分钟前
【redis】线程IO模型
java·redis
姜君竹1 小时前
QT的工程文件.pro文件
开发语言·c++·qt·系统架构
思捻如枫1 小时前
C++数据结构和算法代码模板总结——算法部分
数据结构·c++
嘉陵妹妹1 小时前
深度优先算法学习
学习·算法·深度优先
老胖闲聊1 小时前
Python Rio 【图像处理】库简介
开发语言·图像处理·python
GalaxyPokemon1 小时前
LeetCode - 53. 最大子数组和
算法·leetcode·职场和发展