【数据结构】顺序表的实现

在前面,我们把C语言的全部基础知识学完了,现在正式开始我们的顺序表!!

顺序表的实现

  • 1.顺序表是什么呢?
  • 2顺序表的实现
    • 2.1顺序表变量的命名规则
    • 2.2创建结构体
    • 2.3初始化结构体
    • 2.4打印顺序表
      • SeqList.h文件
      • SeqList.c文件
      • test.c文件
    • 2.5空间大小判断
    • 2.6头插和尾插
      • 2.6.1尾插的实现
      • 2.6.2头插的实现
    • 2.7关键知识讲解
      • 2.7.1头插和尾插
    • 2.8尾删和头删
    • 2.8.1尾删的实现
    • 2.8.2头删的实现
    • 2.9关键知识讲解
    • 2.10任意插入和任意删除和查找
      • 2.10.1任意插入
      • 2.10.2任意删除
      • 2.10.3元素查找
    • 2.11关键知识总结
    • 2.12销毁申请的空间
  • 2.13完整代码1
    • SeqList.h头文件
    • SeqList.c文件
    • test.c文件
  • 2.14完整代码2
    • SeqList.h文件
    • SeqList.c文件
    • test.c文件
  • 3.顺序表的作用与运用场景
    • 3.1顺序表的核心作用
    • 3.2顺序表的典型运用场景

1.顺序表是什么呢?


顺序表就像"规整的货架",数据排得整整齐齐,取数据快,但调整开头或中间的货物就很麻烦。它的核心价值在于随机访问高效、实现简单,适合数据量不算大、以尾插/尾删个随机访问为主的场景。

掌握顺序表是基础中的基础,后续学数据结构与算法、应对专升本考上和编程竞赛,都会经常和它打交道

2顺序表的实现


2.1顺序表变量的命名规则


顺序表经常进行以下命名,可根据自己的命名习惯来命名

  • 顺序表:SeqList 简化:SL
  • 头插:SLpushFront
  • 头删:SLPopFront
  • 尾插:SLPushBack
  • 尾删:SLPopBack
  • 空间大小判断:SLCheckCapacity
  • 打印顺序表:SLPrint
  • 销毁空间:SLDestory

2.2创建结构体


需要在头文件中创建结构体,并将结构体初始化

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

typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
	int* arr;
	int size;//有效数据个数
	int capecity;//空间大小
}SL;
  • 用typedef将结构体缩写为SL,这方便后续写简洁的代码
  • 上面将int修改为SLDataType,方便后续的切换成其他类型,只需要把int类型改成其他类型

2.3初始化结构体


刚开始,需要把结构体中的任何数据初始化为0,然后在后期进行赋值处理

2.4打印顺序表


当实现完前面顺序表的核心内容,剩下的就是打印顺序表和销毁顺序表了,我们先看如何打印顺序表

C 复制代码
//打印顺序表
void SLPrint(SL ps);
C 复制代码
//打印顺序表
void SLPrint(SL sp)
{
	for (int i = 0; i < sp.size; i++)
	{
		printf("%d ", sp.arr[i]);
	}
	printf("\n");
}
C 复制代码
//打印
SLPrint(sl);

SeqList.h文件

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

typedef int SLDataType;//方便后续类型的替换
//动态顺序表
typedef struct SeqList
{
	int* arr;
	int size;//有效数据个数
	int capecity;//空间大小
}SL;

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

SeqList.c文件

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

//顺序表的初始化
void SLInit(SL* s)
{
	s->arr = NULL;
	s->size = s->capecity = 0;
}

test.c文件

C 复制代码
#include"SeqList.h"
void SLTest01()
{
	SL sl;
	//初始化
	SLInit(&sl);
}

int main()
{
	SLTest01();
	return 0;
}

2.5空间大小判断


利用动态内存分配,就要合理的管理内存大小,当内存不够时去申请合理的大小,当内存过大时,就调整内存。

C 复制代码
//判断内存够不够
void SLCheckCapacity(SL* ps);
C 复制代码
//判断内存够不够
void SLCheckCapacity(SL* ps)
{
	if (ps->capecity == ps->size)
	{
		//第一种情况,都为0
		//用三目运算符
		int NewCapecity = ps->capecity == 0 ? 4 : ps->capecity * 2 * sizeof(SLDataType);

		//第二种情况,空间不够
		//开辟新空间,tmp来接受
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapecity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capecity = NewCapecity;
	}
}
  • 空间是顺序表的核心,空间主要分为两种情况:一种是没有空间,另一种是空间不够
  • 第一种:用三目运算符判断,若没有空间,则给4个字节。若有空间,将字节乘2
  • 第二种:当内存不够时,开辟新的空间
  • 当上面两种情况完成后,用新的数据代替旧的数据

2.6头插和尾插

2.6.1尾插的实现


先把尾插的代码掌握好,后面的头插、头删、尾删就很好理解了

C 复制代码
//尾插
void SLPushBack(SL* ps, SLDataType x);
C 复制代码
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//尾插入
	ps->arr[ps->size++] = x;
}
C 复制代码
//尾插
SLPushBack(&sl, 1);
  • 在写尾插时,每次输进一个新元素,size也要往后移一位

2.6.2头插的实现


相对于尾插,头插就相对简单很多了。也就是把元素往后移一位,然后再把新的元素插入开头。

C 复制代码
//头插
void SLpushFront(SL* ps, SLDataType x);
C 复制代码
//头插
void SLpushFront(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//往后各挪一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}
C 复制代码
//头插
SLpushFront(&sl, 5);

2.7关键知识讲解


2.7.1头插和尾插

  1. 动态内存核心:用realloc扩容,首次扩充到4个元素,之后翻倍,效率更高,避免频繁扩容
  2. 头插注意点:必须先把已有元素往后挪,从最后一个元素开始挪,不然会覆盖数据
  3. 内存安全:用完顺序表一点要释放内存,不然内存会泄漏
  4. 断言用法:assert(sp)防止传空指针,调试阶段很有用,正式项目可根据需求关闭

2.8尾删和头删

2.8.1尾删的实现


尾删就是把指向数组末尾的size,往前挪移了一位,将后面打印不到的舍弃

C 复制代码
//删除最后一个元素
void SLPopBack(SL* ps);
C 复制代码
//删除最后一个元素
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	//有效元素减1,后面的空间相当于"废弃"
	ps->size--;
}
C 复制代码
//删除最后一个元素
SLPopBack(&sl);

2.8.2头删的实现


头删就是将所有元素往前挪移一位

C 复制代码
//删除第一个元素
void SLPopFront(SL* ps);
C 复制代码
//删除第一个元素
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);//防止空表删除,直接报错提醒!

	//从第二个元素开始,依次往前挪移一位,覆盖第一个元素
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//有效元素减1
	ps->size--;
}
C 复制代码
//删除第一个元素
SLPopFront(&sl);

2.9关键知识讲解


  1. 尾删为啥这么简单?
    尾删不用动数据!只要把 size 减1,原来的尾元素就不在"有效元素范围"内了,下次插入会直接覆盖,效率超高!
  2. 头删的坑千万别踩!
    头删必须从前往后挪元素,要是从后往前挪,会把前面的有效数据覆盖掉!比如先挪 data[0] = data[1] ,再挪 data[1] = data[2] ,依次类推。
  3. 空表删除防护!
    用 assert(sl->size > 0) 防止用户在空表时执行删操作,新手很容易忽略这个场景,一删就崩!实际项目中也可以用返回值提示错误,不用断言直接退出。
  4. 内存要不要释放?
    这里不用手动释放删元素的内存!因为动态内存是按"容量"管理的, size 只是标记有效元素,扩容时才会调整内存大小,频繁释放小块内存反而效率低。

2.10任意插入和任意删除和查找


顺序表本质就是数组套了层"管理壳",就是数组的连续空间

2.10.1任意插入


插入的核心逻辑就一句话:先把插入位置后面的数据"往后挪一位",再把新数据塞进去。但必须先检查两件事:表满了没?位置合法不?

C 复制代码
//插入指定位置
void SLInsert(SL* ps, int pos, SLDataType x);
C 复制代码
//随机插入元素
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos <= ps->size && pos >= 0);
	//插入数据:空间够不够
	SLCheckCapacity(ps);
	//让pos及之后的数据整体往后挪移1位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[pos + 1] = arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}
C 复制代码
//测试指定位置之前插入数据
SLInsert(&sl, 0, 99);
SLPrint(sl);//99 1 2 3 4

2.10.2任意删除


删除和插入反过来:先把要删的数据"记下来",再把后面的数据"往前挪一位",覆盖掉要删除的。同样要先检查:表空了没?位置合法不?

C 复制代码
//删除指定位置
void SLErase(SL* ps, int pos);
C 复制代码
//删除指定位置
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	SLCheckCapacity(ps);

	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//arr[size - 2] = arr[size - 1]
	}
	ps->size--;
}
C 复制代码
//测试指定位置删除
SLErase(&sl, 0);
SLPrint(sl);//1 2 3 4

2.10.3元素查找


查找就简单了,从第一个数据开始逐个对比,找到就返回位置,没找到就说找不到。顺序表时"线性查找",效率一般,但是胜在简单。

C 复制代码
//查找
int SLFind(SL* ps, SLDataType x);
C 复制代码
//查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->arr[i])
		{
			//找到了
			return i;
		}
	}
	//没有找到
	return -1;
}
C 复制代码
//测试顺序表的查找
int find = SLFind(&sl, 4);
if (find < 0)
{
	printf("没有找到!\n");
}
else
{
	printf("找到了!下标为%d!!", find);
}

SLDestory(&sl);

2.11关键知识总结

  1. 核心就一个"挪"字
  2. 边界检查是"保命符"
  3. 下标别把'1'和'0'搞混

2.12销毁申请的空间


前面我们用realloc申请了我们想要的空间,当我们用完时,要记得把内存还回去

C 复制代码
//销毁地址
void SLDestory(SL* ps);
C 复制代码
//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capecity = 0;
}
C 复制代码
//销毁地址
SLDestory(&sl);

2.13完整代码1

SeqList.h头文件

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

//定义顺序表的结构

//#define N 100
//
////静态顺序表
//struct SeqList
//{
//	int arr[N];
//	int size;//有效数组个数
//};

typedef int SLDataType;//方便后续类型的替换
//动态顺序表
typedef struct SeqList
{
	int* arr;
	int size;//有效数据个数
	int capecity;//空间大小
}SL;

//typedef struct SeqList SL;

//判断内存够不够
void SLCheckCapacity(SL* ps);

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

//插入数据
void SLPushBack(SL* ps, SLDataType x);

//头插
void SLpushFront(SL* ps, SLDataType x);

//销毁地址
void SLDestory(SL* ps);

//打印顺序表
void SLPrint(SL ps);

//删除第一个元素
void SLPopFront(SL* ps);


//删除最后一个元素
void SLPopBack(SL* ps);

SeqList.c文件

C 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

//顺序表的初始化
void SLInit(SL* s)
{
	s->arr = NULL;
	s->size = s->capecity = 0;
}

//判断内存够不够
void SLCheckCapacity(SL* ps)
{
	if (ps->capecity == ps->size)
	{
		//第一种情况,都为0
		//用三目运算符
		int NewCapecity = ps->capecity == 0 ? 4 : ps->capecity * 2 * sizeof(SLDataType);

		//第二种情况,空间不够
		//开辟新空间,tmp来接受
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapecity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capecity = NewCapecity;
	}
}

//头插
void SLpushFront(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//往后各挪一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

//删除第一个元素
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);//防止空表删除,直接报错提醒!

	//从第二个元素开始,依次往前挪移一位,覆盖第一个元素
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//有效元素减1
	ps->size--;
}


//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//尾插入
	ps->arr[ps->size++] = x;
}

//删除最后一个元素
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	//有效元素减1,后面的空间相当于"废弃"
	ps->size--;
}

//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capecity = 0;
}

//打印顺序表
void SLPrint(SL sp)
{
	for (int i = 0; i < sp.size; i++)
	{
		printf("%d ", sp.arr[i]);
	}
	printf("\n");
}

test.c文件

C 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

void SLTest01()
{
	SL sl;
	//初始化
	SLInit(&sl);

	//尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//打印
	SLPrint(sl);

	//头插
	SLpushFront(&sl, 5);
	SLpushFront(&sl, 6);

	//打印
	SLPrint(sl);
	


	//删除最后一个元素
	SLPopBack(&sl);
	SLPrint(sl);

	//删除第一个元素
	SLPopFront(&sl);
	SLPrint(sl);

	//销毁地址
	SLDestory(&sl);
}

int main()
{
	SLTest01();
	return 0;
}

2.14完整代码2


SeqList.h文件

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

//定义顺序表的结构

//#define N 100
//
////静态顺序表
//struct SeqList
//{
//	int arr[N];
//	int size;//有效数组个数
//};

typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
	int* arr;
	int size;//有效数据个数
	int capecity;//空间大小
}SL;

//typedef struct SeqList SL;

//判断内存够不够
void SLCheckCapacity(SL* ps);

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

//尾插
void SLPushBack(SL* ps, SLDataType x);

//头插
void SLPushFront(SL* ps, SLDataType x);

//销毁地址
void SLDestory(SL* ps);

//打印顺序表
void SLPrint(SL ps);

//删除第一个元素
void SLPopFront(SL* ps);

//插入指定位置
void SLInsert(SL* ps, int pos, SLDataType x);

//删除指定位置
void SLErase(SL* ps, int pos);

//删除最后一个元素
void SLPopBack(SL* ps);

//查找
int SLFind(SL* ps, SLDataType x);

SeqList.c文件

C 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

//顺序表的初始化
void SLInit(SL* s)
{
	s->arr = NULL;
	s->size = s->capecity = 0;
}

//判断内存够不够
void SLCheckCapacity(SL* ps)
{
	if (ps->capecity == ps->size)
	{
		//第一种情况,都为0
		//用三目运算符
		int NewCapecity = ps->capecity == 0 ? 4 : ps->capecity * 2 * sizeof(SLDataType);

		//第二种情况,空间不够
		//开辟新空间,tmp来接受
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapecity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//空间申请成功
		ps->arr = tmp;
		ps->capecity = NewCapecity;
	}
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//往后各挪一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

//删除第一个元素
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);//防止空表删除,直接报错提醒!

	//从第二个元素开始,依次往前挪移一位,覆盖第一个元素
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//有效元素减1
	ps->size--;
}


//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	//判断是否为空指针
	assert(ps);

	//判断内存够不够
	SLCheckCapacity(ps);

	//尾插入
	ps->arr[ps->size++] = x;
}

//删除最后一个元素
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	//有效元素减1,后面的空间相当于"废弃"
	ps->size--;
}

//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capecity = 0;
}

//打印顺序表
void SLPrint(SL sp)
{
	for (int i = 0; i < sp.size; i++)
	{
		printf("%d ", sp.arr[i]);
	}
	printf("\n");
}

//随机插入元素
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos <= ps->size && pos >= 0);
	//插入数据:空间够不够
	SLCheckCapacity(ps);
	//让pos及之后的数据整体往后挪移1位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[pos + 1] = arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}

//删除指定位置
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	SLCheckCapacity(ps);

	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//arr[size - 2] = arr[size - 1]
	}
	ps->size--;
}

//查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->arr[i])
		{
			//找到了
			return i;
		}
	}
	//没有找到
	return -1;
}

test.c文件

C 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

#if 0
void SLTest01()
{
	SL sl;
	//初始化
	SLInit(&sl);

	//尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//打印
	SLPrint(sl);//1234

	//头插
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	//打印
	SLPrint(sl);//561234
	


	//删除最后一个元素
	SLPopBack(&sl);
	SLPrint(sl);//56123

	//删除第一个元素
	SLPopFront(&sl);
	SLPrint(sl);//6123

	//销毁地址
	SLDestory(&sl);
}
#endif

void SLTest02()
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPrint(sl);//1 2 3 4

	//测试指定位置之前插入数据
	SLInsert(&sl, 0, 99);
	SLPrint(sl);//99 1 2 3 4

	SLInsert(&sl, sl.size, 88);
	SLPrint(sl);//99 1 2 3 4 88 

	SLInsert(&sl, 2, 77);
	SLPrint(sl);//99 1 77 2 3 4 88

	//测试指定位置删除
	SLErase(&sl, 0);
	SLPrint(sl);//1 77 2 3 4 88

	//测试顺序表的查找
	int find = SLFind(&sl, 4);
	if (find < 0)
	{
		printf("没有找到!\n");
	}
	else
	{
		printf("找到了!下标为%d!!", find);
	}

	SLDestory(&sl);
}

int main()
{
	//SLTest01();
	SLTest02();
	return 0;
}

3.顺序表的作用与运用场景


3.1顺序表的核心作用


  1. 动态管理数据:相比固定大小的数组,顺序表能通过扩容自动调整存储空间,解决了数组"存少了不够用、存多了浪费"的痛点,比如存储用户输入的不确定数量的数据。
  2. 高效随机访问:因为数据存在连续的动态数组里,能通过下标直接访问元素(时间复杂度 O(1)),比如要快速获取第 n 个元素,直接sl->data[n]就能搞定,这是它的核心优势。
  3. 简化数据操作:把尾插、头删等常用操作封装成函数,后续使用时直接调用,不用重复写代码,比如编程竞赛中频繁需要添加/删除元素时,能节省大量时间。

3.2顺序表的典型运用场景


  1. 编程竞赛中的基础场景
  • 简单数据存储与处理:比如题目要求读取一组整数,进行排序、去重、统计频率等操作,顺序表能轻松承载数据,配合算法完成需求。
  • 模拟队列(尾插+头删):虽然顺序表头删效率不高(O(n)),但在数据量不大的竞赛题目中,用顺序表模拟简单队列能快速实现功能,不用复杂的数据结构。
  1. 实际开发中的应用
  • 底层数据结构支撑:很多高级数据结构的底层会用到顺序表,比如栈(用尾插和尾删实现,效率 O(1))、动态数组(比如 C++ 的 vector、Java 的 ArrayList 底层逻辑和顺序表类似)。
  • 数据缓存场景:比如系统中需要缓存最近访问的 100 条数据,用顺序表存储,满了之后删除头部元素(最早访问的),尾部添加新元素,简单高效。
  • 批量数据处理:比如读取文件中的批量数据(如学生成绩、商品信息),先存入顺序表,再进行筛选、排序、汇总等操作,方便后续处理。
  1. 不适合用顺序表的场景(避坑提醒!)
  • 频繁头插/头删且数据量大:头插/头删需要移动所有元素(O(n) 时间复杂度),如果数据量达到 10 万级,效率会极低,此时应该用链表。
  • 数据元素大小不固定:顺序表适合存储相同类型的固定大小元素,比如 int、char,如果是结构体且大小动态变化,用顺序表会很麻烦。
  • 需要频繁插入/删除到中间位置:比如在元素中间频繁添加或删除数据,每次都要移动大量元素,效率远不如链表。
相关推荐
一语长情3 小时前
多线程同步实战指南:Python、Java与Go的等待之道
后端·面试·架构
GilgameshJSS4 小时前
STM32H743-ARM例程31-CAN
c语言·arm开发·stm32·单片机·嵌入式硬件
信奥卷王4 小时前
[GESP202506 五级] 奖品兑换
数据结构·算法
泡沫冰@4 小时前
数据结构(11)
数据结构
摇滚侠4 小时前
Spring Boot3零基础教程,RedisTemplate 定制化,笔记70
spring boot·笔记·后端
刘一说4 小时前
深入浅出 Spring Boot 自动配置(Auto-Configuration):原理、机制与最佳实践
java·spring boot·后端
程序员小假4 小时前
我们来说一说什么是联合索引最左匹配原则?
java·后端
豆苗学前端4 小时前
企业级用户登录Token存储最佳实践,吊打面试官
前端·javascript·后端
奶茶树4 小时前
【数据结构】二叉搜索树
数据结构·算法