【数据结构】顺序表的实现——静态分配

news2024/9/24 11:32:32

在这里插入图片描述

🎈个人主页:豌豆射手^
🎉欢迎 👍点赞✍评论⭐收藏
🤗收录专栏:数据结构
🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步!

【数据结构】顺序表的实现——静态分配

  • 引言
  • 一 静态分配内存的概念
    • 1.1 概念
    • 1.2 类比
    • 1.3 例子
  • 二 顺序表静态分配的概念
    • 2.1 概念
    • 2.2 类比
  • 三 顺序表静态分配的实现方式
    • 3.1 定义顺序表结构体
    • 3.2 初始化顺序表:
    • 3.3 插入元素:
    • 3.4 删除元素:
    • 3.5 查找元素:
    • 3.6 修改元素:
  • 四 静态分配顺序表的优缺点分析
    • 4.1 优点:
    • 4.2 缺点:
  • 五 示例代码
  • 总结

引言

在数据结构的领域中,顺序表是一种基础且重要的线性表实现方式。它采用一段地址连续的存储单元依次存储线性表的数据元素,通过下标进行访问。

本文将重点探讨顺序表的静态分配实现方式,通过对其概念、实现方式以及优缺点的分析,帮助读者深入理解并掌握顺序表的相关知识
在这里插入图片描述

一 静态分配内存的概念

1.1 概念

在数据结构中,静态分配内存是一种在程序编译时确定所需内存大小,并在程序执行之前进行内存分配的方式。

这种分配方式通常在声明变量或数组时进行,它们被存储在程序的静态存储区或栈上。

静态分配内存具有几个特点。

首先,其大小在编译时就已经确定,因此具有固定的位置和生命周期

这意味着一旦分配了内存,其大小在程序运行期间不会改变

其次,静态分配的内存分配和释放是自动进行的,不需要手动管理。

当变量或数组超出其作用域或被销毁时,其占用的内存会自动被释放。

静态分配内存通常用于存储程序中的常量、全局变量和静态局部变量,以及其他需要在程序运行期间保持固定位置和生命周期的数据结构

在C和C++等语言中,静态区和静态内存的使用需要开发者手动控制,通常通过对变量的声明和定义进行修饰实现。

然而,静态分配内存也有一些局限性。

由于其在编译时确定大小,因此无法适应程序运行时可能出现的动态内存需求变化

如果分配的内存过大,可能会浪费系统资源;

如果过小,则可能导致程序运行出错。

为了应对这种局限性,动态内存分配被引入。

动态内存分配允许程序在运行时根据需要分配和释放内存,从而更灵活地管理内存资源。但需要注意的是,动态内存分配需要手动管理,如果管理不当可能导致内存泄漏或其他问题。

总的来说,静态分配内存是一种简单且高效的内存管理方式,适用于那些大小固定且生命周期明确的数据结构。但在处理复杂或动态变化的内存需求时,可能需要结合动态内存分配来使用。

1.2 类比

我们可以用现实中的一个例子来类比数据结构中静态分配内存的概念。

假设你正在策划一场大型活动,如音乐会或运动会。在这个场景中,你可以将静态分配内存类比为提前规划和分配资源的过程

静态分配内存

  • 大小确定:在策划活动时,你需要提前确定一些固定的资源需求,比如座位的数量、舞台的大小、音响设备的配置等。这些资源在活动开始前就已经被确定,并且不会在活动进行过程中改变。
  • 自动管理:一旦你规划了这些资源,它们就会按照你的计划自动存在。你不需要在活动过程中时刻关注这些资源的分配和释放。
  • 固定位置:座位、舞台、设备等在场地内都有固定的位置,它们在活动开始前就已经布置好,并且在活动进行过程中保持不变

类比到数据结构

  • 大小确定:在编程时,当你声明一个静态数组时,你需要在声明时就确定数组的大小。这个大小在程序运行期间不会改变
  • 自动管理:数组的内存分配和释放是由编译器自动管理的。你不需要手动去申请或释放内存
  • 固定位置:数组的元素在内存中也有固定的位置,你可以通过索引直接访问数组中的某个元素

通过这个类比,我们可以看到静态分配内存与现实生活中规划和分配固定资源的过程有很多相似之处。

它们都是在开始前就确定好大小、位置和数量,并且在整个过程中保持不变。

当然,这种固定性也带来了一定的局限性,比如无法应对突发的变化或需求增长。

在编程中,这种局限性可以通过动态内存分配来克服。但在现实生活中,我们也需要灵活应对变化,可能需要一些额外的策略和规划来确保资源的有效利用。

1.3 例子

下面是一个简单的C语言代码示例,展示了静态内存分配的基本用法。在这个例子中,我们将声明一个固定大小的整数数组,然后对其进行初始化,并打印出数组的内容。

#include <stdio.h>

int main() {
    // 静态分配内存,声明一个包含5个整数的数组
    int staticArray[5] = {1, 2, 3, 4, 5};
    
    // 遍历数组并打印每个元素的值
    for (int i = 0; i < 5; i++) {
        printf("staticArray[%d] = %d\n", i, staticArray[i]);
    }
    
    // 静态分配的内存在程序执行完毕后会自动释放
    return 0;
}

代码结果(假设运行在一个标准的终端或控制台):

staticArray[0] = 1
staticArray[1] = 2
staticArray[2] = 3
staticArray[3] = 4
staticArray[4] = 5

代码分析:

  1. main函数中,我们声明了一个名为staticArray的整数数组,并静态分配了5个整数的内存空间。这里的“静态”指的是内存分配是在编译时确定的,并且数组的大小在整个程序执行期间保持不变。

  2. 数组staticArray被初始化为包含5个整数值:1, 2, 3, 4, 5。这些值在编译时就已经确定,并存储在静态存储区。

  3. 通过一个for循环,我们遍历数组并打印出每个元素的值。由于数组是静态分配的,所以我们可以直接通过索引访问其元素。

  4. main函数返回后,由于staticArray是局部变量,其占用的内存会在函数结束时自动释放。然而,由于这是静态分配的内存,实际上编译器在程序编译时就已经确定了这块内存的释放时间,而不是在运行时。

注意:虽然这个例子中的数组名为staticArray,但这里的“静态”并不是指C语言中的static关键字。这里的“静态”仅用于描述内存分配的方式是静态的,即在编译时确定

在C语言中,static关键字用于声明变量的生命周期为整个程序执行期间,而不仅仅是它们所在的函数或代码块

在本例中,即使我们没有使用static关键字,数组仍然是静态分配的,因为它的大小在编译时确定,并且作为局部变量存储在栈上。

如果要使数组的生命周期跨越多个函数调用,可以使用static关键字,但这与静态内存分配的概念是不同的。

二 顺序表静态分配的概念

2.1 概念

在数据结构中,顺序表是一种线性表的存储结构,其中元素在物理内存中以连续的方式存储。

顺序表可以通过两种方式进行实现:静态分配和动态分配

静态分配是指顺序表在声明时其大小就已经确定,且这个大小在程序的整个运行期间都不会改变

在静态分配中,顺序表通常是通过数组来实现的,因为数组的大小在编译时确定,并且一旦确定就不能更改

即静态分配的内存空间在程序执行前就已经分配完毕,并且会在程序执行完毕后自动释放。

静态分配顺序表的主要优点在于其简单性和效率

由于数组的大小在编译时确定,因此编译器可以进行一些优化,提高程序的执行效率。

此外,静态分配的顺序表在访问元素时具有较快的速度,因为可以通过简单的计算(即基址加偏移量)直接定位到元素的存储位置。

然而,静态分配顺序表也存在一些局限性。最主要的问题是其大小固定,无法根据程序运行时的需求进行动态调整

如果预先分配的空间过大,会造成内存资源的浪费;

如果分配的空间过小,则可能导致程序在运行时出现数组越界等错误。

因此,在选择使用静态分配顺序表时,需要根据实际的应用场景和需求进行权衡

如果数据量固定且不大,静态分配是一个简单且高效的选择;

如果数据量可能动态变化,或者需要更灵活的内存管理,那么可能需要考虑使用动态分配或其他数据结构。

2.2 类比

现实中的例子可以类比为在图书馆中分配书架来存储书籍

假设图书馆决定为某个特定类别的书籍分配书架。这个决定是在图书馆规划阶段就做出的,并且书架的数量和位置在规划完成后就固定下来了。这就是类似于数据结构中顺序表的静态分配。

静态分配书架的类比

  1. 大小确定:图书馆根据预计的书籍数量和类别,确定需要多少个书架来存放这些书籍。这些书架的数量和大小在图书馆建设或重新规划时就已经确定,并且在之后的使用过程中不会改变

  2. 位置固定:书架在图书馆内有固定的位置,按照规划好的布局摆放。每个书架都有一个固定的编号或位置标识,方便读者和图书管理员查找和管理。

  3. 连续存储:书架上的格子或层数是连续的,用于存放同一类别的书籍。这种连续存储的方式使得查找和取放书籍变得相对容易,类似于顺序表在内存中的连续存储

  4. 无法动态调整:一旦书架的数量和位置确定后,图书馆就难以根据书籍数量的变化来动态调整书架的配置。如果书籍数量增多,超出了现有书架的容量,图书馆可能需要重新规划并增加书架,这涉及到较大的改动和成本。

类比到数据结构

  1. 大小确定:在编程时,当你静态分配一个顺序表(例如通过数组)时,你需要在声明时就确定顺序表的大小(即数组的长度)。这个大小在程序运行期间不会改变

  2. 位置固定:顺序表的元素在内存中有固定的位置,通过索引可以直接访问到特定的元素

  3. 连续存储:顺序表在内存中占用连续的内存空间,这使得访问元素时可以通过简单的计算来定位到元素的地址。

  4. 无法动态调整:一旦顺序表的大小确定后,如果在程序运行过程中需要增加或减少元素的数量,而原有空间不足或过多,那么就需要进行额外的处理,如重新分配内存或浪费空间

通过这个类比,我们可以看到静态分配书架与静态分配顺序表在概念上有很多相似之处。

它们都是在规划或声明时就确定了大小和位置,并且在之后的使用过程中保持不变

然而,这种固定性也带来了一定的局限性,特别是在需要应对变化或增长的情况时。

因此,在现实中,图书馆可能会根据实际需求进行灵活调整,而在编程中,我们也有动态内存分配等方法来应对类似的问题。

三 顺序表静态分配的实现方式

顺序表静态分配的实现步骤主要涉及以下几个方面:

3.1 定义顺序表结构体

首先,需要定义一个结构体来表示顺序表。这个结构体通常包含两个主要部分:一个是用于存储元素的数组,另一个是用于记录顺序表当前长度的变量。例如,在C语言中,可以这样定义:

#define MAXSIZE 100 // 假设顺序表的最大长度为100

typedef struct {
    int data[MAXSIZE]; // 用于存储元素的数组
    int length;        // 记录顺序表当前长度
} SeqList;

在这个例子中,MAXSIZE 是静态分配的顺序表的最大容量,而 data 数组用于存储顺序表中的元素,length 则记录顺序表当前已存储的元素个数。

具体代码分析:

  1. #define MAXSIZE 100:这行代码定义了一个宏MAXSIZE,其值为100。这个宏在后续的代码中将被用作顺序表的最大长度,也就是数组data的大小。通过宏定义,可以在不修改源代码的情况下,方便地调整顺序表的最大长度。

  2. typedef struct {...} SeqList;:这行代码定义了一个结构体类型SeqList。结构体包含两个成员:

    • int data[MAXSIZE];:这是一个整型数组,用于存储顺序表中的元素。数组的大小由前面定义的宏MAXSIZE确定,即最大可以存储100个整数
    • int length;:这是一个整型变量,用于记录顺序表当前的长度,即当前顺序表中存储的元素的数量。这个长度在初始化时为0,随着元素的插入和删除操作而变化

整个代码段定义了一个简单的顺序表结构,其中使用了静态分配的方式来确定数组的大小。

3.2 初始化顺序表:

在创建顺序表时,需要对其进行初始化。初始化通常包括将顺序表的长度设置为0,以确保它是一个空表

void InitList(SeqList *L) {
    L->length = 0; // 将顺序表长度初始化为0
}

具体代码分析:

这段代码定义了一个名为InitList的函数,它接受一个指向SeqList结构体的指针L作为参数。该函数的主要目的是初始化顺序表,使其处于一个空表的状态。以下是对代码每个步骤的分析:

  1. void InitList(SeqList *L) {:定义了一个返回类型为void的函数InitList,它接受一个指向SeqList结构体的指针L作为参数。通过指针,函数能够访问和修改传入的顺序表实例

  2. L->length = 0;:这行代码通过指针L访问顺序表结构体中的length成员,并将其值设置为0。这个操作表示初始化顺序表,将其长度设置为0,即表示顺序表当前没有任何元素

  3. }:函数体结束。

综上,InitList函数的整个步骤就是接收一个顺序表的指针,然后将其长度初始化为0,从而实现顺序表的初始化。这样的初始化操作是创建新顺序表或重置现有顺序表为空表时的常见步骤。

3.3 插入元素:

向顺序表中插入元素时,需要检查顺序表是否已满(即当前长度是否已经达到最大容量)。如果未满,则将新元素添加到顺序表的末尾,并更新顺序表的长度。

int InsertList(SeqList *L, int elem) {
    if (L->length >= MAXSIZE) {
        // 顺序表已满,无法插入新元素
        return 0; // 返回失败
    }
    L->data[L->length] = elem; // 将新元素添加到顺序表末尾
    L->length++;              // 更新顺序表长度
    return 1;                  // 返回成功
}

具体代码分析:

这段代码定义了一个名为InsertList的函数,用于向顺序表SeqList中插入一个元素。以下是对代码每个步骤的分析:

首先,函数接受两个参数:一个指向SeqList结构体的指针L,以及一个待插入的整数元素elem

接着,函数检查顺序表是否已满,即检查L->length(顺序表的当前长度)是否大于等于MAXSIZE(顺序表的最大容量)。

如果是,说明顺序表已满,无法再插入新元素,因此函数返回0,表示插入失败。

如果顺序表未满,函数执行下一步,将新元素elem插入到顺序表的末尾,具体做法是将elem赋值给L->data[L->length],即顺序表数组中当前长度对应的位置。

然后,函数将顺序表的长度L->length加1,以反映新元素的插入。

最后,函数返回1,表示元素插入成功

整个函数通过检查顺序表是否已满、插入新元素、更新顺序表长度和返回操作结果等步骤,实现了向顺序表中插入新元素的功能。

3.4 删除元素:

从顺序表中删除元素时,通常需要指定要删除元素的位置。删除操作包括将指定位置后的所有元素前移一位,并更新顺序表的长度。

int DeleteList(SeqList *L, int pos) {
    if (pos < 1 || pos > L->length) {
        // 删除位置不合法
        return 0; // 返回失败
    }
    for (int i = pos; i < L->length; i++) {
        L->data[i - 1] = L->data[i]; // 将后续元素前移
    }
    L->length--; // 更新顺序表长度
    return 1;    // 返回成功
}

具体代码分析:

这段代码定义了一个名为DeleteList的函数,用于从顺序表SeqList中删除指定位置的元素。以下是对代码每个步骤的分析:

首先,函数接受两个参数:一个指向SeqList结构体的指针L,以及一个整数pos表示要删除元素的位置。

接着,函数检查删除位置pos是否合法

如果pos小于1或者大于顺序表的当前长度L->length,说明删除位置不合法,因此函数直接返回0,表示删除操作失败。

如果删除位置合法,函数进入循环,从pos位置开始,将顺序表中该位置及之后的每个元素都向前移动一位覆盖掉前一个元素的位置。这样,原来pos位置上的元素就被后续的元素所替代,从而实现了删除操作。

循环结束后,函数将顺序表的长度L->length减1,以反映元素被删除的情况。

最后,函数返回1,表示元素删除成功。

整个函数通过检查删除位置、移动元素和更新顺序表长度等步骤,实现了从顺序表中删除指定位置元素的功能。

在顺序表中,元素是按照数组的形式连续存储的。因此,当要删除某个位置的元素时,我们不能简单地移除那个元素,因为这会导致数组中出现一个“空洞”,即不连续的内存空间。为了维持顺序表的连续性,我们需要将删除位置之后的所有元素都向前移动一位,覆盖掉被删除元素的位置。

在这段代码中,for循环负责执行这个元素前移的操作。它从要删除的位置pos开始,将每个位置的元素值赋给前一个位置,直到到达顺序表的末尾。这样,原来pos位置上的元素就被后面的元素所覆盖,实现了删除的效果。

因此,虽然代码中并没有直接执行一个显式的“删除”操作(比如将某个元素的值设置为一个特殊值或NULL),但通过移动元素和更新长度,已经间接地实现了删除指定位置元素的功能。

3.5 查找元素:

顺序表的查找操作通常通过遍历数组来实现,比较目标值与顺序表中每个元素的值,直到找到目标值或遍历完整个顺序表。

int GetElem(SeqList L, int pos, int *elem) {
    if (pos < 1 || pos > L.length) {
        // 查找位置不合法
        return 0; // 返回失败
    }
    *elem = L.data[pos - 1]; // 返回查找位置的元素值
    return 1;                 // 返回成功
}

具体代码分析:

这段代码定义了一个名为GetElem的函数,用于从顺序表SeqList中获取指定位置的元素值。以下是对代码每个步骤的分析:

首先,函数接受三个参数:

一个SeqList类型的顺序表L,一个整数pos表示要查找的元素位置,以及一个整数指针elem用于返回查找到的元素值。

接着,函数检查查找位置pos是否合法。

如果pos小于1或者大于顺序表的当前长度L.length,说明位置不合法,因此函数直接返回0,表示查找失败。

如果查找位置合法,函数通过指针elem返回顺序表中对应位置的元素值。

这里使用了数组下标pos - 1来访问数组元素,因为数组下标是从0开始的,而位置是从1开始计数的。

最后,函数返回1,表示查找成功,并且已经将查找到的元素值通过指针elem返回给了调用者。

整个函数通过检查位置合法性、返回元素值和返回操作结果等步骤,实现了从顺序表中获取指定位置元素的功能。

3.6 修改元素:

修改顺序表中的元素只需要指定位置和新值,然后直接替换原有元素即可。

int UpdateElem(SeqList *L, int pos, int newElem) {
    if (pos < 1 || pos > L->length) {
        // 修改位置不合法
        return 0; // 返回失败
    }
    L->data[pos - 1] = newElem; // 修改指定位置的元素值
    return 1;                    // 返回成功
}

具体代码分析:

这段代码定义了一个名为UpdateElem的函数,用于更新顺序表SeqList中指定位置的元素值。以下是对代码每个步骤的分析:

首先,函数接受三个参数:

一个指向SeqList结构体的指针L,表示要更新的顺序表;一个整数pos,表示要更新的元素位置;以及一个整数newElem,表示新的元素值。

接着,函数检查更新位置pos是否合法。

如果pos小于1或者大于顺序表的当前长度L->length,说明位置不合法,因此函数直接返回0,表示更新失败。

如果更新位置合法,函数将新元素值newElem赋值给顺序表中对应位置的元素。

这里使用了数组下标pos - 1来访问数组元素,因为数组下标是从0开始的,而位置是从1开始计数的。

最后,函数返回1,表示更新成功。

整个函数通过检查位置合法性、更新元素值和返回操作结果等步骤,实现了顺序表中指定位置元素的更新功能。

这些步骤涵盖了顺序表静态分配的基本操作。

需要注意的是,由于静态分配的顺序表大小在初始化时就已经确定,因此在插入元素时需要检查是否已满,以避免数组越界错误。

同时,由于顺序表在内存中占用的是连续空间,因此插入和删除操作可能会涉及到大量元素的移动,这在某些情况下可能会影响性能。

在实际应用中,如果数据量较大或需要频繁进行插入和删除操作,可能需要考虑使用动态分配或其他数据结构来优化性能。

四 静态分配顺序表的优缺点分析

静态分配顺序表是数据结构中的一种常见形式,它基于数组实现,具有固定的存储空间大小。以下是对其优缺点的详细分析:

4.1 优点:

  1. 存储连续:静态分配顺序表的元素在物理存储上是连续的,这意味着通过下标访问元素的速度非常快,因为可以直接通过计算得出元素的存储位置。

  2. 空间利用率高:因为顺序表是基于数组实现的,其空间利用率通常比链表等结构要高。数组在内存中占用的是一块连续的空间,没有像链表那样的指针占用额外的空间。

  3. 随机访问:顺序表支持随机访问,即可以通过任意位置的索引直接访问该位置的元素,这在某些应用中是非常有用的,如快速查找特定位置的元素。

  4. 操作简单:对于顺序表,插入和删除操作通常只需要移动少量元素即可完成,这使得操作相对简单和高效。

4.2 缺点:

  1. 空间限制:静态分配顺序表的最大缺点是它的空间大小是固定的,一旦初始化后就不能改变。这意味着如果数据量超过了初始分配的空间,就会导致空间溢出,无法继续存储新的数据。

  2. 插入和删除效率:尽管顺序表的插入和删除操作在某些情况下可以高效完成,但在某些特定位置(如头部或中间位置)插入或删除元素时,可能需要移动大量的元素,这会导致效率降低。

  3. 扩展性差:由于静态分配顺序表的空间大小是固定的,因此在面对不断增长的数据量时,需要重新分配更大的空间并复制原有的数据,这不仅增加了操作的复杂性,还可能导致数据丢失或不一致。

  4. 灵活性不足:与链表等动态数据结构相比,静态分配顺序表的灵活性较差。链表可以根据需要动态地分配和释放内存,而顺序表则需要在初始化时就确定空间大小,这在某些应用中可能不够灵活。

综上所述,静态分配顺序表在访问速度快、空间利用率高等方面具有优势,但在空间限制、插入和删除效率、扩展性和灵活性等方面存在不足。因此,在选择使用静态分配顺序表时,需要根据具体的应用场景和需求进行权衡和选择。

五 示例代码

以下是一个静态分配顺序表的简单示例代码,包括初始化、插入、删除、查找和更新元素等基本操作的实现。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAXSIZE 100 // 假设顺序表的最大长度为100

typedef struct {
    int data[MAXSIZE]; // 存储元素的数组
    int length;        // 当前顺序表的长度
} SeqList;

// 初始化顺序表
void InitList(SeqList *L) {
    L->length = 0;
}

// 插入元素
bool InsertList(SeqList *L, int elem) {
    if (L->length >= MAXSIZE) {
        // 顺序表已满,无法插入新元素
        return false;
    }
    L->data[L->length] = elem; // 将新元素添加到顺序表末尾
    L->length++;              // 更新顺序表长度
    return true;
}

// 删除指定位置的元素
bool DeleteList(SeqList *L, int pos) {
    if (pos < 1 || pos > L->length) {
        // 删除位置不合法
        return false;
    }
    for (int i = pos; i < L->length; i++) {
        L->data[i - 1] = L->data[i]; // 将后续元素前移
    }
    L->length--; // 更新顺序表长度
    return true;
}

// 查找元素
int GetElem(SeqList L, int pos, int *elem) {
    if (pos < 1 || pos > L.length) {
        // 查找位置不合法
        return 0;
    }
    *elem = L.data[pos - 1]; // 返回查找位置的元素值
    return 1;
}

// 更新指定位置的元素值
bool UpdateElem(SeqList *L, int pos, int newElem) {
    if (pos < 1 || pos > L->length) {
        // 修改位置不合法
        return false;
    }
    L->data[pos - 1] = newElem; // 修改指定位置的元素值
    return true;
}

// 打印顺序表
void PrintList(SeqList L) {
    for (int i = 0; i < L.length; i++) {
        printf("%d ", L.data[i]);
    }
    printf("\n");
}

int main() {
    SeqList L;
    InitList(&L);

    // 插入元素
    InsertList(&L, 10);
    InsertList(&L, 20);
    InsertList(&L, 30);

    // 打印顺序表
    printf("List after insertion: ");
    PrintList(L);

    // 更新元素
    UpdateElem(&L, 2, 25);

    // 打印顺序表
    printf("List after update: ");
    PrintList(L);

    // 删除元素
    DeleteList(&L, 2);

    // 打印顺序表
    printf("List after deletion: ");
    PrintList(L);

    // 查找元素
    int elem;
    if (GetElem(L, 1, &elem)) {
        printf("Element at position 1: %d\n", elem);
    } else {
        printf("Invalid position for element retrieval.\n");
    }

    return 0;
}

以下是该代码在main函数中执行后的输出样子:

List after insertion: 10 20 30 
List after update: 10 25 30 
List after deletion: 10 30 
Element at position 1: 10

解释:

  1. InsertList 函数被调用了三次,将元素 10、20 和 30 插入到顺序表 L 中。

  2. PrintList 函数被调用,输出顺序表的内容,显示 10 20 30

  3. UpdateElem 函数被调用,将顺序表中位置 2(注意位置是从 1 开始的)的元素从 20 更新为 25。

  4. 再次调用 PrintList 函数,输出更新后的顺序表内容,显示 10 25 30

  5. DeleteList 函数被调用,删除顺序表中位置 2 的元素(现在是 25)。

  6. 第三次调用 PrintList 函数,输出删除元素后的顺序表内容,显示 10 30

  7. GetElem 函数被调用,尝试获取位置 1 的元素。因为位置合法,所以函数返回 1,并且通过指针 elem 返回了元素值 10。

  8. 输出通过 GetElem 函数获取到的元素值,显示 Element at position 1: 10

注意,这段代码假设了静态顺序表的最大长度为 MAXSIZE,定义为 100。在实际应用中,这个值可能需要根据具体的应用场景进行调整。此外,这个简单的例子没有包含错误处理,例如当尝试插入超过顺序表最大长度的元素时,InsertList 函数只是简单地返回 false,并没有给出明确的错误信息。在实际应用中,通常会添加更详细的错误处理逻辑。

总结

通过对顺序表静态分配实现方式的详细探讨,我们深入了解了其概念、实现过程以及优缺点。

静态分配顺序表具有存储密度高、空间利用率好等优点,适用于数据元素数量确定且不易发生变化的场景。

然而,其缺点也不容忽视,如空间扩展性差、插入和删除操作效率较低等。

因此,在实际应用中,我们需要根据具体需求和数据特点来选择合适的顺序表实现方式。

示例代码部分展示了静态分配顺序表的基本操作,包括初始化、插入、删除、查找和修改元素等。

这些操作的实现方式简单明了,为读者提供了实践操作的参考。

综上所述,顺序表静态分配实现方式在数据结构领域中具有重要地位。通过本文的学习,相信读者已经对顺序表有了更深入的理解和掌握,能够在实际应用中灵活运用。

这篇文章到这里就结束了

谢谢大家的阅读!

如果觉得这篇博客对你有用的话,别忘记三连哦。

我是豌豆射手^,让我们我们下次再见

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1552034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ZNB20罗德与施瓦茨ZNB20网络分析仪

181/2461/8938产品概述&#xff1a; 罗德与施瓦茨 ZNB20 矢量网络分析仪具有高达 140 dB 的宽动态范围&#xff08;在 10 Hz IF 带宽时&#xff09;、低于 0.004 dB RMS 的低迹线噪声&#xff08;在 10 kHz IF 带宽时&#xff09;以及高达 的高输出功率13 dBm&#xff0c;可在…

Zabbix-告警

基本概念 一、介绍 自定义的监控项默认不会自动报警 首页也不会提示错误 需要配置触发器与报警动作才可以自动报警 二、触发器 表达式&#xff0c;如内存不足300M&#xff0c;用户超过30个等 当触发条件发生后&#xff0c;会导致一个触发事件 触发事件会执行某个动作 …

网络编程综合项目-多用户通信系统

文章目录 1.项目所用技术栈本项目使用了java基础&#xff0c;面向对象&#xff0c;集合&#xff0c;泛型&#xff0c;IO流&#xff0c;多线程&#xff0c;Tcp字节流编程的技术 2.通信系统整体分析主要思路&#xff08;自己理解&#xff09;1.如果不用多线程2.使用多线程3.对多线…

ssh 公私钥(github)

一、生成ssh公私钥 生成自定义名称的SSH公钥和私钥对&#xff0c;需要使用ssh-keygen命令&#xff0c;这是大多数Linux和Unix系统自带的标准工具。下面&#xff0c;简单展示如何使用ssh-keygen命令来生成具有自定义名称的SSH密钥对。 步骤 1: 打开终端 首先&#xff0c;打开我…

vue前端工程化

前言 本文介绍的是有关于vue方面的前端工程化实践&#xff0c;主要通过实践操作让开发人员更好的理解整个前端工程化的流程。 本文通过开发准备阶段、开发阶段和开发完成三个阶段开介绍vue前端工程化的整体过程。 准备阶段 准备阶段我将其分为&#xff1a;框架选择、规范制…

AI智能分析网关智慧食安监管系统方案

3.15晚会刚过不久&#xff0c;淀粉肠的“屈辱”终于得以洗清&#xff0c;但某些品牌奶茶、梅菜扣肉、预制菜等等&#xff0c;生产过程仍是触目惊心。如何提升食品安全管理水平&#xff0c;保障食品从生产到消费环节的质量和安全&#xff1f;TSINGSEE青犀智利用智能分析网关V4Ea…

mysql--事务四大特性与隔离级别

事务四大特性与隔离级别 mysql事务的概念事务的属性事务控制语句转账示例 并发事务引发的问题脏读脏读场景 不可重复读幻读幻读场景 事务的隔离级别读未提交读已提交可重复读&#xff08;MySQL默认&#xff09; 总结 mysql事务的概念 事务就是一组操作的集合&#xff0c;他是一…

x86的内存分段机制

8086 是 Intel 公司第一款 16 位处理器&#xff0c;诞生于 1978 年&#xff0c;所以说它很古老。 一.8086 的通用寄存器 8086 处理器内部共有 8 个 16 位的通用处理器&#xff0c;分别被命名为 AX、 BX、 CX、 DX、 SI、 DI、 BP、 SP。如下图所示。 “通用”的意思是…

幻兽帕鲁服务器多少钱?可真便宜呀

2024年全网最全的幻兽帕鲁服务器租用价格表&#xff0c;阿里云幻兽帕鲁游戏服务器26元1个月、腾讯云32元一个月、京东云26元一个月、华为云24元1个月&#xff0c;阿腾云atengyun.com整理最新幻兽帕鲁专用4核16G、8核16G、8核32G游戏服务器租用价格表大全&#xff1a; 阿里云幻…

8、鸿蒙学习-HAR

HAR&#xff08;Harmony Archive&#xff09;是静态共享包&#xff0c;可以包含代码、C库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。HAR不同于HAP&#xff0c;不能独立安装运行在设备上。只能作为应用模块的依赖项被引用。 一、创建…

【案例·增】获取当前时间、日期(含,SQL中DATE数据类型)

问题描述&#xff1a; 需要使用当前时间、日期&#xff0c;可以使用 SQL 中的 CURDATE() 、NOW()、CURTIME()运算符 案例&#xff1a; INSERT INTO table_name(current_time, column_name2,...) VALUES (NOW(),, ...)规则(Date 相关函数)&#xff1a; 规则(Date数据类型)

初识C++之命名空间(namespace)

初识C之入门 命名空间(namespace) 文章目录 初识C之入门 命名空间(namespace)1.为什么要有命名空间2. 命名空间 namespace使用方法3. 作用域限定符(::&#xff09;和 命名空间(namespace)4. 命名空间的定义5. 命名空间的嵌套6. 命名空间的使用7. 总结 1.为什么要有命名空间 在C…

通过Caliper进行压力测试程序,且汇总压力测试问题解决

环境要求 第一步. 配置基本环境 部署Caliper的计算机需要有外网权限;操作系统版本需要满足以下要求:Ubuntu >= 16.04、CentOS >= 7或MacOS >= 10.14;部署Caliper的计算机需要安装有以下软件:python 2.7、make、g++(gcc-c++)、gcc及git。第二步. 安装NodeJS # …

Tensorflow2.0笔记 - 自定义Layer和Model

本笔记主要记录如何在tensorflow中实现自定的Layer和Model。详细内容请参考代码中的链接。 import time import tensorflow as tf from tensorflow import keras from tensorflow.keras import datasets, layers, optimizers, Sequential, metricstf.__version__ #关于自定义l…

软考 - 系统架构设计师 - 关系模型的完整性规则

前言 关系模型的完整性规则是一组用于确保关系数据库中数据的完整性和一致性的规则。这些规则定义了在关系数据库中如何存储、更新和查询数据&#xff0c;以保证数据的准确性和一致性。 详情 关系模型的完整性规则主要包括以下三类&#xff1a; 实体完整性规则 这是确保每个…

【Java程序设计】【C00373】基于(JavaWeb)Springboot的社区疫情返乡管控系统(有论文)

TOC 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;博客中有上百套程序可供参考&#xff0c;欢迎共同交流学习。 项目简介 项目获取 &#x1f345;文末点击卡片…

计算机网络——26通用转发和SDN

通用转发和SDN 网络层功能&#xff1a; 转发&#xff1a; 对于从某个端口 到来的分组转发到合适的 输出端口路由&#xff1a; 决定分组从源端 到目标端的路径 网络层 传统路由器的功能 每个路由器(Per Route)的控制平面 &#xff08;传统&#xff09; 每个路由器上都有实…

线程创建方式、构造方法和线程属性

欢迎各位&#xff01;&#xff01;&#xff01;推荐PC端观看 文章重点&#xff1a;学会五种线程的创造方式 目录 1.开启线程的五种方式 2.线程的构造方法 3.线程的属性及获取方法 1.开启线程的五种方式 创造线程的基本两步&#xff1a;&#xff08;1&#xff09;使用run方法…

C++取经之路(其二)——含数重载,引用。

含数重载: 函数重载是指&#xff1a;在c中&#xff0c;在同一作用域&#xff0c;函数名相同&#xff0c;形参列表不相同(参数个数&#xff0c;或类型&#xff0c;或顺序)不同&#xff0c;C语言不支持。 举几个例子&#xff1a; 1.参数类型不同 int Add(int left, int right)…

白盒测试、接口测试、自动化测试详解

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是白盒测试 白盒测试是一种测试策略&#xff0c;这种策略允许我们检查程序的内部结构&…