数据结构复习(一)线性表
学习目标:
- 复习线性表
学习内容:
- 线性表的类型定义
- 线性表的顺序表示和实现
- 线性表的链式表示和实现
开始学习:
1.线性表的类型定义
线性表是是最常用且最简单的一种数据结构。线性表示一个相当灵活的数据结构,它的长度可根据需要增长或缩短,即对数据元素不仅可以进行访问,还可进行插入和删除等操作。
抽象数据类型定义如下:
ADT 线性表(List)
Data
数据对象为{a1, a2, ... , an}的集合,每个元素的类型相同。
Operation
InitList(*L)
操作结果:构造一个空的线性表 L。
DestroyList(*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)。
操作结果:返回 L 中第 i 个数据元素。
LocateElem(L, e)
初始条件:线性表 L 已经存在。
操作结果:返回 L 中第一个出现数据元素 e 的位置,若数据元素 e 不存在,则返回 0。
PriorElem(L, cur_e, *pre_e)
初始条件:线性表 L 已经存在。
操作结果:若 cur_e 不是 L 的第一个元素,则返回 true 和 cur_e 的前驱(赋值给 pre_e),否则返回 false,这时 pre_e 为空。
NextElem(L, cur_e, *next_e)
初始条件:线性表 L 已经存在。
操作结果:若 cur_e 不是 L 的最后一个元素,则返回 true 和 cur_e 的后继(赋值给 next_e),否则返回 false,这时 pre_e 为空。
ListInsert(*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。
endADT
2.线性表的顺序表示和实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
假设线性表的每个元素需占用个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第
+1个数据元素的存储位置
和第i个数据元素的存储位置
之间满足下列关系:
一般来说,线性表的第个数据元素
的存储位置为:
由于高级程序设计语言中的数组类型也有随机存取的特性,因此,通常都使用数组来描述数据结构中的顺序存储结构。在此,由于线性表的长度可变,且所需最大存储空间随着问题的不同而不同,则在C语言中可用动态分配的一维数组,如下描述:
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef int ElemType ;//数据类型定义
typedef struct {
ElemType *elem; //存储空间基址
ElemType length; //当前长度
ElemType listsize; //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
(1) 顺序表的初始化
在上述定义中,数组指针elem指示线性表的基础地址,length表示当前线性表的长度,Listsize指示顺序表当前分配的存储空间的大小,一旦因为插入元素而空间不足时,可以进行再分配,即为顺序表增加一个大小为存储LISTINCREMENT个数据元素的空间。
Status InitList_Sq(SqList &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
(2)顺序表的插入操作
在这种存储结构中,容易实现线性表的某些操作,如随机存取第i个数据元素等,只是要特别注意的是,C语言中数组的下标从“0”开始,因此,若L是SqList类型的顺序表,则表中的第i个数据元素是L.elem[i-1]。下面讨论线性表的插入和删除两种操作在顺序存储表示时的实现方法。
其大致的原理是,在第i个元素处插入元素,如果i=n+1,则不需要移动元素,如若不然,需要移动元素才能反应这个逻辑关系的变化。一般情况下,在第(1<=i<=n)个元素之前插入一个元素时,需要将第n至第i(共n-i+1)个元素向后移动一个位置,算法如下:
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){ //当前存储空间已满,增加分配
int * newbase=(ElemType*) realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)exit(OVERFLOW);//内存分配失败
L.elem=newbase;//引入新的基址
L.listsize+=LISTINCREMENT;//分配增量
}
int *q=&(L.elem[L.length - 1]);//确定插入位置
for(int *p=&(L.elem[L.length - 1]); p >= q; --p) *(p + 1)=*p;//将元素向后移动
*q=e;//插入元素
++L.length;//表长增1
return OK;
}
(3)顺序表的删除操作
一般情况下,删除 第i个元素时,需将从第i+1至第n个元素依次向前移动一个位置,代码实现如下:
Status ListDelete_Sq(SqList &L,int i,ElemType &e){
if((i<1)||(i>L.length))return ERROR;
int *p=&(L.elem[i-1]);
e=*p;
int *q=L.elem+L.length-1;
for(++p;p<=q;++p)*(p-1)=*p;
--L.length;
return OK;
}
3.线性表的链式表示和实现
(1)线性链表的定义
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的。)因此,为了表示每个数据元素与其直接后继数据元素
之间的逻辑关系,对于数据元素
来说,除了存储本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素
的存储映像,称为结点。它包括两个域:其中存储数据元素信息的域成为数据域;存储直接后继的域成为指针域。指针域中存储的信息称作指针或链。n个结点链结成一个链表,为线性表的链式存储结构。又由于此链表的每个节点中只包含一个指针域,则又称为线性链表或者单链表。
(2)线性链表方法实现
线性链表定义如下:
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
初始化如下:
Status InitList(LinkList *L) {
*L = (LinkList) malloc(sizeof(Node));/*新建新结点作为头结点,用头指针L指向头结点*/
(*L)->next = NULL;/*头结点的指针域置空*/
return OK;
}
后插法:
//后插法
void CreateList_Tail(LinkList &L,LinkList &p,int n)
{
LinkList r;//尾结点
L = new LNode;
L->next = NULL;
r =L;//之所以用尾结点,是因为L是指向头节点的 过L来找到这条单链表的,r是一个代替L移动操作的指针
for ( int i=0; i<n; i++ )
{
p = new LNode;
cin>>p->data;
p->next = NULL;
r->next = p;
r = p;
}
}
前插法:
void CreateList_Head(LinkList &L,LinkList &p,int n)
{
L = new LNode;
L->next = NULL;
for( int i=0; i<n; i++ )
{
p = new LNode;
cin>>p->data;
p->next = L->next;
L->next = p;
}
}
cnblog_test:
031b34f8-8e7a-4ca1-892e-aaabb0795a76
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix