《从数组到动态顺序表:数据结构与算法如何优化内存管理?》

🔥@晨非辰Tong:个人主页****

👀专栏:《C语言》** 、**《数据结构与算法》****

💪学习阶段:C语言、数据结构与算法初学者

⏳"人理解迭代,神理解递归。"

引言:
在上一篇中,我们初步认识了动态顺序表的基本结构和特性,了解了它如何通过动态扩容来解决固定数组的长度限制。今天,我们将继续深入探索顺序表的核心操作------增删查改的实现细节。从高效的头部插入到底层的内存管理,每一个操作背后都蕴含着数据结构设计的智慧,让我们一起来揭开这些关键技术的神秘面纱。

目录

四、动态顺序表的应用(续)

[4.3 在尾部删除数据](#4.3 在尾部删除数据)

[4.4 在头部删除数据](#4.4 在头部删除数据)

[4.5 在指定位置查找数据](#4.5 在指定位置查找数据)

[4.6 在指定位置插入](#4.6 在指定位置插入)

[4.7 在指定位置删除](#4.7 在指定位置删除)

[4.8 修改、销毁](#4.8 修改、销毁)


四、动态顺序表的应用(续)

4.3 在尾部删除数据

cpp 复制代码
SeqList.c文件
#include "SeqList.h"

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

//尾删_函数
void SLPopBack(SL* ps)
{
	assert(ps && ps->size);//断言
	//前移size
	ps->size--;
}

//输出_函数
void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

--进行顺序表尾部删除数据的前提是顺序表不能为空(不能传空参数NULL) ,得有数据才能删除------>也就是size不能为空

cpp 复制代码
test.c文件
#include "SeqList.h"

void test02()
{
	SL s2;//创建结构体变量
	SLInit(&s2);//初始化

    SLPushFront(&s2, 1);
	SLPushFront(&s2, 2);
	SLPushFront(&s2, 3);
	SLPrint(&s2);

	//尾删
	//上面先头插输入数据->321
	SLPopBack(&s2);
	SLPrint(&s2);//32
	SLPopBack(&s2);
	SLPrint(&s2);//3
}

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

4.4 在头部删除数据

cpp 复制代码
SeqList.c文件
#include "SeqList.h"

//头删_函数
void SLPopFront(SL* ps)
{
	assert(ps && ps->size);

	//循环移动
	for (int i = 0; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

//输出_函数
void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

--头删与尾删一样,顺序表不能为空。

cpp 复制代码
#include "SeqList.h"
void test02()
{
	SL s2;//创建结构体变量
	SLInit(&s2);//初始化

	//先头插输入数据->4321
	SLPushFront(&s2, 1);
	SLPushFront(&s2, 2);
	SLPushFront(&s2, 3);
	SLPushFront(&s2, 4);
	SLPrint(&s2);//4321

	//头删
	SLPopFront(&s2);
	SLPrint(&s2);//321
	SLPopFront(&s2);
	SLPrint(&s2);//21
	SLPopFront(&s2);
	SLPrint(&s2);//1

}

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

4.5 在指定位置查找数据

--在进行指定插入、指定删除操作,都需要先找到对应数据:

cpp 复制代码
SeqList.c文件
#include "SeqList.h"

//查找_函数
int SLFind(SL* ps, SLTDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			//找到了,返回下标
			return i;
		}
	}
	//未找到
	return -1;//返回任意不是下标的数值
}
cpp 复制代码
test.c文件
#include "SeqList.h"
void test02()
{
    //头插数据->4321
    SLPushFront(&s2, 1);
    SLPushFront(&s2, 2);
    SLPushFront(&s2, 3);
    SLPushFront(&s2, 4);
    SLPrint(&s2);//4321

    //查找
	//pos-下标
	int pos = SLFind(&s2, 4);
    if (pos >= 0)
    {
	    printf("找到了,下标是%d:\n", pos);
    }
    else
    {
    	printf("未找到!\n");
    }
    pos = SLFind(&s2, 3);
    if (pos >= 0)
    {
    	printf("找到了,下标是%d:\n", pos);
    }
    else
    {
    	printf("未找到!\n");
    }
    pos = SLFind(&s2, 2);
    if (pos >= 0)
    {
    	printf("找到了,下标是%d:\n", pos);
    }
    else
    {
	    printf("未找到!\n");
    }
    pos = SLFind(&s2, 0);
    if (pos >= 0)
    {
    	printf("找到了,下标是%d:\n", pos);
    }
    else
    {
    	printf("未找到!\n");
    }
}

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

4.6 在指定位置插入

--利用前面的查找函数

cpp 复制代码
SeqList.c文件_主要实现
#include "SeqList.h"

//指定位置之前插入_函数
void SLInsert(SL* ps, int pos, SLTDataType x)
{
	assert(ps);

	//0<= pos < ps->size
	assert(pos >= 0 && pos < ps->size);

	//插入前判断空间是否足够
	SLCheckCapacity(ps);

	//pos及之后数据向后挪动一位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

注意:元素在向后移动时,要注意空间大小是否足够。

cpp 复制代码
test.c文件
#include "SeqList.h"

void test02()
{
    //指定插入
    //头插数据->4321
    SLPushFront(&s2, 1);
    SLPushFront(&s2, 2);
    SLPushFront(&s2, 3);
    SLPushFront(&s2, 4);
    SLPrint(&s2);//4321

    //在数据3前插入
    int pos = SLFind(&s2, 3);
    SLInsert(&s2, pos, 100);
    SLPrint(&s2);
}

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

4.7 在指定位置删除

cpp 复制代码
SeqList.c文件_主要实现

#include "SeqList.h"

//指定位置删除_函数
void SLErase(SL* ps, int pos)
{
	assert(ps);

	//pos:[0,ps->size)
	assert(pos >= 0 && pos < ps->size);

	//将pos后的数据依次向前移动
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	//有效数据-1
	ps->size--;
}

指定位置删除逻辑与头删类似,只是多了要进行指定行为。

cpp 复制代码
test.c文件

#include "SeqList.h"

void test02()
{
    //测试_指定删除
	    //头插数据->4321
    SLPushFront(&s2, 1);
    SLPushFront(&s2, 2);
    SLPushFront(&s2, 3);
    SLPushFront(&s2, 4);
    SLPrint(&s2);//4321

	    //删除3
    int pos = SLFind(&s2, 3);//查找3的下标
    SLErase(&s2, pos);
    SLPrint(&s2);
}

int main()
{
    test02();
    rerurn 0;
}

4.8 修改、销毁

--修改

cpp 复制代码
SeqList.c文件
#include "SeqList.h"

//修改_函数
void SLModify(SL* ps, int pos, SLTDataType x)
{
	assert(ps);
	ps->arr[pos] = x;
}

test.c文件
#include "SeqList.h"

void test02()
{
    //测试_修改
		//头插数据->4321
	SLPushFront(&s2, 1);
	SLPushFront(&s2, 2);
	SLPushFront(&s2, 3);
	SLPushFront(&s2, 4);
	SLPrint(&s2);//4321
    
    //修改3
	int pos = SLFind(&s2, 3);
	SLModify(&s2, pos, 100);
	SLPrint(&s2);
}

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

--销毁

cpp 复制代码
SeqList.c文件
#include "SeqList.h"

//销毁_函数
void SLDestory(SL* ps)
{
	if(ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

free掉ps->arr,所有都恢复为初始化状态。


结语:

通过对动态顺序表的深入学习,我们理解了连续存储结构的优势与局限。从顺序表到链表,体现了数据结构设计中的"空间换时间"思想。掌握了这两种基础线性结构,就为我们学习更复杂的树、图等非线性结构打下了坚实基础。下篇文章,我们将开启链表之旅,感受指针连接的魅力。

相关推荐
二进制的Liao10 分钟前
【编程】脚本编写入门:从零到一的自动化之旅
数据库·python·算法·自动化·bash
自然数e39 分钟前
C++多线程【线程管控】之线程转移以及线程数量和ID
开发语言·c++·算法·多线程
摇滚侠1 小时前
Vue 项目实战《尚医通》,预约挂号的路由与静态搭建,笔记36
javascript·vue.js·笔记
三品吉他手会点灯1 小时前
STM32F103学习笔记-16-RCC(第4节)-使用 HSI 配置系统时钟并用 MCO 监控系统时钟
笔记·stm32·单片机·嵌入式硬件·学习
云在Steven1 小时前
在线确定性算法与自适应启发式在虚拟机动态整合中的竞争分析与性能优化
人工智能·算法·性能优化
2401_861277551 小时前
软考程序员2016年上半年二叉排序树案例题解答
c语言·决策树·链表
Lester_11012 小时前
嵌入式学习笔记 - 关于看门狗定时器的喂狗的操作放在中断还是放在主循环
笔记·单片机·学习
前进的李工2 小时前
LeetCode hot100:234 回文链表:快慢指针巧判回文链表
python·算法·leetcode·链表·快慢指针·回文链表
sin_hielo2 小时前
leetcode 3228
算法·leetcode
Chan162 小时前
Java 集合面试核心:ArrayList/LinkedList 底层数据结构,HashMap扩容机制详解
java·数据结构·spring boot·面试·intellij-idea