首页 > 编程语言 >C++ 静态顺序表和动态顺序表

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

时间:2024-09-29 13:21:40浏览次数:8  
标签:index arr 顺序 插入 静态 元素 C++ int size

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

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

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. 元素移动:插入和删除时未注意到元素的移动,可能导致数据错位。

标签:index,arr,顺序,插入,静态,元素,C++,int,size
From: https://blog.csdn.net/qq_50373827/article/details/142633086

相关文章

  • 南沙C++信奥老师解一本通题 1221:分成互质组
    ​ 【题目描述】给定n个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?【输入】第一行是一个正整数n。1≤n≤10。第二行是n个不大于10000的正整数。【输出】一个正整数,即最少需要的组数。【输入样例】6142033117143175【输出样例】3......
  • pbootcms制作TAG标签列表时改成静态栏目URL结构
    在PBootCMS中,将TAG标签列表从动态链接转换为静态化的类似栏目结构的需求可以通过以下步骤实现:步骤1:修改PHP文件打开PHP文件:打开 APPs/home/controller/ParserController.php 文件。找到并修改代码:找到大约第1852行左右的代码。删除原有代码,并替换为新的代码......
  • C++:模板初级
    一.泛型编程。1.1如何实现一个交换函数呢?voidSwap(int&left,int&right){ inttemp=left; left=right; right=temp;}voidSwap(double&left,double&right){ doubletemp=left; left=right; right=temp;}voidSwap(char&left,......
  • C++ 学习,标准库
    C++标准库是C++语言的重要组成部分,它提供了一系列的类、函数和模板,使得开发者能够更加高效地进行编程。C++标准库包括一组头文件,头文件提供了各种功能和工具,涵盖了输入输出、容器、算法、多线程、正则表达式等。C++标准库可以分为两部分:标准函数库: 由通用的、独立的、......
  • 【C++掌中宝】用最少的话让你全方位理解内联函数
    文章目录引言1.什么是内联函数2.工作原理3.内联函数的编程风格4.使用限制5.内联函数与宏的比较6.优缺点7.何时使用内联函数8.补充9.总结结语引言在C++编程中,函数的调用开销是程序运行效率的一个重要影响因素。为了解决频繁调用函数时的性能问题,C++提供了内......
  • 【C++标准模版库】map和set的介绍及使用
    map和set一.序列式容器和关联式容器二.set系列的使用1.set和multiset参考文档2.set类的介绍3.set的构造和迭代器4.set的增删查5.insert和迭代器遍历使用6.find和erase的使用7.erase迭代器失效问题8.lower_bound与upper_bound9.multiset和set的差异10.set解决:leetcode例题......
  • C/C++语言基础--C++面向对象之继承、继承限制、多继承、拷贝继承等知识讲解
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言通过前面几节课,我们学习了抽象、封装相关的概念,接下来我们将讲解继承;C语言后面也会继续更新知识点,如内联汇编;本人现在正在写一个C语言的图书管理系统,1000多行代码,包含之前所学的所有知识点,包括链表和顺序表等数据......
  • 【C++系列】C++的历史与发展
    欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏:⭐️全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题.⭐️AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。⭐️大数据平台建设指南:全面讲解从数据采集到......
  • 学习C++ 必看的书,你看过几本了?
    我会陆续把这些书的电子版放到我的资源中,需要的朋友可以下载,都是免积分的。C++PrimerC++沉思录EffectiveSTLeffectivec++STL源码剖析EssentialC++ExceptionalC++InsidetheC++ObjectModelModernC++DesignMoreEffectiveC++MoreExceptionalC++TheC+......
  • 类的静态数据成员
    类的静态数据成员有时需要为某个类的所有对象分配一个单一的存储空间。在C语言中,可以用全局变量,但这样很不安全。全局数据可以被任何人修改,而且,在一个项目中,它很容易与其他的名字相冲突。如果可以把一个数据当成全局变量那样去存储,但又被隐藏在类的内部,并且清楚地与这个......