结构体变种特殊用法——顺序表

顺序表是一种基本的数据结构,它在C语言中通常使用数组来实现。顺序表是一种线性表的物理存储结构,其特点是数据元素的逻辑顺序和物理顺序相同,即表中第i个位置的元素对应数组的第i个元素。

顺序表的结构

结构体第一个元素应该写数组,其次是我们需要该顺序表实现的功能;

例如:一个可以容纳1000整形并且可以知道有效数据个数和容量大小的的顺序表。

typedef struct SlDatatype//数据表名称
{
    int arr[1000];//定义顺序表可容纳的数据个数
    int size;     //有效数据个数
    int capacity  //容量大小
}

顺序表的特点

  1. 随机访问:顺序表支持通过索引快速访问任意位置的元素。
  2. 动态分配:在C语言中,通常使用指针和动态内存分配(如mallocrealloc)来创建可变长度的顺序表。
  3. 连续存储:顺序表中的元素在内存中是连续存储的。

顺序表和数组的区别?

顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接⼝。

顺序表的分类

静态顺序表

数组空间确定,容量确定,预先给定的空间太大会造成空间浪费,太小会导致数据存储不完。

#define N 1000
typedef char SLDataType;
//静态顺序表
typedef struct seqlist 
{
SLDataType arr[N];
int size;//有效数据个数
}SL;

动态顺序表

将静态顺序表中首元素由数组名变成了数组地址,可以利用malloc,realloc函数来为表中数组动态申请空间,可以更高效的利用空间。

//动态顺序表
typedef struct seqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//容量大小
}SL;

下面详细的介绍动态顺序表常用功能的使用方法

初始化:使用malloccalloc函数动态分配内存空间,初始化顺序表。例如:

typedef struct {
    int *data;    // 指向动态分配数组的指针
    int length;   // 顺序表的当前长度
    int capacity; // 顺序表的最大容量
} SeqList;

void initSeqList(SeqList *list, int initialCapacity) //用于申请空间的函数
{
    list->data = (int *)malloc(initialCapacity * sizeof(int));//为函数申请初始空间
    if (list->data == NULL) //如果申请失败,则返回错误报告并退出程序
    {
        printf("Memory allocation failed.\n");
        exit(1);
    }
    list->length = 0;//刚申请空间,目前一个数据都没有,初始化顺序表长度为0;
    list->capacity = initialCapacity;//显示顺序表容量
}

销毁:使用free函数释放动态分配的内存空间。

void freeSeqList(SeqList *list) {
    free(list->data);
    list->data = NULL;
    list->length = 0;
    list->capacity = 0;
}

插入元素:在顺序表的指定位置插入元素,如果空间不足,需要使用realloc函数扩大数组容量。

void insert(SeqList *list, int index, int value)//用于给顺序表插入我们所需要记录的内容的函数
 {
    if (index < 0 || index > list->length)//例行报错
    {
        printf("Index out of bounds.\n");
        return;
    }
    if (list->length == list->capacity)//如果原数组内存不够,则继续申请空间
       {
        int newCapacity = list->capacity * 2;
        int *newData = (int *)realloc(list->data, newCapacity * sizeof(int));
        if (newData == NULL) {
            printf("Memory reallocation failed.\n");
            return;
        }
        list->data = newData;
        list->capacity = newCapacity;
    }

    for (int i = list->length; i > index; i--)//将原数据向左移动一位
    {
        list->data[i] = list->data[i - 1];
    }
    list->data[index] = value;
    list->length++;
}

删除元素:从顺序表中删除指定位置的元素。

void remove(SeqList *list, int index) 
{
    if (index < 0 || index >= list->length)
    {
        printf("Index out of bounds.\n");
        return;
    }
    for (int i = index; i < list->length - 1; i++) 
    {
        list->data[i] = list->data[i + 1];
    }
    list->length--;
}

查找元素:在顺序表中查找一个元素,返回其位置。

int find(SeqList *list, int value) {
    for (int i = 0; i < list->length; i++) {
        if (list->data[i] == value) {
            return i;
        }
    }
    return -1;
}

更新元素:更新顺序表中指定位置的元素值。

void update(SeqList *list, int index, int newValue) {
    if (index < 0 || index >= list->length) {
        printf("Index out of bounds.\n");
        return;
    }
    list->data[index] = newValue;
}

打印顺序表:打印顺序表中的所有元素。

void printSeqList(SeqList *list) {
    for (int i = 0; i < list->length; i++) {
        printf("%d ", list->data[i]);
    }
    printf("\n");
}

扩容:当顺序表的容量不足以容纳更多元素时,需要扩容。

void ensureCapacity(SeqList *list, int newCapacity) {
    int *newData = (int *)realloc(list->data, newCapacity * sizeof(int));
    if (newData == NULL) {
        printf("Memory reallocation failed.\n");
        return;
    }
    list->data = newData;
    list->capacity = newCapacity;
}

顺序表的使用注意事项

  1. 初始化:在创建动态顺序表时,需要为其分配初始内存空间。这通常通过malloccalloc函数完成。分配的内存应该足以存储预期数量的元素,同时留有一定的余地以便于后续的扩展。

  2. 扩容:当顺序表的元素数量达到当前容量时,需要扩容以避免溢出。扩容通常涉及到申请一块更大的内存空间,并将现有元素复制到新内存区域。扩容策略通常是将容量增加到原来的某个固定比例(如两倍),以减少频繁扩容的性能开销。

  3. 释放内存:当顺序表不再使用时,应该使用free函数释放分配的内存空间,以避免内存泄漏。

  4. 内存分配失败的处理:在使用mallocrealloc分配内存时,可能会因为各种原因(如内存不足)失败。程序应该检查这些函数的返回值,并在分配失败时进行适当的错误处理。

  5. 避免内存碎片:频繁的内存分配和释放可能会导致内存碎片,影响程序性能。可以通过适当的内存管理策略(如内存池)来减少内存碎片。

  6. 数据复制:在扩容时,需要将现有数据复制到新的内存区域。这个过程需要小心处理,确保所有数据都被正确复制,并且顺序不发生变化。

  7. 内存对齐和访问效率:现代计算机系统通常有内存对齐的要求。在分配内存时,应确保满足这些要求,以提高内存访问效率。

  8. 引用管理:在涉及到对象引用的动态顺序表中,需要注意管理好引用,确保不再使用的引用能够被垃圾回收,避免内存泄漏。

  9. 性能监控:在程序运行过程中,应监控内存使用情况,及时发现并解决内存使用中的问题,如内存泄漏、过度扩容等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值