【王道数据结构笔记】顺序表的基本操作--删除(代码分析)

本文主要是介绍【王道数据结构笔记】顺序表的基本操作--删除(代码分析),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

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

【王道数据结构笔记】顺序表的基本操作--删除(代码分析)

  • 引言
    • 一 代码
    • 二 代码分析
    • 三 例子
    • 四 注意
  • 总结

在这里插入图片描述

引言

一 代码

bool ListDelete(Sqlist& L, int i, int &e)
{if (i <1 || i > L.length)return false;e = L.data[i - 1];for (int j = i; j < L.length; j++){L.data[j - 1] = L.data[j];}L.length--;return ture;
}

二 代码分析

步骤1:

if (i < 1 || i > L.length)return false;

分析:
这一步检查传入的索引i是否有效。如果i小于1或者大于列表L的当前长度L.length,则函数直接返回false,表示删除操作失败。这是因为数组和顺序表的索引通常是从0开始的,而列表的长度是指其包含的元素数量。

步骤2:

e = L.data[i - 1];

分析:
这步代码将顺序表中索引为i的元素的值赋给引用参数e。由于索引是从0开始的,因此实际访问数组L.data时使用i - 1作为索引。这样,e将保存被删除元素的值。

步骤3:

for (int j = i; j < L.length; j++)
{L.data[j - 1] = L.data[j];
}

这个循环是ListDelete函数中的一个关键部分,用于在顺序表L中删除索引为i的元素。循环的目的是将索引i及其之后的所有元素向前移动一个位置,从而覆盖掉索引i处的元素,实现删除的效果。

下面是循环的详细解释:

  1. 初始化部分 (int j = i;):

    • 这里定义了一个循环变量j,并将其初始化为ii是待删除元素的索引。循环将从i开始,意味着我们将从待删除元素之后的位置开始处理。
  2. 条件判断部分 (j < L.length;):

    • 这是循环继续执行的条件。只要j小于顺序表L的长度L.length,循环就会继续。这确保了循环会遍历到顺序表的最后一个元素,但不会超出数组边界。
  3. 循环体部分:

    • 在循环的每一次迭代中,都会执行循环体内的代码。这里,我们将L.data[j]的值赋给L.data[j - 1]。这实际上是将当前元素向前移动一个位置。
    • 由于数组索引是从0开始的,所以L.data[j - 1]实际上是指向j之前位置的元素的引用。通过不断地将后续元素的值赋给前一个位置,我们实现了删除索引为i的元素的效果。
    • 需要注意的是,这个操作不会改变顺序表的物理大小(即数组L.data的容量),而只是改变了顺序表中有效元素的数量(通过L.length来跟踪)。
  4. 迭代部分 (j++):

    • 在每次循环迭代结束时,j的值都会增加1。这确保了循环能够遍历顺序表中的每个元素,从i开始直到最后一个元素。

这个循环结束时,顺序表中索引为i的元素及其之后的所有元素都将向前移动了一个位置,原来的索引i处的元素就被“覆盖”掉了,从而实现了删除操作。最后,通过减少L.length的值,我们更新了顺序表的有效长度,以反映这次删除操作。

步骤4:

L.length--;

分析:
这步代码将顺序表L的长度减少1,因为我们已经从表中删除了一个元素。这是必要的步骤,以确保L.length正确地反映了顺序表中当前元素的数量。

步骤5:

return true;

分析:
如果代码执行到这里,说明删除操作成功完成。因此,函数返回true,表示删除操作成功。注意,这里应该修正拼写错误,将ture改为true

综上,整个ListDelete函数的目的是从顺序表L中删除索引为i的元素,并将被删除元素的值赋给引用参数e。如果索引i无效,函数返回false;否则,执行删除操作并返回true

三 例子

当然可以。假设我们有一个顺序表L,它的长度L.length是5,并且它存储了以下整数:

L.data: [10, 20, 30, 40, 50]

现在,如果我们想要删除索引为i = 2的元素(即值为30的元素),我们可以使用这个循环来实现。

在循环开始之前,顺序表的状态如下:

索引: 0  1  2  3  4
值:   10 20 30 40 50

循环开始时,j被初始化为i的值,即j = 2。循环的条件是j < L.length,即j < 5,所以循环会执行。

在第一次迭代中(j = 2):

  • L.data[j - 1]L.data[1](索引为1的元素,值为20)
  • L.data[j]L.data[2](索引为2的元素,值为30,即待删除的元素)

我们将L.data[2]的值(30)赋给L.data[1],此时顺序表变为:

索引: 0  1  2  3  4
值:   10 30 30 40 50

注意,现在索引1和2的位置都有相同的值30,但我们还未完成删除操作。

接着进行第二次迭代(j现在自增为3):

  • L.data[j - 1]L.data[2](现在是30)
  • L.data[j]L.data[3](值为40)

L.data[3]的值(40)赋给L.data[2],顺序表变为:

索引: 0  1  2  3  4
值:   10 30 40 40 50

再进行第三次迭代(j现在为4):

  • L.data[j - 1]L.data[3](现在是40)
  • L.data[j]L.data[4](值为50)

L.data[4]的值(50)赋给L.data[3],顺序表变为:

索引: 0  1  2  3  4
值:   10 30 40 50 50

此时,由于j(现在是4)不再小于L.length(5),循环终止。

最后,我们需要减少顺序表的长度L.length以反映已经删除了一个元素:

L.length--; // 现在L.length变为4

更新后的顺序表状态为:

索引: 0  1  2  3
值:   10 30 40 50

注意,索引4及其之后的位置现在包含了未定义的值(可能是之前存储的旧数据),但在我们的顺序表逻辑中,我们不再考虑这些位置,因为L.length已经更新为4,表示只有前4个元素是有效的。这样,我们就成功地从顺序表中删除了索引为2的元素。

四 注意

在顺序表中,我们不能直接删除要删除的元素,而是要通过将后续元素向前覆盖的方式来模拟删除操作,主要出于以下几个原因:

  1. 连续性:顺序表通常基于数组实现,数组中的元素在内存中是连续存储的。因此,如果直接删除数组中的某个元素,而不做任何处理,那么原本存储在该元素位置之后的数据将会向前移动填补空白,导致数据的连续性被破坏。

  2. 内存管理:直接删除数组中的元素并不意味着释放了相应的内存空间。在C++等语言中,数组的大小是在创建时确定的,并且通常不能在运行时改变。即使我们“逻辑上”删除了某个元素,数组所占用的内存空间仍然保持不变。

  3. 效率:通过将后续元素向前覆盖的方式模拟删除操作,可以避免移动大量数据。如果我们直接删除一个元素,那么所有位于该元素之后的元素都需要向后移动一位以填补空白,这将是一个O(n)的操作,其中n是顺序表的长度。而通过覆盖的方式,我们只需要将后续的元素逐个向前移动,直到覆盖掉要删除的元素,这是一个O(k)的操作,其中k是要删除元素之后的元素数量。

  4. 简化操作:通过覆盖的方式,我们实际上是在“覆盖”掉要删除的元素,而不是真正地从内存中移除它。这种方式简化了删除操作的实现,因为我们不需要处理内存分配和释放的复杂性。同时,由于顺序表的长度L.length会相应减少,我们在逻辑上仍然认为该元素已经被删除。

因此,尽管我们不能直接从顺序表中删除一个元素,但通过覆盖后续元素的方式,我们可以在逻辑上实现删除的效果,同时保持顺序表的连续性和内存空间的有效利用。需要注意的是,这种删除操作并不会释放任何内存,如果顺序表的大小成为了问题,那么可能需要考虑使用动态数组(如std::vector在C++中)或其他数据结构来更灵活地管理元素的增删操作。

总结

这篇文章到这里就结束了

谢谢大家的阅读!

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

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

在这里插入图片描述

在这里插入图片描述

这篇关于【王道数据结构笔记】顺序表的基本操作--删除(代码分析)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/922685

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

macOS无效Launchpad图标轻松删除的4 种实用方法

《macOS无效Launchpad图标轻松删除的4种实用方法》mac中不在appstore上下载的应用经常在删除后它的图标还残留在launchpad中,并且长按图标也不会出现删除符号,下面解决这个问... 在 MACOS 上,Launchpad(也就是「启动台」)是一个便捷的 App 启动工具。但有时候,应

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3