数据结构C语言版:顺序表基本操作的实现

2024-06-16 13:36

本文主要是介绍数据结构C语言版:顺序表基本操作的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考教材:数据结构C语言版(严蔚敏,吴伟民编著)

目录

线性表的基本操作:

1:线性表L的初始化(参数用引用)

2:销毁线性表L

3:清空线性表L

4:求线性表L的长度

5:判断线性表是否为空

6:顺序表的取值(根据位置i获取相应位置数据元素的内容)

7:线性表的查找

8:顺序表的插入 

9:顺序表的删除


线性表的基本操作:

补充:操作算法中用到的预定义常量和类型

//函数结果状态代码
#define    TURE           1
#define    FALSE          0
#define    OK             1
#define    ERROR          0
#define    INFEASIBLE     -1
#define    OVERFLOW       -2
//Status是函数的类型,其值是函数结果状态的代码
typedef  int  Status;
typedef  char  ElemType;

1:线性表L的初始化(参数用引用)

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

new表示动态分配空间,即空间可伸缩

这个函数是初始化线性表,1.给数组分配空间,并检测分配是否成功        2.为长度赋值为0

if(!L.elem):这是一个条件语句,检查线性表L中的elem’成员是否为NULL或者未分配。’!是逻辑非运算符,所以’!L.elem”的意思是如果L.elem'为NULL或者未分配,条件成立。

c的写法是(elem type*)malloc(sizeof(elemtype)*maxsize;

2:销毁线性表L

void DestroyList(SqList &L){if(L.elem) delete L.elem;//释放存储空间
}

 销毁:从内存中将L占用的空间释放

前提条件:有空间才才释放,没有空间不需要释放

if(L.elem) delete L.elem:如果这个线性表存在,然后将他删除掉,线性表L将不再存在。

3:清空线性表L

vold ClearList(SqList &L){L.length=0;    //将线性表的长度置为0
}

这个就属于逻辑上的清空,让之前的数据找不到了就叫做清空。

逻辑清空,假装已经清空了,只要把长度变成0,那么后面的访问超出范围就会主动拒绝掉。

4:求线性表L的长度

int GetLength(SqList L){return (L.length);
}

这里可以加&,这样当列表很大时可以节约开辟副本的时间和空间。

5:判断线性表是否为空

int IsEmpty(SqList L){
if (L.length==0) return 1;
else return 0;
}

if (L.length==0):判断线性表是否为空,如果是空的则返回1,不是空的返回0

6:顺序表的取值(根据位置i获取相应位置数据元素的内容)

int GetElem(SqList L,int i,ElemType &e){if (i<1||i>L.length) return ERROR;//判断i值是否合理,若不合理,返回ERRORe=L.elem[i-1];//第i-1的单元存储着第i个数据return Ok;
}

不引用是因为,不需要修改,牢记一点:是否需要对这个数据进行修改?不需要修改那么不需要引用。

只要记住,引用&的目的是修改这个数据,不修改就不引用,这个要点可以解答你所有有关“为什么&,为什么不&”的问题

i是需要获取第i个元素,e代表要取出的元素,这里用&引用直接会修改传入的变量e

这里i是位序,逻辑位序,物理位序的话是数组的下标,差了1,所以逻辑上的i,实际上是数组里的i-1

判断里是逻辑序号1,2,...,length, e的赋值语句里是物理序号0,1,,...,length-1,也可以把判断换成i<0||i>L.length-1

因为每个语句只执行一次,此处的时间复杂度为常量阶:O(1)

线性表的常用的两种储存结构:顺序存储结构(顺序表)和链式存储结构(链表)

7:线性表的查找

1:在线性表L中查找与指定值e相同的数据元素的位置

2:从表的一端开始,逐个进行记录的关键字和给定值的比较。如果找到,返回该元素的位置序号,未找到,返回0。 

int LocateELem(SqList L, ElemType e){
//在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)for (i=0;i< L.length;i++)if(L.elem[i]==e) return i+1; //查找成功,返回序号return 0; //查找失败,返回0
}

这里面elem如果是自定义类型,是不可以做相等判断的,需要重载==

l.length就是元素的个数,因为下标从0开始,所以i=0,从0开始查找

i是对比数组里下标为i的数,数组的实际使用个数=l.length,但是下标是length-1.

此算法的执行次数最多的语句是: if(L.elem[i]==e) return i+1;         时间复杂度:O(n)

int LocateELem(SqList L, ElemType e){
//在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)while (i< L.length&&L.elem[i]!=e) i++;if(i<L.length) return i+1; //查找成功,返回序号return 0; //查找失败,返回0
}

顺序表的查找分析:

因为查找算法的基本操作为:将记录的关键字同给定值进行比较

基本操作:L.elem[i] == e

比较次数,e=a,1次;e=b,2次;e=c,3次;......,e=g,7次

平均查找次数:(1+2+3+4+5+6+7)/7 =4次        (首相加末项)/2=(1+7)/2

最好情况:查找的元素就在表头,仅需比较一次,时间复杂度为O(1)。
最坏情况:查找的元素在表尾(或不存在)时,需要比较n次,时间复杂度为O(n)

平均查找长度ASL(Average Search Length)

为确定记录在表中的位置,需要与给定值进行比较的关键字的个数的期望值叫做查找算法的平均查找长度。

对含有n个记录的表,查找成功时:

Pi:第i个记录被查找的概率        Ci:找到第i个记录需比较的的次数

顺序查找的平均查找长度:ASL=P_{1}*1+P_{2}*2+...+(n-1)P_{n-1}+nP_{n}

假设每个记录的查找概率相等:P_{i}=\frac{1}{n}

假如P_{1}=P_{2}=...=P_{n}=\frac{1}{n},则ASL=P_{1}*1+P_{2}*2+...+(n-1)P_{n-1}+nP_{n} \\=\frac{1}{n}(1+2+..+n) \\=\frac{1}{n}*\frac{n(n+1)}{2} \\=\frac{n+1}{2}

8:顺序表的插入 

线性表的插入运算是指在表的第 (1≤i<n(L.length)+1)个位置上,插入一个新结点(元素) e,使长度为n(L.length)的线性表(a1,… ai -1,ai,… an)变成长度为n+1(L.length+1) 的线性表(a1, .. ai -1,e, ai,an)。

算法思想:①判断插入位置i 是否合法。
②判断顺序表的存储空间是否已满,若已满返回ERROR。                                                            ③将第n至第ì 位的元素依次向后移动一个位置,空出第i个位置                                                      ④将要插入的新元素e放入第i个位置。                                                                                            ⑤表长加1,插入成功返回OK。

Status ListInsert_Sq(SqList &L,int i ,ElemType e){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;    //将新元素e放入第i个位置L.length++;            //表长增1return OK;
}

if(i < 1 || i > L.Length+1)return ERROR:判断i的范围是否有效,i只能在1~L.length+1的范围,如果i不在规定范围:i<1或i > L.Length+1,则返回error。注意:这里的i是位序 不是组数下标! 

if(L.length == MAXSIZE) return ERROR:判断当前的存储空间是否已满,L.length == MAXSIZE:当前存储空间已满,不能插入,则返回error

 for(j = L.length-1; j >= i-1; j--)
        L.elem[j+1]=L.elem[j];  
   :j是数组下标,将第i个元素及之后的元素后移,将下标为j的元素放入到j+1

p要小于等于n+1就是只能紧贴着原数组的最后一个元素去插入,因为线性表规定所有元素必须紧挨在一起,不能出现空一个的情况

算法时间主要耗费在移动元素的操作上:
若插入在尾结点之后,则根本无需移动(特别快);        时间复杂度:O(1)

若插入在首结点之前,则表中元素全部后移(特别慢);        时间复杂度:O(n)

若要考虑在各种位置插入(共n+1种可能)的平均移动次数,该如何计算? 

i+x=n+1,x=n+1-i        i是第几个位置,x是移动次数

i~n总共移动x次,也就是总共x个元素,移动后i~n下标变成i+1~n+1,所以前面i个元素与后面x个元素的和为n+1。

i是位序(插到第几位),n是下标,x是移动次数,例:数组有5个元素,把新元素添插在最后就是第6;代入公式:6+0=5+1。

再来一个理解方法:n+1是插入新元素数组的最后一个位置,i是插入元素的位置,移动次数就是[最后-当前]=[n+1-i]

设pi代表在第i个位置上插入一个结点的概率,那么pi=1/(n+1),所以在长度为n个结点的顺序表中插入结点时所需要移动的平均次数可以这样表示·: 

顺序表插入算法的平均时间复杂度:O(n)

插入不同位置的算法演示:

插入位置在最后:

插入位置在中间:

实际操作的时候,  先判断数组是否满, 满就返回错误。然后如果是在中间插入, 当然需要挪元素, 需要挪最后一个元素,最后一个元素的位序是 length-1 , 然后挪到length的位置

插入位置在最前面: 

可以遍历整一个逆序的数组,然后在最后面插入一个元素,然后再遍历逆序一下,回到原来的数组

9:顺序表的删除

线性表的删除运算是指将表的第 i (1 ≤ i ≤ n(L.length) )个结点删除

使长度为n 的线性表(a_{1},...,a_{i-1},a_{i},a_{i+1},...,a_{n})

变成长度为n-1的线性表(a_{1},...,a_{i-1},a_{i+1},...,a_{n})

算法思想:
①判断删除位置i 是否合法(合法值为1≤i≤n)。不合法则返回ERROR                                                  ②将欲删除的元素保留在e中。
③将第i+1至第n 位的元素依次向前移动一个位置。
④表长减1,删除成功返回OK。 

Status ListDelete_Sq(SqList &L,int i){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- -;                           //表长减1return OK;                           
}

Status ListDelete_Sq(SqList &L,int i):在线性表L上面删除第i个位置上的元素,删除的结果仍由线性表L保存

if((i < 1)||(i > L.length)) return ERROR:判断删除位置是否合法,如果是小于1或大于L.length,则不合法,返回ERROR,位置合法,进行下一步。L.length就是元素的个数。

for (j = i;j <= L.length-1; j+ +)   :从删除的元素i的后继开始,一直到最后一个元素L.length。 L.length个元素在L.length-1的位置存储。

L.elem[j-1 ]= L.elem[j]:将后面一个元素,赋值到前一个位置

i理解为位置,j是下标,i位置是(1~n),j对应下标是(0~n-1),所以删第i个位置就是删下标i-1。这里是j等于i,是指位置序号,不是数组下标

这里包括前面的代码都是删除指定位置的元素而不是指定索引的元素。

算法时间主要耗费在移动元素的操作上:
若删除尾结点,则根本无需移动(特别快);                        时间复杂度:O(1)
若删除首结点,则表中n-1个元素全部前移(特别慢);      时间复杂度:O(n)                                      若要考虑在各种位置删除(共n种可能)的平均移动次数,该如何计算?

 

i=1,2,3,...,n                x(次数)=n-1,n-2,...,0        i和x的关系:n-i

将移动次数相加:((n-1) + (n-2)+...+(0)) / n

顺序表删除算法的平均时间复杂度为O(n) 

 

这篇关于数据结构C语言版:顺序表基本操作的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动