C++ 静态顺序表和动态顺序表

对比静态顺序表与动态顺序表

特性静态顺序表动态顺序表
大小固定动态
内存管理简单复杂
随机访问快速快速
插入/删除效率较低较低(需移动元素)
扩展能力不可扩展可扩展

C++ 静态顺序表概述

定义:静态顺序表是一种线性表的实现方式,采用一段连续的内存空间存储数据元素,具有固定的大小。在编译时确定长度,无法动态扩展。

主要特性

  • 固定大小:在创建时指定大小,无法在运行时改变。
  • 连续存储:元素在内存中是连续存放的,支持随机访问。
  • 效率:访问元素速度快,但插入和删除效率较低。

设计静态顺序表时,可以从以下思路入手:

设计思路

  1. 数据结构:使用动态数组(指针)存储元素,需管理数组的容量和当前大小。
  2. 基本操作
    • 插入:在指定位置插入元素,需移动后面的元素。
    • 删除:删除指定位置的元素,需移动后面的元素。
    • 访问:通过索引直接访问元素,利用数组的随机访问特性。

图示理解

[0] [1] [2] [3] [4]   // 初始静态顺序表,容量为5
 -   -   -   -   -     // 初始元素为空

插入10、20、30后:
[10] [20] [30] [ ] [ ]   // 当前大小为3

删除20后:
[10] [30] [ ] [ ] [ ]   // 当前大小为2

访问第0个元素:
返回10

实现

以下是静态顺序表的简单实现示例:

#include <iostream>

template <typename T>
class StaticArray {
private:
    T* arr;        // 存储元素的数组
    int capacity;  // 数组的最大容量
    int size;      // 当前元素数量

public:
    // 构造函数
    StaticArray(int cap) : capacity(cap), size(0) {
        arr = new T[capacity];
    }

    // 析构函数
    ~StaticArray() {
        delete[] arr;
    }

    // 插入元素
    bool insert(int index, const T& value) {
        if (index < 0 || index > size || size >= capacity) {
            return false; // 索引无效或已满
        }
        for (int i = size; i > index; --i) {
            arr[i] = arr[i - 1]; // 移动元素
        }
        arr[index] = value; // 插入新元素
        ++size;
        return true;
    }

    // 删除元素
    bool remove(int index) {
        if (index < 0 || index >= size) {
            return false; // 索引无效
        }
        for (int i = index; i < size - 1; ++i) {
            arr[i] = arr[i + 1]; // 移动元素
        }
        --size;
        return true;
    }

    // 获取元素
    T get(int index) const {
        if (index < 0 || index >= size) {
            throw std::out_of_range("Index out of range");
        }
        return arr[index];
    }

    // 获取当前大小
    int getSize() const {
        return size;
    }

    // 获取容量
    int getCapacity() const {
        return capacity;
    }

    // 打印数组
    void print() const {
        for (int i = 0; i < size; ++i) {
            std::cout << arr[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    StaticArray<int> array(5);

    // 插入元素
    array.insert(0, 10);
    array.insert(1, 20);
    array.insert(2, 30);
    array.print(); // 输出: 10 20 30

    // 删除元素
    array.remove(1);
    array.print(); // 输出: 10 30

    // 获取元素
    std::cout << "Element at index 0: " << array.get(0) << std::endl; // 输出: 10

    // 当前大小和容量
    std::cout << "Size: " << array.getSize() << ", Capacity: " << array.getCapacity() << std::endl;

    return 0;
}
 

主要操作

  1. 插入(Insert):在指定位置插入新元素,需移动后面的元素。
  2. 删除(Remove):删除指定位置的元素,需移动后面的元素。
  3. 获取(Get):通过索引访问元素,需注意索引范围。
  4. 容量管理:通过 capacitysize 管理数组的最大容量和当前元素数量。

应用场景

  • 简单数据存储:适合存储固定数量的数据,如学生成绩、产品列表等。
  • 需要快速访问的场景:适合需要频繁访问元素的情况。

优缺点

  • 优点

    • 随机访问速度快。
    • 实现简单。
  • 缺点

    • 固定大小,无法动态扩展。
    • 插入和删除操作效率低。

C++ 动态顺序表概述

定义:动态顺序表是一种线性表的实现,能够在运行时动态调整大小,适应数据量的变化。通常使用动态数组实现。

主要特性

  • 动态大小:可以根据需要扩展或缩减大小。
  • 随机访问:支持高效的随机访问。
  • 内存管理:需要处理内存的分配与释放。

设计思路

  1. 动态内存管理:使用动态数组,初始时给定一个容量,达到上限后进行扩展。
  2. 操作管理:支持插入、删除、访问操作,需处理元素移动。
  3. 扩展策略:一般采用容量翻倍的策略,避免频繁的内存分配。

图示理解

  1. 初始状态(容量为2):

  2. [0] [1]   // 初始动态顺序表
    -   -     // 空元素

  3. 插入元素10、20后

  4. [0] [1]
    [10] [20]  // 当前大小为2

  5. 插入元素30(触发扩展)

  6. [0] [1] [2] [3]
    [10] [20] [30] [ ]   // 扩展后容量变为4

  7. 删除元素20后

  8. [0] [1] [2] [3]
    [10] [30] [ ] [ ]   // 当前大小为2

实现

以下是动态顺序表的简单实现示例:

#include <iostream>

template <typename T>
class DynamicArray {
private:
    T* arr;          // 存储元素的数组
    int capacity;    // 数组的最大容量
    int size;        // 当前元素数量

    // 扩展数组的容量
    void resize() {
        capacity *= 2; // 容量翻倍
        T* newArr = new T[capacity];
        for (int i = 0; i < size; ++i) {
            newArr[i] = arr[i]; // 复制旧数组的元素
        }
        delete[] arr; // 释放旧数组
        arr = newArr; // 更新指针
    }

public:
    // 构造函数
    DynamicArray(int cap = 2) : capacity(cap), size(0) {
        arr = new T[capacity];
    }

    // 析构函数
    ~DynamicArray() {
        delete[] arr;
    }

    // 插入元素
    void insert(int index, const T& value) {
        if (index < 0 || index > size) {
            throw std::out_of_range("Index out of range");
        }
        if (size >= capacity) {
            resize(); // 扩展数组
        }
        for (int i = size; i > index; --i) {
            arr[i] = arr[i - 1]; // 移动元素
        }
        arr[index] = value; // 插入新元素
        ++size;
    }

    // 删除元素
    void remove(int index) {
        if (index < 0 || index >= size) {
            throw std::out_of_range("Index out of range");
        }
        for (int i = index; i < size - 1; ++i) {
            arr[i] = arr[i + 1]; // 移动元素
        }
        --size;
    }

    // 获取元素
    T get(int index) const {
        if (index < 0 || index >= size) {
            throw std::out_of_range("Index out of range");
        }
        return arr[index];
    }

    // 获取当前大小
    int getSize() const {
        return size;
    }

    // 打印数组
    void print() const {
        for (int i = 0; i < size; ++i) {
            std::cout << arr[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    DynamicArray<int> array;

    // 插入元素
    array.insert(0, 10);
    array.insert(1, 20);
    array.insert(2, 30);
    array.print(); // 输出: 10 20 30

    // 删除元素
    array.remove(1);
    array.print(); // 输出: 10 30

    // 获取元素
    std::cout << "Element at index 0: " << array.get(0) << std::endl; // 输出: 10

    // 当前大小
    std::cout << "Size: " << array.getSize() << std::endl; // 输出: 2

    return 0;
}

主要操作

  1. 插入(Insert):在指定位置插入元素,自动扩展数组。
  2. 删除(Remove):删除指定位置的元素,需移动后面的元素。
  3. 访问(Get):通过索引访问元素,需注意索引范围。
  4. 动态调整:当元素数量超过容量时,自动扩展数组。

应用场景

  • 数据量不确定:适合存储数据量不确定的情况,如动态用户输入、动态任务列表等。
  • 频繁插入和删除:适合需要频繁修改数据的场景。

优缺点

  • 优点

    • 能够动态扩展,适应变化的数据量。
    • 随机访问速度快。
  • 缺点

    • 需要管理内存,可能导致内存碎片。
    • 扩展时需要复制数组,效率较低。

常见坑

  1. 越界访问:对索引的检查不充分,导致访问越界。
  2. 内存泄漏:未正确释放动态分配的内存,导致内存泄漏。
  3. 频繁扩展:如果扩展策略不当,频繁扩展可能导致性能下降。
  4. 元素移动:插入和删除时未注意到元素的移动,可能导致数据错位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值