利用线性表来解决多个问题1文档格式.docx
《利用线性表来解决多个问题1文档格式.docx》由会员分享,可在线阅读,更多相关《利用线性表来解决多个问题1文档格式.docx(24页珍藏版)》请在冰豆网上搜索。
对于非空的线性表,有且仅有一个开始结点a1,它没有直接前趋,而仅有一个直接后继a2;
有且仅有一个终端结点an,它没有直接后继,而仅有一个直接前趋an-1;
其余的内部结点ai(2≤i≤n-1)都有且有一个直接前趋ai-1和一个直接后继ai+1。
常见的线性表的基本运算有如下六种:
(1)InitList(L)
构造一个空的线性表L,即表的初始化。
(2)ListLength(L)
求线性表L中的结点个数,即求表长。
(3)GetNode(L,i)取线性表L中的第i个结点,这里要求1≤i≤ListLength(L)
(4)LocateNode(L,x)在L中查找值为X的结点,并返回该结点在L中的位置。
若L中有多个结点的值的X相同,则返回首次找到的结点位置;
若L中没有结点的值为X,则返回一个特殊值表示查找失败。
(5)InsertList(L,x,i)
在线性表L的第I个位置上插入一个值为X的新结点,使得原编号为i,i+1,...,n的结点变为编号为i+1,i+2,...,n+1的结点。
这里1≤i≤n+1,而n是原表L的长度。
插入后表L的长度加1.
(6)DeleteList(L,i)
删除线性表L的第i个结点,使得原编号为i+1,i+2,...,n的结点变成编号为i,i+1,...,n-1的结点。
这里1≤i≤n,而是原表L的长度。
删除后表L的长度减1.
2.2线性表的顺序存储结构
结点ai的存储地址Loc(ai)=Loc(a1)+(i-1)*c1≤i≤n
我们用结构类型来定义顺序表类型
#defineListSine100//表空间的大小可根据实际需要而定,这里假设为100
TypedefDataType;
//DataType的类型可根据实际情况而定,这里假设为int
Typedefstruct{
DataTypedata[ListSize];
//向量Data用于存放表结点
Intlength;
//当前的表长度
}Seqlist;
在上述定义中线性表的开始结点a1和终端结点分别存储在L->
data[0]和L->
data[l->
length-1]中。
2.2.2顺序表上实现的基本运算
1.插入线性表的插入运算是指在表的第i个(1≤i≤n+1)个位置上,插入一个新结点X,
使长度为n的线性表:
(a1,…,ai-1,ai,…,an)变为长度为n+1的线性表:
(a1,…,ai-1,x,ai,an)用顺序表作为线性表的存储结构时,由于结点的物理顺序必须将表中位置n,n-1,…,i上的结点,依次后移到位置n+1,n,…,i+1上,空出第i个位置,然后在该位置上插入新结点X.仅当插入位置i=n+1时,才无须移动结点,直接将X插入表的未尾.
其插入过程如下见图,具体算法描述如下:
a2
...
ai-1
ai
ai+1
an
1
i-1
插入
X
i
n
ListSize-1
后移后
a1
an-1
X
插入后
插入前
程序如下:
VoidInsertList(SeqList*L,DataTypeX,inti)
{//将新结点x插入L所指的顺序表的第i个结点ai的位置上
Intj;
If(i<
1||i->
Length+1)
Error("
positionerror"
);
//非法位置,退出运行
If(L->
Length>
=ListSize)
overflow"
//表空间溢出,退出运行
for(j=L->
Length-1;
j>
=i-1;
j--)
L->
data[j+1]=L->
data[j];
//结点后移
data[i-1]=x;
//插入x
Length++;
//表长加1
}
2.删除
线性表的删除运算是指将表的第i个(1≤i≤n)个结点删去,使长度为n的线性表
(a1,…,ai-1,ai,…,an)变成长度为n-1的线性表(a1,…,ai-1,ai,…,an)和插入运算类似,在
顺序表上实现删除运算也必须移动结点,才能反映出结点间逻辑关系的变化.若i=n,则只要简单地删除终端结点,无须移动结点;
若1≤i≤n-1;
则必须将表中位置i+1,i+2,…n上的结点,依次前移到位置i,i+1,i+2,…n-1上,以填补删除操作造成的空缺.
具体算法如下:
VoidDeteList(Seqlist*L,inti)
{//
Inti;
1||L->
length)
positionerror"
//
for(j=1;
j<
=L->
length-1;
j++)
data[j-1]=L->
Length--;
//表长减少
3.单链表的描述
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始点。
同时,由于终端结点无后继,故终端结点的指针域为空,即NULL(也可用^表示)。
单链表由头指针惟一确定,因此单链表可以用头指针(head)的名字来命名。
例如,线性表(bat,cat,eat,fat,hat,jat,lat,mat)的单链表示意图可用箭头链接起来表示为:
单链表的一般图示法
用C语言描述的单链表如下:
typedefcharDataTpye;
//假设结点的数据域类型是字符
typedefstructnode{//结点类型定义
DataTypedata;
//结点的数据域
structnode*next;
//结点的指针域
}ListNode;
TypedefListNode*LinkList;
ListNode*p;
LinkListhead;
3.2单链表的插入
(1)头插法建表
从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表和表头上,直到读入结束标志为止。
具体算法如下:
LinkListCreateListF(void)
{//返回单链表的头指针
charch;
LinkListhead;
//头指针
ListNode*s;
//工作指针
head=NULL;
//链表开始为空
ch=getchar();
//读第1个字符
while(ch!
=’\n’){
s=(ListNode*)malloc(sizeof(ListNode));
//生成新结点,对应图中的①
s->
data=ch;
//将读入的数据放入新结点的数据域中,对应图中的②
next=head;
//对应图中的③
head=s;
//对应图中的④
//读入下一字符
}
returnhead;
//返回头指针
(2)尾插法建表
该方法是将新结点插到当前链表的表尾上,为此必须增加一个尾指针r,使其始终指向当前链表的表尾。
生成结点的顺序与输入顺序一致。
建成表算法如下:
LinkListCreateListR(void)
{
charch;
ListNode*s,*r;
r=NULL;
//链表初值为空,尾指针初值为空
while((ch=getchar())!
=’\n’){
s=(ListNode*)malloc(sizeof(ListNode));
//对应下图①
//对应下图②
if(head=NULL)
//新结点插入空表
else
r->
next=s;
//新结点插入非空表尾结点*r之后,对应下图③
r=s;
//尾指针指向新表尾,对应图④
}//endofwhile
if(r!
=NULL)
next=NULL;
//对于非空表,将尾结点指针域置空
在链表的开始结点之前附加一个结点(head),并称为头结点,将带来两个优点:
1由于开始结点的位置被存放在头结点的指针域中,所以在链表的第一个位置的操作就和在表的其它位置的操作一样,无须进行特殊处理。
2无论表是否为空,其头指针是指向头结点的非空指针,因此,空表和非空表的处理也就统一了。
引入头结点后,尾插法建链表的算法可简化为:
LinkListCreateListR1(void)
{
LinkListhead=(LinkList)malloc(sizepof(ListNode));
//生成头结点
ListNode*s,*r;
r=head;
//尾指针初值亦指向头结点
while((ch=getchar())!
=‘\n’){
s=(ListNode*)malloc(sizeof(ListNode));
//终端结点的指针域置空,或空表的头结点指针域置空
上述算法中申请新结点的处理应为:
s=(ListNode*)malloc(sizeof(ListNode))
if(s==NULL)//动态分配空间失败
Error(“Nospacefornodecanbeobtained”);
//退出运行
//以下按正常情况处理
2、单链表的查找运算
(1)按序号查找
链表不是随机存取结构,所以在链表中,即使知道被访问结点的序号,也不能像顺序表那样直接按序访问,而只能从链表的头指针开始,顺链域逐个查找直到找到为止。
如:
单链表的长度为n,要查找表中第i个结点,仅当1≤i≤n时,i值是合法的。
当计数器j与