【数据结构】线性表----链表详解

数据结构—-链表详解

目录

文章目录

    • 链表的定义
    • 链表的构成
    • 链表的分类
      • 双向和单向
      • 带头和不带头
      • 循环和不循环
    • 链表的命名
    • 基本操作的实现
      • 初始化
      • 打印
      • 取值
      • 查找
      • 插入
      • 指定位置插入
      • 删除
      • 删除
      • 销毁
    • 部分其他链表的代码实现
      • 循环链表
      • 双向链表
    • 优点/缺点(对比顺序表)
      • 优点
      • 缺点
      • 缺点

链表的定义

前面我们介绍的顺序表,在逻辑结构和物理结构上都是线性、连续的关系,那么我们在篇尾的时候也提到了是否有一种顺序表,无需在物理结构上连续,从而达到更好存取的目的呢?今天它来了。

链表(LinkList)属于线性表的一种,以下是百度百科关于链表的定义:

在这里插入图片描述

总结下来,我们可以看出:

在结构上链表并不是像顺序表那样底层结构是数组,而是包含两个区域:数据域指针域。我们可以类比成火车,火车每一节车厢实际上是独立的,也就好比数据域,存储着各自的数据;但每一节车厢之间都会由一条链连接在一起,从而形成整个火车,链也就好比指针域,起到连接该车厢和指向下一车厢的作用。而实际上这样的存储结构也就是为什么链表的物理结构可以不连续,而逻辑结构依旧是连续的

这样的好处就是当我们需要对指定元素进行移动、替换、存取等操作的时候,我们可以一步到位,无需挪动数据,无需扩容,不会造成空间上的浪费——好比你火车更换车厢,总不可能让整个火车都为你而改动吧。

在这里插入图片描述

所以,如果要用一句话概括链表是什么,我们可以说:链表是一种线性数据结构,由结点组成,每个结点包含一个数据元素也就是数据域和指向下一个节点的指针也就是指针域。(叫法:结点或者节点都行)

在这里插入图片描述

联想:指针域的作用

实际上,在后续的数据结构中,还有很多类型的数据结构会使用到指针域这个概念,或者可以说是结点的概念。结点指地是组成数据元素的存储映像,往往指针就是指向结点的,鉴于它不受物理空间限制的优点,往往都会使用指针和结点来更高效率地实现数据结构。

链表的构成

数据域(data):存放实际数据

指针域(next):存放下一节点的首地址

结点:由数据域和指针域两部分信息组成的数据元素的存储映像

链表的分类

我们平常使用的最多的就是单链表——不带头单向不循环链表

既然有不带头,那么必然就有带头;既然有单向,那么必然就有双向;既然有不循环,那么必然就有循环

接下来针对这三个方向进行介绍。

双向和单向

单向链表:每个节点包含一个指向下一个节点的指针。单向链表只能从头节点开始遍历,无法从尾节点向前遍历。
双向链表:每个节点包含一个指向下一个节点和一个指向前一个节点的指针。双向链表可以从头节点或尾节点开始遍历,可以方便地在链表中间插入或删除节点。(向的描述与指针域的描述是一致的,单向只有一个指针域,而双向有两个)

可以通俗地理解为,单向为单行道,只能从头走到尾;双向为双行道,既可退又可进。

带头和不带头

带头链表:指第一个结点叫做头结点,不存储有效数据,只作为指引结点
不带头链表:指第一个结点不叫做头结点,就是第一个结点,存储有效数据

注意这里指的带头就是带有头结点的意思,头结点不存储任何数据,它仅仅用于指向第一个结点。优点是操作链表时统一处理,不需要特殊处理第一个节点,代码更加简洁清晰。缺点是需要额外的头节点,占用额外的空间。

循环和不循环

循环链表:最后一个节点的指针指向第一个节点,形成一个环状结构。循环链表可以从任意节点开始遍历,但需要注意避免出现死循环的情况。
不循环链表:最后一个节点的指针直接指向空,仅仅作为线性结构。

虽然链表种类之多,例如还有带有尾结点的链表等等,但在实际应用中只有两种:**单链表(不带头单向不循环链表)双向链表(带头双向循环链表)**使用得最多,因为它们两个的特性加起来即为所有特性,而其他类型的链表也就不难创建了。

链表的命名

typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;struct SListNode* next; 
}SLTNode

单链表

SLTDataType、ElemType、LinklistType等等(根据自己的偏好设定),以下都命名为SLTDataType

数据域

SLTDataType data; //保存结点数据

指针域(*

struct SListNode* next;//保存下一结点地址

操作

SLTPushBack//针对操作的命名一般在操作前缀添加SLT等代表其为链表的大写字母缩写

基本操作的实现

有关链表的操作,下方是一些举例


//链表的头插、尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);//链表的头删、尾删
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDesTroy(SLTNode** pphead);
//打印
void SLTPrint(SLTNode* phead);

接下来针对上述操作进行详细介绍。

初始化

即构造一个空链表

void SlistTest01() {//一般不会这样去创建链表,这里只是为了给大家展示链表的打印SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->data = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->data = 2;SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->data = 3;SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));node4->data = 4;
//当我们定义好了数据域之后,指针域应该如何定义呢?node1->next = node2;node2->next = node3;node3->next = node4;node4->next = NULL;
//像这样,让指针域指向该节点的下一节点,达到链接的目的
SLTNode* SLTBuyNode(SLTDataType x) {SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL) {//如果开辟失败的情况perror("malloc fail!");exit(1);}newnode->data = x;//开辟数据域newnode->next = NULL;//开辟指针域return newnode;
}

打印

在接下来承担显示的作用,将链表的结构可视化

void SLTPrint(SLTNode* phead) {SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;//使用next指针指向下一节点}printf("NULL\n");
}

取值

与顺序表的取值不一样,因为链表物理结构是不连续的,所以在链表中进行访问的时候不能直接随机访问,只能从首元素出发遍历进行访问。

Status SLTGet(LinkList L, int i, ElemType& e)//获取线性表L中的耨个数据元素的内容,通过变量e返回
{ p = L->next;                    //初始化,p指向首元结点,j = 1;                          //初始化,j为计数器while (p&&j < i)                //向后扫描,直到p指向的第i个元素或p为空{p = p->next;                //p指向下一个结点++j;}if (!p || j > i)                //第i个元素不存在,抛出异常return NULL;   e = p->data;                    //取第i个元素return OK;
}

查找

查找操作同顺序表类似,都是哦才能够首元结点开始,依次将元素与给定值进行比较。

//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x) {assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur) //等价于pcur != NULL{if (pcur->data == x) {return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

插入

插入分为尾插头插指定位置插入,而指定位置插入又分为指定位置之前和之后

尾插

//尾插
void SLTPushBack(SLTNode** pphead/*为什么是**二级指针?因为*pphead这个指针在传参时实际上还是传值而不是传地址,需要传这个指针的地址也就是使用二级指针*/, SLTDataType x) {assert(pphead);SLTNode* newnode = SLTBuyNode(x);//链表为空,新节点作为pheadif (*pphead == NULL) {*pphead = newnode;return;}//链表不为空,找尾节点SLTNode* ptail = *pphead;while (ptail->next)//并非ptial不能为空,而是ptail->next不能指向空{ptail = ptail->next;}//ptail就是尾节点ptail->next = newnode;
}

头插

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x) {assert(pphead);SLTNode* newnode = SLTBuyNode(x);//newnode *ppheadnewnode->next = *pphead;*pphead = newnode;
}

指定位置插入

之前

//在指定位置之前插入数据
//关键:找到前驱节点
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {assert(pphead);assert(pos);//要加上链表不能为空,如果链表都空了,必然找不到前驱节点assert(*pphead);SLTNode* newnode = SLTBuyNode(x);//pos刚好是头结点if (pos == *pphead) {//头插SLTPushFront(pphead, x);return;}//pos不是头结点的情况(如果不分情况讨论,那么prev就永远找不到pos)SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev -> newnode -> posprev->next = newnode;newnode->next = pos;
}

之后

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {assert(pos);SLTNode* newnode = SLTBuyNode(x);//错误操作:(顺序错误,导致pos->next不再指向下一节点//pos->next=newnode //newnode->next=pos->next//正确操作:newnode->next = pos->next;pos->next = newnode;
}

删除

删除又分为尾删头删指定结点删除以及指定位置后续结点删除

尾删

//尾删
void SLTPopBack(SLTNode** pphead) {assert(pphead);//第一个节点不能为空//链表不能为空assert(*pphead);//链表不为空if ((*pphead)->next == NULL)//如果只有一个节点 {free(*pphead);//直接释放*pphead = NULL;//置空return;}//如果有多个节点SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next)//不能指向空{prev = ptail;ptail = ptail->next;}prev->next = NULL;//销毁尾结点free(ptail);ptail = NULL;
}

头删

//头删
void SLTPopFront(SLTNode** pphead) {assert(pphead);//链表不能为空assert(*pphead);//让第二个节点成为新的头//把旧的头结点释放掉SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}

删除

删除又分为删除指定结点删除指定结点之后的所有结点

删除pos结点

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos) {assert(pphead);assert(*pphead);assert(pos);//pos刚好是头结点,没有前驱节点,执行头删if (*pphead == pos) {//头删SLTPopFront(pphead);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//找到了prev以及pos pos->next//先改变指向prev->next = pos->next;//再释放节点free(pos);pos = NULL;
}

删除pos之后的结点

//删除pos之后的节点,也就是pos->next->next
void SLTEraseAfter(SLTNode* pos) {assert(pos);//pos->next不能为空assert(pos->next);//pos  pos->next  pos->next->nextSLTNode* del = pos->next;//pos->next = pos->next->next;free(del);del = NULL;
}

销毁

//销毁链表
//注意链表的空间是不连续的,所以不能一次性销毁所有元素,只能使用循环一个元素一个元素销毁
void SListDesTroy(SLTNode** pphead) {assert(pphead);assert(*pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

以上操作都基于单链表

部分其他链表的代码实现

循环链表

在介绍链表的分类的时候,已经介绍了循环链表的基本定义,也就是链表的最后一个结点的指针域指向第一个结点,这样就形成了一个循环链表,如果用图像来表示关系的话,如下:
在这里插入图片描述

那么针对其代码的实现,实际上只需要让最后一个结点的指针域不指向空,而是指向第一个结点即可。

//关键代码
p=B->next->next;
B->next=A->next;
A->next=p;//指向头结点

循环链表的作用以及使用场景

  1. 约瑟夫问题:约瑟夫问题是一个经典的问题,即有n个人围成一圈,从第一个人开始报数,报到m的人出列,然后从出列的下一个人开始重新报数,直到所有人都出列。循环链表可以很好地模拟这个问题。
  2. 环形队列:循环链表可以用来实现环形队列,即队列的尾节点指向头节点,可以很方便地实现循环入队和出队操作。
  3. 循环播放列表:循环链表可以用来实现循环播放音乐列表或视频列表等功能。实际上循环这个概念,在生活中许多部分都有被使用到,而当它需要使用代码实现的时候,那么循环链表是较为容易实现的方案。

双向链表

在这里插入图片描述

双向链表的每个节点都包含两个指针,一个指向前一个节点,一个指向后一个节点。鉴于这个特点,它与单向链表不同的是,双向链表可以从头到尾或从尾到头遍历链表。

在双向链表中,通常有一个头节点和一个尾节点,它们分别指向链表的第一个节点和最后一个节点,可以方便地在头部或尾部进行插入或删除操作。

双向链表的操作普遍上比单向链表简单,因为它多了一个指针域所以操作的灵活性大大提高。

双向链表的作用以及使用场景

  1. 需要频繁在链表中间插入或删除节点的情况:双向链表可以在O(1)的时间复杂度内完成插入或删除操作,因此适合在需要频繁插入或删除节点的场景中使用。
  2. 需要双向遍历链表的情况:双向链表可以方便地从头到尾或从尾到头遍历链表,因此适合在需要双向遍历链表的场景中使用。
  3. 需要实现栈或队列的情况:双向链表可以方便地在两端进行插入或删除操作,因此适合用来实现栈或队列。
  4. 需要实现LRU缓存淘汰算法的情况:LRU缓存淘汰算法中经常需要删除最近最少使用的节点,双向链表可以方便地删除尾节点,因此适合用来实现LRU缓存淘汰算法。

优点/缺点(对比顺序表)

优点

1.存储空间充足,对内存利用率高

链表无需像顺序表那样预先分配空间,只要内存空间允许,链表中的元素个数就没有限制,那么这也可以反向说明链表对内存的利用率较高。

2.插入和删除的效率高

不像顺序表那样,在进行插入和删除的时候需要移动整个表,链表可以直接对单个元素进行插入和删除操作。

3.动态性和灵活性

链表的大小可以动态地调整,可以根据需要动态地插入或删除元素,不需要提前指定大小。

4.可以实现高级数据结构

实际上,在后续更高阶的数据结构中,许多结构都是基于链表的。链表可以实现栈、队列、哈希表等高级数据结构,具有很高的灵活性和扩展性。

缺点

1.存储密度小,单个结点有效数据占用空间小

我们发现,链表中的一个结点包含数据域和指针域,但是实际上真正存储了有效元素的只有数据域一部分,那么这就说明了其存储密度小(存储密度=数据元素本身占用的存储量/结点结构占用的存储量)

2.存取元素的效率低

链表不像顺序表那样,是随机存取结构,可以随时存取该位置上的元素;它属于顺序存取结构,只能通过遍历来实现存取元素操作。

3.每存一个数据都要开辟动态空间,增加了内存分配的开销,并可能导致内存碎片化。所以说,动态化既有利也有弊。

要内存空间允许,链表中的元素个数就没有限制,那么这也可以反向说明链表对内存的利用率较高。

2.插入和删除的效率高

不像顺序表那样,在进行插入和删除的时候需要移动整个表,链表可以直接对单个元素进行插入和删除操作。

3.动态性和灵活性

链表的大小可以动态地调整,可以根据需要动态地插入或删除元素,不需要提前指定大小。

4.可以实现高级数据结构

实际上,在后续更高阶的数据结构中,许多结构都是基于链表的。链表可以实现栈、队列、哈希表等高级数据结构,具有很高的灵活性和扩展性。

缺点

1.存储密度小,单个结点有效数据占用空间小

我们发现,链表中的一个结点包含数据域和指针域,但是实际上真正存储了有效元素的只有数据域一部分,那么这就说明了其存储密度小(存储密度=数据元素本身占用的存储量/结点结构占用的存储量)

2.存取元素的效率低

链表不像顺序表那样,是随机存取结构,可以随时存取该位置上的元素;它属于顺序存取结构,只能通过遍历来实现存取元素操作。

3.每存一个数据都要开辟动态空间,增加了内存分配的开销,并可能导致内存碎片化。所以说,动态化既有利也有弊。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/12021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于ssm学生档案管理系统论文

系统简介 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得到提升&#xff0c;而读书就是人们获得精神享受非常重要的途径。…

linux性能监控之free

free&#xff1a;linux系统自带命令&#xff0c;显示内存状态&#xff0c;命令查询来源于/proc/meminfo 文件 [rootk8s-master ~]# free --helpUsage:free [options]Options:-b, --bytes show output in bytes-k, --kilo show output in kilobytes-m, --mega…

flutter开发实战-compute将工作交由isolate处理

flutter开发实战-compute将工作交由isolate处理 最近查看flutter文档时候&#xff0c;看到了compute可以将工作交由isolate处理。通过 Flutter 提供的 compute() 方法将解析和转换的工作移交到一个后台 isolate 中。这个 compute() 函数可以在后台 isolate 中运行复杂的函数并…

利用阿里国际站和eBay平台销售数据提升产品销售额的有效方法。

作为全球知名的跨境电商平台&#xff0c;阿里国际站和eBay汇聚了众多跨境电商商家。为了提升业务效率和优化经营策略&#xff0c;商家们需要时刻关注自家店铺中产品的销售情况。通过深入了解销售数据&#xff0c;商家们能够准确把握店铺的经营状态&#xff0c;及时识别潜在问题…

Android XML的使用详解

一、布局文件&#xff1a; 在layout目录下&#xff0c;使用比较广泛&#xff1b;我们可以为应用定义两套或多套布局&#xff0c;例如&#xff1a;可以新建目录layout_land(代表手机横屏布局)&#xff0c;layout_port(代表手机竖屏布局)&#xff0c;系统会根据不同情况自动找到…

OpenAI 今日(北京时间 5 月 14 日凌晨两点)将发布的大更新,不是 GPT-5,也不是搜索引擎

&#x1f989; AI新闻 &#x1f680; OpenAI 今日&#xff08;5月13日&#xff09;将发布的大更新&#xff0c;不是 GPT-5&#xff0c;也不是搜索引擎 摘要&#xff1a;OpenAI 预计即将推出一款新的 AI 语音助手&#xff0c;该助手不仅可以进行语音和文字交流&#xff0c;还能…

Hashmap详细解析,原理及使用方法分析

hashmap基本原理 根据的hashCode值存储数据。由数组链表组成的&#xff0c;Entnr数组是HashMap的主体&#xff0c;数组中每个元素是一个单向链表。链表则是1/1解哈希冲突而存在的。在lava8中&#xff0c;使用红黑树优化。当链表长度大于8并且元素个数大于64&#xff0c;转为红…

常见加解密算法02 - RC4算法分析

RC4是一种广泛使用的流密码&#xff0c;它以其简洁和速度而闻名。区别于块密码&#xff0c;流密码特点在于按位或按字节来进行加密。 RC4由Ron Rivest在1987年设计&#xff0c;尽管它的命名看起来是第四版&#xff0c;实际上它是第一个对外发布的版本。 RC4算法的实施过程简洁…

centos7.8 迁移为 TencentOS Server 2.4(TK4) 报错解决

文章目录 一 问题二 解决三 注意 一 问题 CentOS 官方计划停止维护 CentOS Linux 项目&#xff0c;公司某台腾讯云的centos7.8服务器计划迁移为 TencentOS Server 2.4(TK4) 。在下载rpm包执行迁移命令后报错&#xff0c;场景还原如下。 首先 安装 Python 3 yum install -y p…

什么?免费使用GPT-4o?

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

[Algorithm][多源BFS][矩阵][飞地的数量][地图中的最高点][地图分析] + 多源BFS原理讲解 详细讲解

目录 0.原理讲解1.矩阵1.题目链接2.算法原理详解3.代码实现 2.飞地的数量1.题目链接2.算法原理详解3.代码实现 3.地图中的最高点1.题目链接2.算法原理详解3.代码实现 4.地图分析1.题目链接2.算法原理详解3.代码实现 0.原理讲解 注意&#xff1a;只要是用**BFS解决的最短路径问题…

Apache SeaTunnel在世界级银行巨头JP Morgan 内部的应用实践

作者系 JP Morgan 大数据工程师&#xff0c;文章内容来源于[DET 网络研讨会] 与 Apache SeaTunnel 的数据集成&#xff1a;https://www.youtube.com/watch?vln4mn6vLenc&#xff08;有兴趣的同学可以观看演讲&#xff09; 文章介绍了他任职期间使用 Apache SeaTunnel 优化数据…

基础模型的工具学习:综述

23年6月清华、人大、UIUC、纽约大学、北邮和CMU等的论文“Tool Learning with Foundation Models”。 人类拥有创造和利用工具的非凡能力&#xff0c;使他们能够克服物理限制并探索新领域。随着最近强大的基础模型的出现&#xff0c;人工智能系统有可能像人类一样熟练地使用工…

实践指南:如何将 SpringBoot 项目无缝部署到 Tomcat 服务器

序言 SpringBoot 是一个用来简化 Spring 应用初始搭建以及开发过程的框架&#xff0c;我们可以通过内置的 Tomcat 容器来轻松地运行我们的应用。但在生产环境中&#xff0c;我们可能需要将应用部署到独立的 Tomcat 服务器上。本文给大家介绍 SpringBoot 项目部署到独立 Tomcat…

三:哈希map day6 哈希表理论基础 ● 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数● 1. 两数之和

今日任务 ● 哈希表理论基础 ● 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数 ● 1. 两数之和 今日任务 242.有效的字母异位词 题目 大型概括&#xff1a;map 的使用 1.题目描述-->思路&#xff1a; 给出两个string s,t; …

Android Update Engine 分析(二十九)如何进行连续多个版本的升级?

本文为洛奇看世界(guyongqiangx)原创,转载请注明出处。 原文链接:https://blog.csdn.net/guyongqiangx/article/details/138849767 0. 背景 关于如何连续进行多个版本升级,这是一个很常见的需求,也是 OTA 讨论群里试不试就会讨论的一个话题。 例如,昨天一个小伙伴在群里…

a-auto-complete 请求后端数据做模糊查询,解决下拉框选择选不上,不回显的问题

a-auto-complete 请求后端数据做模糊查询&#xff0c;解决下拉框选择选不上&#xff0c;不回显的问题 记录一个a-auto-complete卡bug卡了两天&#xff0c;找不到哪里的问题下拉框选择选不上&#xff0c;不回显&#xff0c;最后终于解决了。 我还对下拉框显示的内容做了小调整。…

越来越真的Deepfake再次引起网安界的关注

当地时间5月6日&#xff0c;全球网络安全领域最受关注的年度盛会 RSAC 2024在美国旧金山隆重开幕。当天&#xff0c;被誉为“安全圈奥斯卡”的创新沙盒大赛也决出了冠军&#xff0c;Reality Defender凭借其创新性的深度伪造&#xff08;Deepfake&#xff09;检测平台摘得桂冠&a…

【漏洞复现】泛微OA E-Cology users.data信息泄露漏洞

漏洞描述&#xff1a; 泛微OA E-Cology是一款面向中大型组织的数字化办公产品&#xff0c;它基于全新的设计理念和管理思想&#xff0c;旨在为中大型组织创建一个全新的高效协同办公环境。泛微OA E-Cology users.data存在敏感信息泄露漏洞&#xff0c;攻击者利用此漏洞可以获取…

Excel 根据包含的关键词将指定列按关键词指定顺序排列

例题描述和简单分析 有 Excel 文件&#xff0c;数据如下所示&#xff1a; AB1Parent ColumnModifier (Column)2Jack lives in the villageRose3As mentioned by jackVillage4Rose already spoke to jack about last nightJack5Rose left the village6rose was their yesterda…