【开卷数据结构 】 顺序表与链表(一)

简介: 【开卷数据结构 】 顺序表与链表

🌺线性表的定义


线性表:线性表是由n ( n≥0 ) 个数据特性相同的元素构成的有限序列。n是线性表的表长,当 n=0时线性表是一个空表。若用 L 来命名线性表,则其一般表达式为

L  =  (a1,a2,...... ,an)


图像:image.png


a1是唯一的【第一个】数据元素,又称表头元素。an是唯一的【最后一个】数据元素,又称表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后续。


以上就是线性表的逻辑特性,这种线性有序的逻辑结构正是线性表名字的由来。


🌺线性表的特点


从线性表的图像和表达式中可以很明显的看出线性表的特点,那就是


存在唯一的“第一元素”,没有前驱;

除第一元素外,其它元素均有唯一的"前驱"。

存在唯一的“最后元素”,没有后继;

除最后元素外,其它元素均有唯一的"后继";


🌺 顺序表


      线性表的顺序存储又称为顺序表,它用一组地址连续的存储单元依次存放线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。


       第1个元素存储在线性表的起始位置,第i个元素的存储位置后面紧接着存储的是第i+1个元素。当我们知道顺序表的第一位元素的地址时,就很容易就可以推理出剩余元素的地址,因此顺序表是一种随机存取的存储结构。

顺序表的特点:表中元素的逻辑顺序与其物理顺序相同

假设线性表L存储的起始位置是 LOC(A),sizeof(ElemType)是每个数组元素所占用的存储空间的大小,那么线性表L的顺序存储如下图所示。


线性表的顺序存储结构

数组下标 顺序表 内存地址
0 a1 LOC(A)
1 a2 LOC(A)+sizeof(ElemType)
... ... ...
i-1 ai LOC(A)+(i-1)*sizeof(ElemType)
... ... ...
n-1 an LOC(A)+(n-1)*sizeof(ElemType)
... ... ...
MaxSize-1 ...

LOC(A)+(MaxSize-1)*sizeof(ElemType)


       每个数据元素的存储位置都和线性表的起始位置相差一个和该数据元素的位序成正比的常数。因此,线性表中的任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构。


看到这里不知道大家有没有感觉很熟悉,似曾相识。没错,我们的老朋友——数组也是一种随机存取的存储结构。因此,通常用高级程序设计语言中的数组来描述线性表的顺序存储结构。


注意:线性表中元素的位序是从【1】开始的,而数组中元素的下标是从【0】开始的.


🌷实现原理


首先我们需要定义一下顺序表的长度,也就是最大有多少个元素。我们采用【define】来确定长度,因为使用【define】可以更方便的进行对长度的修改。

#difine        MAXSIZE        ****        //最大长度


下面,我们用结构体,定义一个新的数据类型。


typedef struct
{   ElemType *elem;  //存储空间基地址    
  int length;     //当前长度
}SqList;            //结构类型为SqList


第一数据域:


在结构体中包含了两个数据域,第一个数据域是elem,很明显,elem是一个指针域,它指向了ElemType类型(在真正实现时,是本来的数据类型)

ElemType:它是element type(“元素的类型”)的简化体


【ElemType *elem】代表着连续空间的首地址,也称基地址,elem类似于数组的名字,它也可以当作数组名字使用。


第二数据域:


第二数据域length表示线性表的数据元素的长度


🌷顺序表的初始化


顺序表的初始化就是建立一个新的空的顺序表


🔺实现原理


1️⃣为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。

2️⃣将表的当前长度设为0。


💬 代码演示


Status InitList(SqList &L)
{//构造一个空的顺序表L 
  L.elem=new ElemType[MAXSIZE];//为顺序表分配一个大小为MAXSIZE的数组空间  
  if(!L. elem) exit(OVERFLOW);//存储分配失败退出 
  L.length=0;                        //空表长度为0 
  return OK; 
}


🌷顺序表的取值


🔺实现原理

1️⃣判断指定位置是否合理,若不合理,则返回 ERROR。

2️⃣若i值合理,则将第i个元素L.elem[i-1]赋值给参数e,通过e返回第i个数据元素的传值。


💬 代码演示


Status GetElem(SqListL, int i,ElemType &e)
{
  if(i<1||i>L. length) //判断是否合理 
  return ERROR;e=L. elem[i-1];    //elem[i-1]存储第i个数据元素 
  return OK;
}


🌷顺序表的查找


🔺实现原理

1️⃣从第一个元素开始,一个一个与e相比较,若查找成功,返回该元素在表中的位置序号。

2️⃣若查找失败,则返回0。


💬 代码演示


int LocateElem(SqList L,ElemType e)
{//在顺序表1中查找值为e的数据元素,返回其序号
  for(i=0;i<L. length;i++)
  {
  if(L. elem[i]==e) 
    return i+1;
  }
  return 0; 
}


🌷顺序表的插入


线性表的插入操作是指在表的第i个位置插入一个新的数据元素e,使得长度为n的线性表变成长度为n+1的线性表。


❓那么问题来了,应该怎么实现呢?


在线性表的顺序存储结构中,由于逻辑上相邻的数据元素在物理位置上也是相邻的,为了在线性表的第i个位置上插入一个数据元素,则需将第i个至最后一个数据元素依次向后移动一个位置。


🔺实现原理


1️⃣判断插入位置i是否合法(i值的合法范围是1≤i≤n+1),若不合法则返回ERROR。


2️⃣判断顺序表的存储空间是否已满,若满则返回ERROR。


3️⃣将第n个至第i个位置的元素依次向后移动一个位置,空出第i个位置(i=n+1时无需移动)


4️⃣将要插入的新元素e放入第i个位置。


5️⃣表长加一。


🔑空间状态

d411fb3b4b438cdcc709c85d4c1e8f14_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_19,color_FFFFFF,t_70,g_se,x_16.png

41261038b72a583476b25d72f1f105c9_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_19,color_FFFFFF,t_70,g_se,x_16.png




💬 代码演示


Status ListInsert(SqList &L, int i,ElemType e)
{//在顺序表L中第i个位置插入新的元素e,i值的合法范围是1≤i≤L. length+1
  if((i<1)||(i>L. length+1)) 
  return ERROR;//i值不合法
  if(L. length==MAXSIZE) 
  return ERROR;//当前存储空间已满
  for(j=L. length-1;j>=i-1;j--)
  L.elem[j+1]=L.elem[j];
  L.elem[i-1]=e;
  ++L. length;
  return OK;
}


🌷顺序表的删除


和插入同理,在线性表的顺序存储结构中,由于逻辑上相邻的数据元素在物理位置上也是相邻的,为了在线性表的第i个位置上删除一个数据元素,则需将第i个至最后一个数据元素依次向前移动一个位置。


🔺实现原理


1️⃣判断插入位置i是否合法(i值的合法范围是1≤i≤n+1),若不合法则返回ERROR。


2️⃣将第i+1个至第n个元素依次向前移动一个位置。


3️⃣表长减一。


🔑空间状态

5bfc79ea4144f20df6efe206e8a9d4e0_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_19,color_FFFFFF,t_70,g_se,x_16.png

e9a10100fc8c4917dfef14ffb9583df8_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_19,color_FFFFFF,t_70,g_se,x_16.png




💬 代码演示


Status ListDelete(SqList &L, int i)
{//在顺序表L中删除第i个元素,i值的合法范围是1≤i≤L.1ength 
  if(i<1)||(i>L. length)) 
  return ERROR;//i值不合法
  for(j=i;j<=L. length-1;j++)
  L,elem[j-1]=L,elem[j];//被删除元素之后的元素前移
  --L. length;//表长减1
  return OK;
}


🌷顺序表的优缺点


顺序表的内存连续,支持随机访问,可以高效的按下标进行操作,可以很方便的查找表中任一元素。

然而,通过上文不难发现,在做插入或删除操作时,需移动大量元素。当表中数据元素个数较多且变化较大时,操作过程相对复杂。这些问题,以通过线性表的另一种表示方法——链式存储结构来解决。



相关文章
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
226 4
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
383 30
|
10月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
459 25
|
11月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
530 5
|
11月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
本文档介绍了线性表的基本运算任务,涵盖顺序表和链表的初始化、销毁、判定是否为空、求长度、输出、查找元素、插入和删除元素等内容。通过C++代码示例详细展示了每一步骤的具体实现方法,并提供了测试说明和通关代码。 主要内容包括: - **任务描述**:实现顺序表的基本运算。 - **相关知识**:介绍线性表的基本概念及操作,如初始化、销毁、判定是否为空表等。 - **具体操作**:详述顺序表和链表的初始化、求长度、输出、查找、插入和删除元素的方法,并附有代码示例。 - **测试说明**:提供测试输入和预期输出,确保代码正确性。 - **通关代码**:给出完整的C++代码实现,帮助完成任务。 文档
371 5
|
12月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
358 5
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
298 59
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
131 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。

热门文章

最新文章