目录
2.5线性表的链式表示和实现
一.线性表的链式表示
1.基本概念
(1)用一组物理欸之任意的储存单元来存放线性表的数据元素
(2)这组储存单元既可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的。
(3)链表中的元素的逻辑次序和物理次序不一定相同
2.组成
各结点由两个域组成:
数据域:存储元素数值数据
指针域:存储直接后继结点的存储位置
3.与链式存储有关的术语
(1)结点:数据元素的存储映像。由数据域和指针域两部分组成
(2)链表:n个结点由指针链组成一个链表。
他是线性表的链式存储映像,称为线性表的链式存储结构
4.单链表
结点只有一个指针域的链表,称为单链表或者线性链表
5.双链表
结点有两个指针域的链表,称为双链表
6.循环链表
首尾相接的链表称为循环链表
7.头指针,头结点和首元结点
头结点:是指向链表中第一个结点的指针
首元结点:是指链表中存储第一个数据元素a1的结点
头结点:是在链表的首元结点之前附设的一个结点
8.存储结构的两种形式
- 不带头结点的
- 带头结点的
9.如何表示空表
- 无头结点时,头指针为空时表示空表
- 有头结点时,当头结点的指针域为空时表示空表
10.链表中设置头结点有什么好处
(1)便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无须进行特殊处理。
(2)便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。
11.头结点的数据域内装什么
头结点的数据域可以为空,也可以存放线性表长度等附加信息,但此结点不能计入链表长度值
12.链表(链式存储结构)的特点
(1)结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
(2)访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等。
向后顺序扫描其余结点:这种存取元素的方法被称为顺序存取法
2.5.1单链表的定义和表示
一.带头结点的单链表
1.带头指针的单链表
单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名若头指针名是L,则把链表称为表L。
2.单链表的存储结构
typedef struct Lnode{ //声明结点的类型和指向结点的指针类型
ElemType data; //结点的数据域
struct Lnode *next; //结点的指针域 嵌套类型的指针
}Lnode,*LinkList; //LinkList为指向结构体Lnode的指针类型
- 为了统一链表的操作,通常这样定义:
typedef Struct{
char num[8];
char name[8];
int score;
}ElemType;
typedef struct Lnode{
ElemType data; //数据域
struct Lnode*next; //指针域
}Lnode,*LinkList;
2.5.2单链表基本操作的实现
一.单链表的初始化(带头结点的单链表)
1.构造一个空表
Status lnitList_L(LinkList&L){
L=new LNode; //或c语言:L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
return OK;
}
(LinkList&L):typedef struct Lnode{
ElemType data;
struct Lnode*next;
}LNode,*LinkList;
二.补充单链表的几个常用简单算法
1.判断链表是否为空
int ListEmpty(LinkList L){ //若L为空表,则返回1,否则返回0
if(L->next) //非空
return 0;
else
return 1;
}
2.单链表的销毁
(1)算法思路:从头结点开始,依次释放所有结点
(2)指针怎样指向下一个结点:L=L->next
Status DestroyList_L(LinkList&L){
Lnode&p; //或LinkList p;
while(L){
p=L;
L=L->next;
delete p;
}
return OK;
}
3.清空链表
(1)算法思路:依次释放所有结点,并将头结点指针域设置为空
Status ClearList(LinkList&L){ //将L重置为空表
Lnode*p,*q; //或LinkListp,q;
p=L->next;
while(p){ //没有表尾
q=p->next;
delete p;
p=q;
}
L->next=NULL; //头结点指针域为空
return OK;
}
4.求单链表的表长
int ListLength_L(LinkList L){
LNode *p;
p=->next;
i=0;
while(p){
i++;
p=p->next;
}
return i;
}
5. 取值——取单链表中第i个元素的内容
(1)算法思路:从链表的头指针出发,顺着链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。
Status GetElem_(LinkList L,int i,ElemType&e){
p=->next;j = 1; //初始化
while(p&&j<i){ //向后扫描,直到p指向第i个元素或p为空
p=p->next;++i;
}
if(!p||j>i)return ERROR; //第i个元素不存在
e=p->data; //取第i个元素
return OK;
}//GetElem_L
6.查找——根据指定数据获取该数据所在位置(地址)
Lnode*LocateElem_L(LinkList L,Elemtype e){
//在线表L中查找值为e的数据元素
//找到,则返回L中值为e的数据元素的地址,查找失败返回null
p=->next;
while(p&&p->data!=e)
p=p->next;
return p;
}
//在线性表L中查找值为e的数据元素的位置序号
int LocateElem_L(LinkList L,Elemtype e){
//返回L中值为e的数据元素的位置序号,查找失败返回0
p=L->next;j=1;
while(p&&p->data!=e)
{p=p->next;j++;}
if(p)return j;
else return 0;
}
7.插入——在第i个结点前插入值为e的新结点
//在L中第i个元素之前插入数据元素e
Status Listlnsert_L(LinkList &L,int i,ElemType e){
p=L;j=0;
while(p&&j<i-1){p=p->next;++j;} //寻找第i-1个结点,p指向i-1结点
if(!p||j>i-1)return ERROR; //i大于表长+1或者小于1,插入位置非法
s=new LNode;s->data=e; //生产新结点s,将结点s的数据域置为e
s->next=p->next; //将结点s插入L中
p->next=s;
return OK;
}//Listlnsert_L
8.删除——删除第i个结点
//将线性表L中第i个数据元素删除
Status ListDelete_L(LinkList&L,int i,ElemType &e){
p=L;j=0;
while(p->next&&j<i-1){p=p->next;++j} //寻找第i个结点,并令p指向其前趋
if(!(p->next)||j>i-1)return ERROR; //删除位置不合理
q=p->next; //临时保存被删结点的地址以备释放
p->next=q->next; //改变删除结点前驱结点的指针域
e=q->data; //保存删除结点的数据域
delete q; //释放删除结点的空间
return OK;
}//ListDelete_L
9.单链表的建立:头插法——元素插在链表头部
void CreateList_H(LinkList &L,int n){
L=new LNode;
L->next=NULL; //先建立一个带头结点的单链表
for(i=n;i>0;--i){
p=new LNode; //生成新结点
cin>>p->data; //输入元素值scanf(&p->data);
p->next=L->next; //插入到表头
L->next=p;
}
}//CreateList_H
10.尾插法
void CreateList_R(LinkList&L,int n){
L=new LNode; L->next=NULL;
r=L; //尾指针r指向头结点
for(i=0;i<n:++i){
p=new LNode;cin>>p->data; //生产新结点,输入元素值
p->next=NULL;
r->next=p; //插入到表尾
r=p; //r指向新的尾结点
}
}//CreateList_R