线性表&顺序线性表
第二章 线性表
参考文献:[数据结构(C语言版)].严蔚敏
本篇章仅为个人学习数据结构的笔记,不做任何用途。
2.1 线性结构的特点
(1). 存在唯一的一个被称为"第一个"的数据元素
(2). 存在唯一的一个被称为"最后一个"的数据元素
(3). 除第一个之外,集合中的每个数据元素均有唯一的前驱
(4). 除最后一个之外,集合中的每个数据元素均有唯一的后继
2.2 线性表的类型定义
线性表(linear_list) 是最简单最常用的一种数据结构。一个线性表是n个数据元素的有限序列。
例如,26个英文字母的字母表:
(A,B,C,...,Z)
上述是一个线性表,数据元素是单个字母字符。
例如,一个家庭中各个家庭成员的年龄,可用线性表的形式给出:
(6,17,32,38,48,70,96)
上述线性表中的数据元素是整数。
复杂的线性表情况如下:
- 一个数据元素有若干个 数据项(item) 组成。
- 如上情况,数据元素称为 记录(record)。
- 含有大量记录的线性表称为 文件(file)。
例如,一个学生的学生健康情况登记表。表中每个学生的情况为一个记录。
它由姓名,学号,性别,年龄,班级等5个数据项组成。
| 姓名 | 学号 | 性别 | 年龄 | 班级 |
|---|---|---|---|---|
| 张盛东 | 790302 | 男 | 28 | 计科062 |
| 卢晔 | 790303 | 女 | 26 | 计科061 |
因此,线性表的抽象描述如下:
$$ (a_{1},...,a_{i-1},a_{i},a_{i+1},...,a_{n}) $$
当i=1,2,...,n-1时,ai有且仅有一个直接后继。
当i=2,3,...,n时,ai有且仅有一个直接前驱。
线性表中元素的个数n(n>=0)定义为线性表的长度,n=0为空表。
非空表中的每个数据元素都有一个确定的位置。如a1是第一个数据元素,如an是最后一个数据元素,ai是第i个元素,i为数据元素ai在线性表的位序。
抽象数据类型的结构:
ADT 抽象数据类型名{
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
} ADT 抽象数据类型名
抽象数据类型线性表的定义:
ADT List{
数据对象:D ={a(i)|a(i) 属于ElemSet, i=1,2,...,n,n>=0}
数据关系:R ={<a(i-1),a(i)>|<a(i-1),a(i) 属于D,i=2,...,n}
基本操作:
InitList(&L)
操作结果:构造一个空的线性表L。
DestoryList(&L)
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList(&L)
初始条件:线性表L已存在。
操作结果:将L重置为空表。
ListEmpty(L)
初始条件:线性表L已存在。
操作结果:判断L是否为空表,是的话返回True,不是返回False。
ListLength(L)
初始条件:线性表L已存在。
操作结果:返回L中数据元素的个数。
GetElem(L,i,&e)
初始条件:线性表L已存在,1<=i<=ListLength(L)
操作结果:用e返回L中第i个数据元素的值。
LocateElem(L,e,compare())
初始条件:线性表L存在,compare()是数据元素判定函数。
操作结果:返回L中第一个与e满足关系compare()的数据元素的位序。若这样的数据元素不存在,则返回值为0。(通俗来讲,就是返回数据元素的位置)
PriorElem(L,cur_e,&pre_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e不存在。(通俗来讲,返回数据元素的前驱)
NextElem(L,cur_e,&next_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e不存在。(通俗来讲,返回数据元素的后继)
ListInert(&L,i,e)
初始条件:线性表L已存在,1<=i<=ListLength(L)+1。
操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。
ListDelete(&L,i,&e)
初始条件:线性表L已存在,1<=i<=ListLength(L)。
操作结果:删除L中第i个数据元素,并用e返回其值,L的长度减1。
ListTraverse(L,visit())
初始条件:线性表L已存在。
操作结果:依次对L的每个数据元素调用visit()。一旦visit()失败,则操作失败。
(通俗来讲,对每一个数据元素进行遍历)
} ADT List
2.3 线性表的顺序表示和实现
线性表的顺序表示 指的是用一组地址连续的存储单元依次存储线性表的数据元素。
假设线性表的每个元素需要用l个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则第i+1个数据元素的存储位置LOC(a1+1)和第i个数据元素的存储位置LOC(ai)满足如下关系:
$$ LOC(a_{i+1})=LOC(a_{i})+l$$
一般来说,线性表中的第i个数据元素的存储位置为:
$$ LOC(a_{i})=LOC(a_{1})+(i-1)*l$$
上述的这种表述称为线性表的顺序结构。亦或者称为顺序映像(sequential mapping)。其特点为:
相邻的两个数据元素ai和a1+1。其存储的"物理位置"也相邻。示意图如下:

由于确定了存储线性表的起始位置,每一个数据元素的存储位置都和线性表的起始位置相差一个和数据元素在线性表中的位序成正比的常数,线性表中任一数据元素都可随机存取,所以线性表的顺序结构是一种随机存取的存储结构。
C语言中可用动态分配的一维数组,来描述线性表的顺序存储结构,其中数组指针elem指示线性表的基地址,length代表线性表的当前长度,如下:
// - - - - - 线性表的动态分配顺序存储结构 - - - - -
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct {
ELemType * elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量(以sizeof(ElemTpye)为单位)
}SqList;
如下算法用于构造一个空的线性表。初始化操作是为顺序表分配一个预定义大小的数组空间,并将线性表的当前长度设为"0"。listsize为当前分配的存储空间大小。
Status InitList_Sq(SqList &L){
//构造一个空的线性表L。
L.elem = (ELemType *)malloc(LIST_INIT_SIZE * sizeof(ELemType));
if(! L.elem) exit(OVERFLOW); //存储分配失败
L.length = 0; //空表长度为0
L.listsize = LIST_INIT_SIZE; //初始化存储容量
return OK;
}// InitList_Sq
线性表的顺序存储的插入操作:
例如:在线性表的第i-1个数据元素和第i个数据元素之间插入一个新的数据元素,会使得长度为n的线性表。
$$ (a_{1},...,a_{i-1},a_{i},...,a_{n}) $$
变成长度为n+1的线性表
$$ (a_{1},...,a_{i-1},b,a_{i},...,a_{n}) $$
在线性表中的顺序存储结构中,由于逻辑上相邻的数据元素在物理位置上也是相邻的。因此,插入数据元素,存储位置有如下的变化。

顺序线性表的插入算法:
Status ListInsert_Sq(SqList &L,int i,ElemType e){
//在顺序线性表中L中第i个位置之前插入新的元素e。
//i的合法值为1<=i<=ListLength_Sq(L)+1
if(i < 1 || i >L.length+1) return ERROR; //i值不合法
if(L.length >L.listsize){
newbase = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT) * sizeof(ElemTpye));
if(! newbase)exit(OVERFLOW); //存储分配失败
L.elem = newbase; //新基址
L.listsize += LISTINCREMENT; //增加存储容量
}
q = &(L.elem[i-1]); //q为插入位置
for (p = &(L.elem[L.length-1]);p >= q; --p)
*(p+1) =*p; //插入位置及之后的元素后移
* q =e; //插入e
++L.length; //线性表长度+1
return OK;
}// ListInsert_Sq
线性表的顺序存储的删除操作:
例如:在线性表中删除一个数据元素,会使得长度为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}) $$
删除数据元素,存储位置有如下变化。

顺序线性表的删除算法:
Status ListDelete_Sq(SqList &L,int i,ElemType &e){
//在顺序线性表中L中删除第i个元素,并用e返回其值。
//i的合法值为1<=i<=ListLength_Sq(L)
if(i < 1 || i >L.length+1) return ERROR; //i值不合法
p = &(L.elem[i-1]); //q为删除元素的位置
e = *p; //被删除元素的值赋予e
q = L.elem+L.length-1; //表尾元素的位置
for(++p;p<=q,++p) *(p-1) = *p; //被删除元素之后的位置左移
--L.length; //线性表长度-1
return OK;
}// ListDelete_Sq
线性表的顺序存储的查找操作:
顺序线性表的查找算法:
int LocateElem_Sq(SqList L,ElemType e,Status (*compare)(ElemType,ElemType)){
//在顺序线性表中L中查找第一个与e满足compare()的元素的位序。
//若找到,则返回其在L中的位序,否则返回0。
i = 1 //i的初值为第一个元素的位序。
p = L.elem; //p的初值为第一个元素的存储位置。
while(i<=L.length && !(*compare)(* p++,e)) ++i;
if(i<=L.length) return i;
else return 0;
}// LocateElem_Sq
线性表的顺序存储的合并操作:
void MergeList_Sq(SqList La,Sqlist Lb,SqList &Lc) {
// 已知顺序线性表La和Lb的元素按值非递减排列
//归并La和Lb得到的新的顺序线性表Lc,Lc的元素也按值非递减排列
pa =La.elem; pb=Lb.elem;
Lc.listsize =Lc.length = La.length+Lb.length;
pc = Lc.elem =(ElemTpye *)malloc(Lc.listsize *sizeof(ElemTpye));
if(!Lc.elem)exit(OVERFLOW); //存储分配失败
pa_last = La.elem + La.length -1;
pb_last = Lb.elem + Lb.length -1;
while(pa <= pa_last && pb <= pb_last){ //归并
if( *pa <= *pb) *pc++ = *pa++;
else *pc++ = *pb++;
}
while(pa <= pa_last) *pc++ = *pa++;
while(pb <= pb_last) *pc++ = *pb++;
} //MergeList_Sq
线性表&顺序线性表的更多相关文章
- 动态分配的顺序线性表的十五种操作—C语言实现
线性表 定义:是最常用的,也是最简单的数据结构,是长度为n个数据元素的有序的序列. 含有大量记录的线性表叫文件 记录:稍微复杂的线性表里,数据元素为若干个数据项组成,这时把一个数据元素叫记录 结构特点 ...
- 顺序线性表之大整数求和C++
顺序线性表之大整数求和 大整数求和伪代码 1.初始化进位标志 flag=0: 2.求大整数 A 和 B 的长度: int aLength = a.GetLength(); int bLength = ...
- 顺序线性表 ---- ArrayList 源码解析及实现原理分析
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...
- 顺序线性表之大整数求和C++实现
顺序线性表之大整数求和 大整数求和伪代码 1.初始化进位标志 flag=0: 2.求大整数 A 和 B 的长度: int aLength = a.GetLength(); int bLength = ...
- 数据结构----线性表顺序和链式结构的使用(c)
PS:在学习数据结构之前,我相信很多博友也都学习过一些语言,比如说java,c语言,c++,web等,我们之前用的一些方法大都是封装好的,就java而言,里面使用了大量的封装好的方法,一些算法也大都写 ...
- C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作
1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...
- 线性表——顺序表的实现与讲解(C++描述)
线性表 引言 新生安排体检,为了 便管理与统一数据,学校特地规定了排队的方式,即按照学号排队,谁在前谁在后,这都是规定好的,所以谁在谁不在,都是非常方便统计的,同学们就像被一条线(学号)联系起来了,这 ...
- 01线性表顺序存储_List--(线性表)
#include "stdio.h" #include "stdlib.h" #include "io.h" #include " ...
- java哈希表(线性探测哈希表。链式哈希表)
哈希表(散列表) 通过哈希函数使元素的存储位置与它 的关键码之间能够建立一一映射的关系,在查找时可以很快找到该元素. 哈希表hash table(key,value) 的做法其实很简单,就是把Key通 ...
随机推荐
- VS code的疑惑之处
作为一个新手,我充满疑惑 eg:下载了git但无法使用匹配 然后在各位博主的详细解释下知道 VS code更新后的git.path被格式化了: so需要进行路径覆盖. 在这之后我的终端依旧出现问题 ...
- optimizer
在很多机器学习和深度学习的应用中,我们发现用的最多的优化器是 Adam,为什么呢? 下面是 TensorFlow 中的优化器, https://www.tensorflow.org/api_guide ...
- 关于 Block 中捕获 self 的分析
问题 最近遇到一个已经使用了weak-strong dance的block依旧强引用了self的情况,好在block没被VC持有只是延迟释放,但这里的关键是用了weak_self的blcok理应不会强 ...
- 剑指offer面试题26:复杂链表的复制
题目:请实现一个函数,复制一个复杂链表. 在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指针指向链表中的任意结点或者nulL 直观解法: 1.遍历链表,复制链表节 ...
- 微服务中Feign快速搭建
在微服务架构搭建声明性REST客户端[feign].Feign是一个声明式的Web服务客户端.这使得Web服务客户端的写入更加方便 要使用Feign创建一个界面并对其进行注释.它具有可插入注释支持,包 ...
- 每天学点SpringCloud(七):路由器和过滤器-Zuul
为什么要使用Zuul 先来看一下下方这个图 假如现在我们具有四个微服务,分别是用户.订单.支付.催收微服务,它们的调用方式分别是使用http.restful.thrift.kafka.这个时候如果我们 ...
- 吴恩达机器学习笔记38-决策下一步做什么(Deciding What to Do Next Revisited)
我们已经讨论了模型选择问题,偏差和方差的问题.那么这些诊断法则怎样帮助我们判断,哪些方法可能有助于改进学习算法的效果,而哪些可能是徒劳的呢? 让我们再次回到最开始的例子,在那里寻找答案,这就是我们之前 ...
- C 单向链表就地逆转
1.问题描述 给定一个单链表L,设计函数Reverse将L就地逆转.即不需要申请新的节点,将第一个节点转换为最后一个结点,第二个节点转换为倒数第二个结点,以此类推. 2.思路分析 循环处理整个链表.将 ...
- Java面试集合(六)
1. abstract抽象 什么是abstract,中文为抽象,从具体事物抽出,概括它们共同的方面,本质属性与关系等,称为抽象.看不见,摸不着的东西叫做抽象,抽象是人们对世界万物的感觉,用特定的图像表 ...
- Kali学习笔记13:操作系统识别
为什么要扫描操作系统呢? 其实和上一篇博客:<服务扫描>类似,都是为了能够发现漏洞 发现什么漏洞? 不同的操作系统.相同操作系统不同版本,都存在着一些可以利用的漏洞 而且,不同的系统会默认 ...