一篇文章掌握“顺序表”

目录

一、线性表基础

1、逻辑结构

2、物理结构

二、顺序表

(一)顺序表定义

(二)分类

1、静态顺序表

2、动态顺序表

三、工程结构设计

四、动态表核心方法的实现

(一)初始化动态表

(二)增

1、空间检查与扩容

2、打印

3、尾插

4、头插

5、任意位置之前插入数据

6、任意位置之前批量插入元素

(三)删

1、尾删

2、头删

3、指定位置删除

4、指定位置批量删除元素

(四)改

1、修改指定位置数据

(五)查

1、查找顺序表中是否存在对应数据

(六)销毁动态顺序表

(七)总结

五、顺序表的问题与反思

(一)核心缺陷

[1、头部 / 中间操作效率低](#1、头部 / 中间操作效率低)

2、扩容消耗大

3、空间浪费不可避免

[(二) 改进方向:链表的引入](#(二) 改进方向:链表的引入)


一、线性表基础

线性表是 n 个具有相同特性的数据元素的有序、有限序列

线性表是一种在实际中广泛使用的数据结构,顺序表、链表、栈、队列、字符串均属于线性表。要理解顺序表,需要先掌握线性表的共性。

核心特性可从两个维度分析:

1、逻辑结构

一定是线性的,即元素间呈 "一条线" 的前后关系(如排队的人抽象为线性结构),是人为想象的抽象结构。

2、物理结构

不一定是线性的,即元素在内存中的存储地址可能连续(如数组),也可能不连续(如后续会学的链表)。

二、顺序表

(一)顺序表定义

顺序表是用物理地址连续的存储单元依次存储数据元素的线性结构 ,底层基于数组实现,但通过封装提供更完备的操作接口

不仅提供存储空间,还预实现增删改查等操作方法,用户无需重复编写基础逻辑。

(二)分类
1、静态顺序表

(1)概念 :用定长数组存储元素,初始化时空间大小固定,无法动态调整。

(2)结构体定义(代码实现)

cpp 复制代码
// 定义数据类型别名,方便后续修改存储类型(如int→char)
typedef int SLDataType;
// 宏定义数组固定大小
#define N 100
typedef struct SeqList {
    SLDataType a[N];  // 定长数组
    int size;         // 有效数据个数
} SL;

(3)结构解析

**① a[N]:**固定大小的数组,容量由N决定(如N=100则最多存 100 个元素)。

**② size:**关键变量,记录有效数据个数 ------ 如size=5表示数组前 5 个元素(下标 0-4)是有效数据,后续元素(下标 5-99)无意义。

**示例:**若N = 7(数组容量 7),当前存 4 个有效数据,则size = 4,指向数组下标 4 的位置(下一个可插入数据的位置)。

**(4)**特点

**① 优点:**结构简单,内存占用少

② 缺点:空间灵活性差给小了不够用,如存储用户数据时,空间不足导致用户注册失败;给大了造成浪费,如给 100 万空间仅用 1 万。

2、动态顺序表

(1)概念 :通过指针动态申请内存,空间不足时可扩容,适用于大多数实际场景。

(2)结构体定义

cpp 复制代码
typedef int SLDataType;
typedef struct SeqList {
    SLDataType* a;    // 动态数组指针(指向堆区内存)
    int size;         // 有效数据个数
    int capacity;     // 当前已申请的空间容量
} SL;

(3)结构解析

**① a:**指针,初始为NULL,后续通过malloc/realloc申请内存,指向存储数据的连续空间。

**② size:**有效数据个数,如size=3表示当前存了 3 个数据。

**③ capacity:**当前总容量,如capacity = 5表示已申请 5 个空间(可能用了3个,空闲2个)。

(4)特点

**① 优点:**按需扩容,空间浪费可控(如初始 10 个空间,满了扩到 20 个)。

**② 缺点:**需额外维护 capacity,结构稍复杂。

三、工程结构设计

需创建 3 个文件,分工明确,便于维护和调试,后续学链表、栈等结构也可复用此结构。头文件为 SeqList.h,实现文件为 SeqList.c,测试文件为 test.c。

头文件 的核心作用,首先是引用依赖的库、然后定义结构体 、再声明要实现的函数

实现文件 首先引用头文件(#include"SeqList.h"),然后完成对声明函数的具体实现

测试文件 首先引用头文件(#include"SeqList.h"),然后测试函数的正确性,函数的调用都是在这里完成的。

下面是一个工程里面,三个文件的具体展示。你要用到的头文件和结构体都先往 SeqList.h 里面去写,然后你要实现一个功能,就先往 SeqList.h 里面去写声明,先暂时确定参数与返回值。

声明完成之后,就在 SeqList.c 文件里面去实现,具体实现的期间可能存在返回值与参数的适当修改,此时同时也要修改头文件。

当头文件与实现文件的内容确认无误后,我们就在 Test.c 文件里面调用函数测试即可。

四、动态表核心方法的实现

你要用任何一个数据结构,第一步肯定是初始化,最后一步肯定是销毁 ,中间的操作步骤无非就是增、删、改、查

对于顺序表而言:

在增的方面,有尾插、头插、指定位置之前插入数据、指定位置之前插入批量数据;

在删的方面,有尾删、头删、删除指定位置数据、删除指定位置向后的批量数据;

在改的方面,就是对任意位置的数据进行修改;

在查的方面,就是查找顺序表,这个数据是否存在。

这个思路,不仅仅是顺序表,其他数据结构的也是大差不差的。

(一)初始化动态表

将动态顺序表初始化为 "空状态",避免野指针(未初始化的指针)导致程序崩溃。

1、头文件(SeqList.h)

cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//顺序表的结构
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;       //有效空间大小
	int capacity;   // 空间大小
}SL;

//typedef struct SeqList SL;

//初始化
void SLInit(SL* ps);

2、实现文件(SeqList.c)

cpp 复制代码
#include"SeqList.h"

//初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

3、测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
}
int main()
{
	test01();
	return 0;
}
(二)增

在下面的代码中,为了不重复书写头文件与定义结构体,从而使代码变得冗余,头文件我仅展示具体的函数声明 ,实现文件我仅展示具体的函数实现 ,测试文件我将使用目前所实现的函数进行测试

具体的函数代码已经上传,可于文章头部下载。

1、空间检查与扩容

插入数据前必调用,判断当前空间是否充足;不足则扩容,确保插入操作能正常执行。

因为我不确定每次增加的数据是,如同尾插、头插、定点插入,只插入一个数据;还是会批量插入,所以我需要通过加法计算得到总容量。

然后在下面将总容量与新容量进行对比,决定是否进行扩容。

若每次只增加一个空间,会存在频繁扩容 ,这样程序执行效率低,时间效率低;若每次增加的空间较大,会存在空间的浪费

所以一般增容成倍数去增加,通常是 2 倍,5个空间满了,就扩容成10个。

因为这个函数是实现文件的一个辅助函数,用于辅助实现文件里面函数的实现,而不是在测试文件中进行测试。

(1)头文件

传递的是结构体的指针,使用传址调用,间接传递整个结构体。

cpp 复制代码
//判断空间是否足够
void SLCheckCapacity(SL* ps);

(2)实现文件

cpp 复制代码
 //判断空间是否足够
void SLCheckCapacity(SL* ps, int needSize) {
    assert(ps);
    
    // 计算需要的总容量
    int requiredCapacity = ps->size + needSize;
    if (requiredCapacity <= ps->capacity) {
        return; // 容量足够,无需扩容
    }
    
    // 计算新容量(确保能容纳所有元素)
    int newCapacity;
    if (ps->capacity == 0) 
	    newCapacity = 4;
    else 
	    newCapacity = ps->capacity
    while (newCapacity < requiredCapacity) 
        newCapacity *= 2;
    
    // 扩容操作
    SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
    if (temp == NULL) {
        perror("realloc fail");
        exit(EXIT_FAILURE);
    }
    
    // 更新顺序表的指针和容量
    ps->arr = temp;
    ps->capacity = newCapacity;
}
2、打印

无论是增、删、改,都需要通过测试知道,是否执行成功。而反馈是否执行成功,最直观的就是将顺序表打印出来,而不是去一步步地调试。

如果打印失败,又无法确切发现问题在哪,才需要去调试解决。

(1)头文件

cpp 复制代码
//打印数据
void Print(SL* ps);

(2)实现文件

cpp 复制代码
//打印
void Print(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
		printf("%d\n", ps->arr[i]);
}
3、尾插

在顺序表末尾追加一个数据,无需挪动元素,效率最高(时间复杂度 O (1))

(1)头文件

传递的是结构体的指针,使用传址调用,间接传递整个结构体;同时传递需要插入的元素。

cpp 复制代码
//尾插
void SLPushBack(SL* ps, SLDataType x);

(2)实现文件

cpp 复制代码
//尾插(这个代码只能一个一个地插入)
//时间复杂度为O(1)
void SLPushBack(SL* ps, SLDataType x)
{
    // 判断结构体是否为空,同时
	assert(ps);
	SLCheckCapacity(ps, 1);
	
    ps->arr[ps->size] = x;
	ps->size++;
	//ps->arr[ps->size++] = x;
} 

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
    SLPushBack(&sl, 1);
    SLPushBack(&sl, 2);
    SLPushBack(&sl, 3);
    SLPushBack(&sl, 4);
    SLPushBack(&sl, 5);
    SLPushBack(&sl, 6);
    SLPushBack(&sl, 7);
    SLPushBack(&sl, 8);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
4、头插

在顺序表头部插入一个数据,需先将现有元素整体后移一位,避免数据被覆盖,时间复杂度为 O (n)

(1)头文件

cpp 复制代码
void SLPushFront(SL* ps, SLDataType x);

(2)实现文件

cpp 复制代码
void SLPushFront(SL* ps, SLDataType x)
{
	// 断言检测是否为空指针,下面两种测试也可以
    assert(ps);
	// assert(ps!=NULL);
    //if (ps == NULL)
	//	return 0;

    // 步骤1:检查空间
	SLCheckCapacity(ps,1);
	
    // 步骤2:现有元素整体后移
    int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	
    // 步骤3:头部插入新数据,同时有效数据个数+1
    ps->arr[0] = x;
	ps->size++;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	SLPushFront(&sl, 7);
	SLPushFront(&sl, 8);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
5、任意位置之前插入数据

在指定下标 pos 的 "前面" 插入数据(如pos=2,则插入到下标 2 的位置,原下标 2 及后续元素后移),是头插、尾插的通用场景。

(1)头文件

cpp 复制代码
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

(2)实现文件

cpp 复制代码
void SLInsert(SL* ps, int pos, SLDataType x) 
{
    assert(ps);
    // 步骤1:校验pos的合法性
    assert(pos >= 0 && pos <= ps->size);
    // 步骤2:检查空间
    SLCheckCapacity(ps, 1);
    // 步骤3:pos及后续元素整体后移
    int i = 0;
    for (i = ps->size; i > pos; i--) 
        ps->a[i] = ps->a[i - 1];
    // 步骤4:在pos位置插入数据
    ps->a[pos] = x;
    // 步骤5:有效数据个数+1
    ps->size++;
}

**关键校验:**assert(pos >= 0 && pos <= ps->size) ------ 若pos = -1(越界左)或pos = size + 1(越界右),程序立即报错,避免非法插入。

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	SLPushFront(&sl, 7);
	SLPushFront(&sl, 8);
    SLInsert(&sl, 2, 100);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
6、任意位置之前批量插入元素

在指定下标 pos 的 "前面" 插入任意数量的数据(如pos=2,count =3 ,则从到下标为 2 的位置开始插入 3 个元素,原下标 2 及后续元素后移)。

(1)头文件

cpp 复制代码
// 任意位置批量插入
// pos: 插入位置(0 <= pos <= size)
// data: 待插入的数据数组
// count: 插入的元素数量
void SLBatchInsert(SL* ps, int pos, const SLDataType* data, int count);

(2)实现文件

这里有一个关键的点,一旦要添加的数据的话,那么覆盖一定是从后往前,即先确定最后的一位的数据。因为如果覆盖从前往后,那前面的数据被覆盖了,就无法对后面的数据进行覆盖。

实现了这个函数,其实也可以任意插入一个元素,这是包含了上面函数的实现的。

cpp 复制代码
// 指定位置之前批量插入数据
void SLBatchInsert(SL* ps, int pos, const SLDataType* data, int count) 
{
	assert(ps && data && count > 0);
	assert(pos >= 0 && pos <= ps->size); // 确保插入位置合法

	// 1. 提前扩容,确保有足够空间容纳count个新元素
	SLCheckCapacity(ps, count);

	// 2. 从后往前移动元素,腾出插入位置
	// (需要移动size - pos个元素,每个元素向后移动count个位置)
	int i = 0;
	for (i = ps->size - 1; i >= pos; i--)
		ps->arr[i + count] = ps->arr[i];

	// 3. 批量插入新元素
	for (int i = 0; i < count; i++) 
		ps->arr[pos + i] = data[i];

	// 4. 更新元素总数
	ps->size += count;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
    const int arr[10] = { 11,12,13,14,15,16,17,18,19,20 };
    SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
    SLBatchInsert(&sl, 2, arr, 5);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
(三)删

删除顺序表末尾的有效数据,无需挪动元素,仅修改 size时间复杂度为 O (1) 。

1、尾删

(1)头文件

cpp 复制代码
//尾删 
void SLPopBack(SL* ps);

(2)实现文件

cpp 复制代码
void SLPopBack(SL* ps) 
{
    assert(ps);
    // 校验顺序表非空(size > 0),空表无法删除
    assert(ps->size > 0);
    // 关键操作:有效数据个数-1(原末尾数据变为"无效数据",后续插入会覆盖)
    ps->size--;
}

**逻辑说明:**现有数据[1,2,3,4](size=4),尾删后size=3------ 此时a[3]的4仍在内存中,但size=3表示 "仅前 3 个元素有效",后续插入(如尾插5)会覆盖a[3],无需手动 "删除" 物理数据

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPopBack(&sl);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
2、头删

删除顺序表头部的有效数据,需将后续元素整体前移一位,覆盖头部数据,时间复杂度 O (n)

(1)头文件

cpp 复制代码
void SLPopFront(SL* ps);

(2)实现文件

cpp 复制代码
void SLPopFront(SL* ps) {
    assert(ps);
    assert(ps->size > 0);  // 空表校验
    // 步骤1:后续元素整体前移(从第二个元素开始,覆盖前一个元素)
    int i = 0;
    for (i = 0; i < ps->size - 1; i++)
        ps->a[i] = ps->a[i + 1];
    // 步骤2:有效数据个数-1
    ps->size--;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
    SLPopFront(&sl);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
3、指定位置删除

删除指定下标 pos 的有效数据,pos 后续元素前移覆盖(头删、尾删的通用场景)。

(1)头文件

cpp 复制代码
//指定位置删除数据
void SLEraes(SL* ps, int pos);

(2)实现文件

cpp 复制代码
void SLErase(SL* ps, int pos) {
    assert(ps);
    assert(ps->size > 0);  // 空表校验
    // 校验pos合法性(0 ≤ pos < size,pos=size无有效数据)
    assert(pos >= 0 && pos < ps->size);
    
    // 步骤1:pos后续元素整体前移
    int i = 0;
    for (i = pos; i < ps->size - 1; i++) 
        ps->a[i] = ps->a[i + 1];
    
    // 步骤2:有效数据个数-1
    ps->size--;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLEraes(&sl, 0);
	SLEraes(&sl, 2);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
4、指定位置批量删除元素

删除指定下标 pos 及以后的 Number 个有效数据,pos+Number-1 的后续元素前移覆盖

(1)头文件

cpp 复制代码
//批量删除
void SLBatchDelete(SL *ps, int pos, int Number);

(2)实现文件

cpp 复制代码
// 批量删除
void SLBatchDelete(SL* ps, int pos, int Number)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	assert(Number > 0);
	assert(pos + Number <= ps->size);
	int i;
	for (i = pos; i < ps->size - Number; i++)
		ps->arr[i] = ps->arr[i + Number];
	ps->size -= Number;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
    SLBatchDelete(&sl, 1, 3);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
(四)改
1、修改指定位置数据

修改 pos 位置的数据,将其修改为 value。

(1)头文件

cpp 复制代码
void SLModify(SL* ps, int pos, SLDataType value);

(2)实现文件

cpp 复制代码
void SLModify(SL* ps, int pos, SLDataType value)
{
    // 检查指针有效性
    assert(ps);
    // 检查位置合法性:必须在有效元素范围内
    assert(pos >= 0 && pos < ps->size);
    
    // 直接通过索引修改数据
    ps->arr[pos] = value;
}

(3)测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLModify(&sl, 1, 5);
	SLModify(&sl, 2, 55);
    Print(&sl);
}

int main()
{
	test01();
	return 0;
}
(五)查
1、查找顺序表中是否存在对应数据

(1)头文件

cpp 复制代码
// 查找
int SLFind(SL* ps, SLDataType x);

(2)实现文件

在顺序表中查找,将数据 x 与顺序表中数据进行比较;找到了就返回下标,未找到,返回无效下标,如 -1 (下标无负数值,用于标识 "未找到")。

cpp 复制代码
// 查找
int SLFind(SL* ps, SLDataType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
			return i;
	}
	return -1;
}

**(3)**测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	
    int ret = SLFind(&sl, 11);
	if (ret < 0)
		printf("未找到\n");
	else
		printf("找到了\n");
}

int main()
{
	test01();
	return 0;
}
(六)销毁动态顺序表

释放动态顺序表在堆区申请的内存,避免内存泄漏(程序结束前必调用)。

1、头文件

cpp 复制代码
// 销毁
void SLDesTroy(SL* ps);

2、实现文件

cpp 复制代码
void SLDestroy(SL* ps) 
{
    assert(ps);
    // 仅当数组指针非空时释放(避免重复释放导致崩溃)
    if (ps->arr != NULL) 
        free(ps->arr);        // 释放堆区内存
    ps->arr = NULL;           // 指针置空,避免野指针(释放后指针仍指向原地址,需置空)
    ps->size = 0;             // 重置有效数据个数
    ps->capacity = 0;         // 重置容量
    
}

3、测试文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"SeqList.h"

void test01()
{
	SL sl;
	SLInit(&sl);
	
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
    
    SLDesTroy(&sl);
}

int main()
{
	test01();
	return 0;
}
(七)总结

里面代码涉及的一些思路其实是很简单的:

就是部分数据后移,把一块空间放出来,再插入数据,然后调整有效数据个数;

就是部分数据前移,把需要删除的数据覆盖掉,然后调整有效数据个数;

就是先遍历找到这个元素,再去覆盖即可;

就是是遍历找到这个元素。

五、顺序表的问题与反思
(一)核心缺陷
1、头部 / 中间操作效率低

(1)问题

头插、头删、中间插入、中间删除均需挪动大量元素,时间复杂度为 O (n)------ 若顺序表有 100 万数据,头插需挪动 100 万次,效率极低。

(2)场景限制

不适用于 "频繁操作头部或中间" 的场景(如实现队列、频繁插入日志等)。

2、扩容消耗大

扩容时需执行 "申请新空间→拷贝旧数据→释放旧空间" 三步操作,频繁扩容会严重降低程序效率。

3、空间浪费不可避免

(1)问题

2 倍扩容策略虽减少扩容次数,但会导致 "闲置空间"------ 如容量从 100 扩到 200,仅存 105 个数据,浪费 95 个空间;容量从 1 万扩到 2 万,仅存 1.1 万个数据,浪费 9000 个空间。

(2)本质

用 "部分空间浪费" 换 "更少的扩容次数",是一种 "权衡",但无法完全避免浪费。

(二) 改进方向:链表的引入

顺序表的缺陷可通过 "链表" 解决:

链表的头部 / 中间插入删除时间复杂度为 O (1)(无需挪动元素,仅修改指针指向)。

链表无需预分配空间,插入一个数据申请一个空间,无扩容消耗和空间浪费。

以上即为 一篇文章掌握"顺序表" 的全部内容,麻烦三连支持一下呗~

相关推荐
傻乐u兔8 小时前
C语言进阶————指针4
c语言·开发语言
历程里程碑8 小时前
Linux22 文件系统
linux·运维·c语言·开发语言·数据结构·c++·算法
2601_9491465315 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
ValhallaCoder16 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
月挽清风17 小时前
代码随想录第十五天
数据结构·算法·leetcode
知南x17 小时前
【Ascend C系列课程(高级)】(1) 算子调试+调优
c语言·开发语言
NEXT0618 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
2的n次方_19 小时前
Runtime 执行提交机制:NPU 硬件队列的管理与任务原子化下发
c语言·开发语言
凡人叶枫20 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发