大话西游之王道考研数据结构第一讲---线性表的顺序表示

写在前面的话

王道考研数据结构是一本非常好的书,本系列所有的内容是按照其书进行讲述的,所以您可以以那本书作为主要内容,这个做参考。

大学时候,在网上看到了一个人通过讲三国的形式把并查集(union find)讲的非常清楚且很有意思。我很喜欢这样的方式,所以一直想着能够利用相似的方式把我对数据结构的理解表达出来。

这样的方式可能并不能够被所有人接受,内容也会很不严谨,如果有错误的地方请多多包涵。我希望能够帮到一些很讨厌数据结构的人,至少能够让数据结构看起来不是很枯燥。

恰好最近在给一个同学补习考研数据结构,所以我想一直更新下去,每周更新三次(二、四、六),感谢您的支持。

第二章 线性表

2.1 线性表的定义

线性表就是一堆类型的n(n>=0)个数据元素的有限序列。

(注意下标)

举个栗子:

把唐僧师徒5人看成数据元素,他们准备成立一家公司。

首先,公司得去工商局注册,我们得告诉工商局公司最大打算招多少员工(500人)。

公司当然得分老大老二了。唐僧肯定是老大了。

老大

老二

老三

老四

老五

唐僧 猴哥 八戒 沙僧 马马

接下来就是猴哥、八戒、沙僧、马马。

 特点:

1.公司最大人数有限(最多500个人,再多可能以为是P2P)

(表中元素个数有限)

2.团队内部等级分明,是有次序的

(表中元素具有逻辑上的顺序性,在数列中各元素排序已有其先后次序)

3.人总得有个住处,公司得登记大家住处,所以每一个人一个房子(再牛的老大也就一个房子。。。)

(每个元素相同大小的存储空间)

4.无论高低贵贱,在一起就是兄弟,就能排上号,并不是因为年龄大就辈分大。

(元素具有抽象性,仅讨论元素间的逻辑关系,不考虑元素究竟表示什么内容,也就是如果存储内容是年龄的话,并不是因为年龄大就在前面)

线性表有两种表示方法,一种是顺序表示,一种是链式表示。

2.2 线性表的顺序表示

2.2.1 顺序表的定义

线性表的顺序存储又称为顺序表,表中元素的逻辑顺序与其物理顺序相同

举个栗子:

这个公司比较有钱,他们属于单位分配房子,所以大家都在一个小区,唐僧的门牌号是(62000,62可以是小区的编号),并且从这个编号往后数500位都是你们的编号,自行分配。但是哪个房子住谁都得给工商局备案,并且为了公平,大家按照辈分依次分房。

唐僧是老大,所住房子是62000。公司内部为了简单起见,把前面的编号省去,所以他是0。

0

1

2

3

4

老大

老二

老三

老四

老五

唐僧 猴哥 八戒 沙僧 马马

2.1.2 顺序表上的基本操作与实现

首先,我们定义一下公司的内容。

#define MAXSIZE 500    //公司最大规模
typedef struct
{int *seat;  //交椅(编号)-人int length; //当前公司有多少个人}SqList;

1.申请公司~,工商局得有个准备工作,看看给你的编号段之前有没有信息,(比如有个公司原来是这个编号段,但是倒闭了,信息还在,但是可以分配给新的公司),有的话清除掉(把倒闭公司的信息抹掉)。

(InitList(&L):初始化表,构造一个空的线性表)

void InitList(SqList &sqList){sqList.seat = (int *)malloc(sizeof(int)*MAXSIZE); //咱直接申请最大规模的公司sqList.length = 0;    //当前公司人数是0个,因为还没分老大老二呢
}

2.看下这个公司当前有多少人。

(Length(L):求表长,返回线性表L的长度,即L中数据元素的个数)

int Length(SqList sqList){return sqList.length;
}

3. 看下马马的房子编号是多少

(LocateElem(L,e):按值查找操作,e代表人)

int LocateElem(SqList sqList,int e){int locate = -1;for(int i =0;i<sqList.length;i++){ //我们在找马马if(sqList.seat[i] == e){ //找到了locate = i; return locate; //返回马马的编号}}return locate; //如果找不到的话,就返回-1
}

4.看下编号是4的人叫啥

(GetElem(L,i):按位查找操作,i代表编号)

int GetElem(SqList sqList,int i){return sqList.seat[i];}

随机访问,可以通过首地址和元素符号在O(1)复杂度下找到那个人

5.来了一位能力超群大佬想加入公司,并且要求你必须给我老三的位置

(ListInsert(&L,i,e):把e插入到第i个位置)

1.插入的位置对不对

2.够不够插

3.往后挪

4.插!

5.修改总人数length

6.返回true

(&表示人员变动得上报工商局,不然罚款)

bool ListInsert(SqList &sqList,int i,int e){/*加入一个人当老i*/bool isSucceed = false; //先让它置为false,基本操作if(i<1 || i>sqList.length+1){  //首先,我们检查第i个位置是否在这个团队中,比如唐僧是老大(位置是0),马马是老五个人(位置是4)//如果我们输入的i<1 是不存在老0 老-1 之类的 所以返回flase//如果我们输入的i>L.length+1 比如 i = 7 现在最小老五, 来个人想当老7 也是不合理的, 返回falsereturn isSucceed;}if(sqList.length + 1 > MAXSIZE){ //如果队伍人数超过之前申请的最大人数 队伍满啦 再来小弟大家就没饭吃了 所以返回falsereturn isSucceed;}for(int j = sqList.length;j>=i;j--){ //比如来个人当老二,那么马马 沙僧 八戒都得往后排//想想为什么是倒序sqList.seat[j] = sqList.seat[j-1];}sqList.seat[i-1] = e;  //这把交椅就是兄弟你的了sqList.length++;  //总人数加1isSucceed = true; //插入成功~return isSucceed;}

6.      老二猴哥表示这破公司,我TM(提莫~)待不下去了,俺老孙去也~

1.位置对不对

2.挪!  为什么不执行删的步骤

3.修改人数

4.返回true

(ListDelete(&L,i,&e):删除第i个位置的人,并用e把这个人返回,”&”---还得上报工商局)

bool ListDelete(SqList &sqList, int i,int &e){/*把老i踢出公司*/bool isSucceed = false; //先让它置为false,基本操作if(i<1 || i>sqList.length+1){  //首先,我们检查第i个位置是否在这个团队中,比如唐僧是老大(位置是0),马马是老五个人(位置是4)//如果我们输入的i<1 是不存在老0 老-1 之类的 所以返回flase//如果我们输入的i>L.length+1 比如 i = 7 现在最小老五, 想踢老7 也是不合理的, 返回falsereturn isSucceed;}//想想这里为什么不检查是否超出公司最大人数,但在ListInsert里面检查了e = sqList.seat[i-1]; //用e返回这个人,想想e传参时候为什么加地址for(int j = i;j<sqList.length;j++) //为什么是正序{sqList.seat[j-1] = sqList.seat[j]; //为什么是j-1,想想老大和老大的位置之间的关系}sqList.length--; //走了一个,总人数减1isSucceed = true;return isSucceed;
}

7.      公司开会,我来点个名

(PrintList(L):输出操作)

void PrintList(SqList sqList){for(int i =0;i<sqList.length;i++){printf("%d ",sqList.seat[i]); //加个空格优雅美观大方楚楚动人}printf("\n");
}

8.      是不是空壳公司哇~

(Empty(L):判空操作)

bool Empty(SqList sqList){if(sqList.length == 0)return true;elsereturn false;
}

9.  浙江皮革厂倒闭啦,WBDHHLBDZXYZPL

(DestroyList(&L):销毁操作,”&”--这必须上报工商局)

void DestroyList(SqList &sqList){sqList.length = 0;free(sqList.seat); //这里不能直接释放sqList,至于原因emmmmm我也不晓得哎~
}

课后习题附加

1.理论部分

1.1逻辑结构和存储结构的区别

选择题第2题有涉及到这个内容,这里说明一下:

  • 什么是逻辑结构

逻辑结构就是数据之间的关系。而按数据之间的关系来说,逻辑结构大概可以分为两种:线性结构非线性结构(集合、树、网)

  • 线性结构:有且只有一个开始结点和一个终端结点,并且所有结点都最多只有一个直接前驱和一个直接后继。例如:线性表,典型的线性表有:顺序表、链表、栈(顺序栈、链栈)和队列(顺序队列、链队列)。它们共同的特点就是数据之间的线性关系,除了头结点和尾结点之外,每个结点都有唯一的前驱和唯一的后继,也就是所谓的一对一的关系。

举个栗子

唐僧是老大,猴哥是老二,他俩就是前驱和后继的关系,而且老K的前驱是老K-1,后继是老K+1,是唯一的。

老大

老二

老三

老四

老五

唐僧 猴哥 八戒 沙僧 马马
  • 非线性结构:对应于线性结构,非线性结构也就是每个结点可以有不止一个直接前驱直接后继。常见的非线性结构包括:树(二叉树)、图(网)等。

举个栗子

猴哥下面有很多猴子猴孙,比如猴哥生了2个猴(A,B),每一个猴又生了2个猴(A生(a1,a2),B生(b1,b2)),那么A的后继是a1,a2,这就不是线性结构了,这是树形结构:

  • 什么是存储结构

逻辑结构指的是数据间的关系,而存储结构是逻辑结构的存储映像。通俗的讲,可以将存储结构理解为逻辑结构用计算机语言的实现。常见的存储结构有顺序存储、链式存储、索引存储以及散列存储(哈希表)

  • 顺序存储:把逻辑上相邻的节点存储在物理位置上相邻的存储单元中,结点之间的逻辑关系由存储单元的邻接关系来体现。由此得到的存储结构为顺序存储结构,通常顺序存储结构是借助于数组来描述的。优点:节省空间,可以实现随机存取;缺点:插入、删除时需要移动元素,效率低。

举个栗子

这里说的是我们之前提到的编号问题,比如唐僧编号是0,猴哥编号是1。他俩的地址是相邻的。也可以理解为他们都住在计算机的内存里,他俩是邻居。

  • 链式存储:在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。特点是元素在物理上可以不相邻,所以每个数据元素包括了一个数据域和一个指针域,数据域用来存放数据,而指针域用来指向其后继结点的位置。优点:插入、删除灵活;缺点:不能随机存取,查找速度慢。

举个栗子

这个是即将提到的链式存储,可以理解为唐僧在一个地方,猴哥在另一个地方。他俩不一定是邻居。

1.2 随机存取和顺序存取的区别

  • 顺序存取:就是存取第N个数据时,必须先访问前(N-1)个数据 (链表)

举个栗子

原来打电话时候,我们不能直接获取对方的电话号码,需要先拨对方公司电话转接处,转接处知道对方的电话,所以帮你转接到对方座机。得有个顺序~

  • 随机存取:就是存取第N个数据时,不需要访问前(N-1)个数据,直接就可以对第N个数据操作 (线性表)

举个栗子

自从有了小天才电话手表,打电话再也不需要转接了,直接拨打对方号码,因为我们知道对方号码是多少,至于为什么知道——因为是小天才电话手表哇~ 随机这个词起的不是很好理解,姑且理解为你随便打个电话,就能打到当事人把~原来是只能打到转接处。

2.代码题

2.1 设计一个高效的算法,讲顺序表的所有元素逆置,要求算法空间复杂度为O(1)

注意,本题提到的是算法空间复杂度,也就是我们需要额外开辟的空间只能是一个元素的空间。置于时间上面没有要求。而逆置则是将原来的顺序颠倒,比如:

老大

老二

老三

老四

老五

唐僧 猴哥 八戒 沙僧 马马

最后的输出结果为:

老大

老二

老三

老四

老五

马马 沙僧 八戒 猴哥 唐僧

思路很关键,我们可以完全新开辟一个线性表,然后原来这个表按照从后向前,依次复制给新的线性表。但是新的线性表的空间为O(n),不符合要求。

也可以这么做,老大和老五交换,老二和老四交换,老三和老三交换。这样是不是就好了,怎么交换呢,之前在冒泡排序时候,相信大家都有这么一个操作。

void InversionList(SqList &sqList){int s = 0;int e = sqList.length-1;while(e>s){int temp = sqList.seat[s];sqList.seat[s] = sqList.seat[e];sqList.seat[e] = temp;s++;e--;}
}

3.长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,把其中所有值为x的元素删掉。

时间复杂度为O(n),一看到这个,我们因该想到遍历一遍顺序表的复杂度是O(n),所以我们只能遍历一遍,空间复杂度是O(1),说明我们只能额外开辟一个、两个空间(注意O(1)指的是开辟的空间个数是不变的,一个两个都算O(1)),就像O(2) = O(1) = O(100) ),和上题类似。

很容易想到的是,遍历一遍,遇到x的话,把后面的往前移,然后删掉x。然后我们再遍历一遍,遇到x的话,把后面的往前移,然后删掉x。然后......直到有一遍中没有x。

这是完全不符合要求的,但是只要你能把这个写出来,10分可以拿8分(改卷人就是这么不尊重算法的效率)。我们可以再想一个。比如x是坏果子,其他的是好果子,现在果子排成一排。我们要是能把好果子都放在最前面,坏果子都放在最后面。那么这个问题就解决了。

我们可以不考虑坏果子,从头到尾开始检查,遇到一个好果子就放在第一个位置,遇到一个就放在前面那堆好果子的后面。并且记录下一共有多少个好果子。这样好果子最后都在最前面了。自然坏果子都在后面了。

整体上空间复杂度是O(1),时间复杂度O(n)

void DeleteX(SqList &sqList, int x){int j = 0; //记录最前面好果子的最后一个位置for(int i = 0;i<sqList.length;i++){if(sqList.seat[i] != x){sqList.seat[j] = sqList.seat[i];j++;}}sqList.length = j;}

总结

顺序表的特点:

1.随机访问

因为唐僧的编号是确定的,他是老大,如果我们想知道老三是谁,我们就可以去工商局查,查的时候得需要老三的编号。因为唐僧老大,编号62000,老三编号肯定是62002,因为他们之间不容许有空号,这就是顺序表的特定。所以一查就是沙僧。

2.存储密度高

这个得和线性表的链式表示做一个对比了,等我们讲完链式表示在说说这个问题。目前我们知道,顺序表只需要一个存内容的数组的指针,一个内容长度。

3.插入、删除需要移动大量元素

因为我们不容许编号之间有空缺,比如有一个老大,没有老二,有个老三。这是不可以哒~,所以插入一个老二时候,原来的老二以及以后的人都得往后挪一挪。删除也是一样。

线性表的顺序表示比较简单,应该要明白线性表的每个操作的含义是什么,比如插入元素,我们因该先检查能不能插入,然后再插入,最后在返回结果。每个人写的代码都不一样,而且我们也背不会代码,所以思路是关键!。我上传了上述的所有代码,并且有一些调试的内容在里面。

https://download.csdn.net/download/zhangbaodan1/10555510

也可以在gitHub上面下载,这里是免费的

https://github.com/zhangbaodan/DataStructure

大话西游之王道考研数据结构第一讲---线性表的顺序表示相关推荐

  1. 数据结构——绪论以及线性表的顺序表示

    绪论 数据类型 数据类型是一个值的集合和定义在此集合上一组操作的总称. (1)原子类型:其值不可再分的数据类型,如int,char,float. (2)结构类型:其值可以再分解为若干成分的数据类型. ...

  2. 【数据结构基础】-线性表的顺序实现(数组实现)基本操作

    2019.10.10 [数据结构-线性表的顺序结构] 基本操作:初始化,判断是否空表,清空表,获取表中的第i个元素,查找元素,插入元素,删除元素,获取表的元素个数. 抽象数据类型: #include ...

  3. 数据结构与算法——线性表的顺序储存结构

    目录 前言 一.顺序储存的定义及储存方式 二.地址计算方法 三.顺序存储结构的插入和删除 3.1  获得元素操作 3.2   插入操作 3.3   删除操作 四.分析插入和删除操作的时间复杂度 五.线 ...

  4. (王道408考研数据结构)第二章线性表-第一节:线性表的定义和基本操作

    文章目录 一:线性表的定义 二:线性表的基本操作 一:线性表的定义 线性表(Linear List):零个或多个数据元素的有限序列 元素之间是有顺序的 若元素存在多个,则第一个元素无前驱,最后一个元素 ...

  5. (王道408考研数据结构)第二章线性表-第三节5:顺序表和链表的比较

    文章目录 一:逻辑结构比较 二:存储结构比较 三:基本操作比较 (1)初始化操作 (2)销毁操作 (3)插入和删除 (4)查找 顺序表和链表的选取原则 一:逻辑结构比较 顺序表和链表都是线性表,都是线 ...

  6. (王道408考研数据结构)第二章线性表-第三节1:单链表的定义及其操作(插入和删除,建立之尾插和头插)

    文章目录 一:单链表相关 (1)单链表的定义 (2)头指针与头结点 二:单链表代码描述 三:单链表的初始化 四:单链表的插入 五:单链表的删除 六:单链表查找 (1)按位查找 (2)按值查找 七:单链 ...

  7. (王道408考研数据结构)第二章线性表-第二节1:顺序表的定义

    文章目录 一:顺序表实现 (1)静态分配 (2)动态分配 二:顺序表特点 顺序表:也叫做线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素 一:顺序表实现 (1)静态分配 静 ...

  8. 王道408数据结构——第二章 线性表

    文章目录 一.线性表的定义和基本操作 线性表 顺序表 1.插入操作 2.删除操作 3.按值查找(顺序查找) 二.单链表 1. 头插法 2. 尾插法 3. 按序号查找 4. 按值查找 5. 插入结点 6 ...

  9. 数据结构——第一章线性表:01线性表的逻辑结构

    1.线性结构的基本特征:线性结构是一个数据元素的有序集. (1)集合中必定存在一个唯一的"第一元素" (2)集合中必定存在一个唯一的"最后元素" (3)除最后一 ...

最新文章

  1. 空间点像素索引(一)
  2. 深度剖析不一样的Redis架构设计!
  3. ros订阅相机深度信息_一起做ROS-DEMO系列 (2):基于find_object_2d的目标匹配识别
  4. 【PC工具】更新:在线智能抠图工具,在线视频、图片、音频等转换工具,绿色免安装抠图神奇抠图工具...
  5. 软件问题造成的经济损失案例_公司印章管理使用哪些行为会造成法律风险隐患...
  6. 登陆状态下加入购物车
  7. 牛客练习赛73 D 离别(线段树+右端点排序离线查询)
  8. linux没有interface文件,Linux下interface文件修改
  9. Shell——输入/输出重定向
  10. mavros 使用记录
  11. Shell每行前面加上行号
  12. A*寻路算法的探寻与改良(一)
  13. 关于url路径的定义方式
  14. ModelSim之命令行仿真入门
  15. oppo锁屏断网设置在哪里呀_oppo锁屏时钟怎么改格式?锁屏时钟位置在哪里设置调整...
  16. Devcpp(Dev-C++)代码编辑的快捷键
  17. VMware激活密钥
  18. limesurvey php5.2,WinXP下安装LimeSurvey(php环境搭建及网站程序安装)
  19. 一行脚本批量下载哔哩哔哩视频
  20. Audio Format

热门文章

  1. imos 学习笔记五 抓拍 c#
  2. 吴忠军 价值中国网主页
  3. Origin_正态检验以及频率统计
  4. 百度地图API调用实例之地址标注与位置显示
  5. 用于发现物联网设备的规则采集引擎
  6. WinDbg 命令三部曲:(三)WinDbg SOSEX 扩展命令手册
  7. 熊猫压缩怎么使用_将Excel与熊猫一起使用
  8. 【error:mysql】Data truncated for column ‘present_iri‘ at row 478
  9. mush上线,一篇关于技术的博客,欢迎关注!
  10. 如何登录微擎后台直接跳转到人人商城后台首页(其他模块也可参考)