软件技术基础线性表.docx

上传人:b****6 文档编号:3270560 上传时间:2022-11-21 格式:DOCX 页数:31 大小:1.08MB
下载 相关 举报
软件技术基础线性表.docx_第1页
第1页 / 共31页
软件技术基础线性表.docx_第2页
第2页 / 共31页
软件技术基础线性表.docx_第3页
第3页 / 共31页
软件技术基础线性表.docx_第4页
第4页 / 共31页
软件技术基础线性表.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

软件技术基础线性表.docx

《软件技术基础线性表.docx》由会员分享,可在线阅读,更多相关《软件技术基础线性表.docx(31页珍藏版)》请在冰豆网上搜索。

软件技术基础线性表.docx

软件技术基础线性表

2.2线性表

2.2.1线性表的定义和运算

一般形式:

L=(a1,a2,…,an)

其中L为线性表,ai(i=1,…,n)是属于某数据对象的元素,n(n≥0)为元素个数称为表长,n=0为空表。

线性表的定义:

L=(D,R)

其中:

D={a1,a2,…,an}

R={|ai-1,ai∈D,2≤i≤n}

若ai-1≥ai,i=2,3,…,n,则称该线性表为有序表,否则称为无序表。

线性表的基本运算:

插入、删除、查找、排序。

2.2.2顺序存储线性表

1.顺序存储结构

2.顺序存储结构的插入、删除运算

插入

INSERTLIST(V,n,i,x)

1.if(i<1)OR((i>n+1)then{参数错return}(i=n+1表示插入在最后)

2.forj=ntoistep(-1)

3.V[j+1]←V[j]

4.end(j)

5.V[i]←x

6.n←n+1

7.return

删除

DELETELIST(V,n,i)

1.if(i<1)OR((i>n+1)then{参数错return}

2.forj=iton-1

3.V[j]←V[j+1]

4.end(j)

5.n←n-1

6.return

2.2.3线性链表

1.链式存储结构

2.线性链表的基本运算

(1)基本操作

设p,q,s均为指针类型变量,指向数据域为data,指针域为next的结点,表2.2表示线性链表的几项基本操作。

(2)结点的动态生成及回收

设具有数据域date,指针域next的空白链表,其头指针为av。

从空白链表中获取一个结点,由指针P指向,其算法为:

GETNODE(P)

1.p←av

2.av←next(av)//修改空白链表头指针//

3.return

回收一个由P指针指向的结点,放回空白链表的算法为:

REP(P)

1.Next(P)←av

2.av←P

3.return

(3)插入运算

INLINKST(head,a,b)

1.GETNODE(p);data(p)←b;//取得一个新结点p//

2.if(head=nil)then{head←p;next(p)←nil;return}//空白情况//

3.if(data(head)=a)then{next(p)←head;head←p;return}//a为头结点//

4.LOOKFOR(head,a,q)//寻找元素a之前的结点q//

5.next(p)←next(q);next(q)←p

6.return

其中LOOKFOR(head,a,q)为在非空链表中寻找包含指定元素a之前的结点q的算法:

LOOKFOR(head,a,q)

1.q←head

2.While(next(q)≠nil)and(data(next(q))≠a)do

3.q←next(q)//如果表中无a结点,则q指向链表最后一个结点//

(4)删除运算

DELINKST(head,a)

1.if(head=nil)then{空表return}//空表情况//

2.if(data(head)=a)then{s←next(head);RET(head);head←s;return}//a为头结点//

3.LOOKFOR(head,a,q)

4.if(next(q)=nil)then{无此结点return}

5.p←next(q);next(q)←next(p)

6.RET(p)

7.return

3.线性链表的其他形式

 

4.应用实例---一元多项式相加

Pn(x)=P0+P1X2+…+Pixi+…+Pnxn

设有一元多项式A(x)和B(x),现要求相加结果C(x)=A(x)+B(x)。

其运算规则为:

将两个多项式中指数相同的项对应系数相加,若和不为零,则构成C(x)中的一项;A(x)和B(x)中所有指数不相同的项均复抄到C(x)中。

用带有头结点的线性链表表示多项式A(x),B(X),设指针ha,hb分别为指向多项式链表A(x),B(X)的头指针,指针p,q的初始位置分别指向A(x),B(x)中第一项,则求A(x)+B(x)的运算过程为:

比较p,q所指结点中的指数项,若EXP(p)EXP(q),则q所指的结点为C(x)中的一项,将q结点插入p结点之前,并将q指针后移一个结点;若EXP(p)=EXP(q),则将两个结点中的系数相加,当和不为零时,修改p结点中的系数,回收q结点;否则删去p结点,同时回收p,q结点。

这一方法实际上是将B(x)加到A(x)中,最后形成C(x),因此C(x)中的结点不需要重新生成。

算法描述如下:

A(x)=5-3x+13x5,B(x)=3x-8x4-6x5+7x8。

(EXP:

exponentCOEF:

coefficient)

ADD-POLY(ha,hb)

1.p←next(ha);q←next(hb)

2.pre←ha;hc←ha

//pre指向p的前趋,为已经算好的多项式的最后一项,为c(x)头指针//

3.while(p<>nil)AND(q<>nil)do

4.case

5.EXP(p)

6.{pre←p;p←next(p)}

7.EXP(p)=EXP(q):

8.{x←COEF(p)+COEF(q);

9.if(x<>0)then{COEF(p)←x;pre←p}

10.else{next(pre)←next(p);RET(p)}

11.p←next(pre);u←q;q←next(q);RET(u)}

12.EXP(p)>EXP(q):

13.{u←next(q);next(q)←p;

next(pre)←q;pre←q;q←u}

14.end(case)

15.end(while)

16.if(q<>nil)thennext(pre)←q

17.RET(hb)//释放多项式B(x)的头结点//

18.return

2.2.4向量和链表的比较(自学)

2.3栈与队

2.3.1栈的结构和运算

1.栈的定义

栈是限定只能在表的一端进行插入和删除操作的线性表。

允许插入或删除的一端称为栈顶(top),另一端称为栈底(bottom),如图所示。

设栈s=(a1,a2,a3,…,an),称a1为栈底元素,an为栈顶元素。

栈中元素按a1,a2,a3,…,an次序入栈,又按an,…,a2,a1次序退栈。

若n=0,则称为空栈。

因此栈又称为“后进先出”(LIFO,lastinfirstout)线性表。

2.顺序栈

s[1:

m]m表示栈允许的最大容量,通常top指示栈顶位置,top=0表示栈空,top=m表示栈满。

PUSF(s,m,top,x)//将元素x入栈//

1.if(top=m)then{‘上溢’,return}

2.top=top+1

3.s[top]=x

4.return

POP(s,top,y)//退栈,将栈顶元素送入y中//

1.if(top=0)then{‘下溢’,return}

2.y=s[top]

3.top=top-1

4.return

 

3.链栈

4.栈的应用

(1)表达式求值

运算符:

**/*+-;

优先数:

322110

两个栈:

操作数(NS),运算符(OS)

首先在OS中放入表达式结束符“;”,然后自左至右扫描表达式。

根据扫描的每一符号作如下不同的处理:

1.若为操作数,将其压入NS栈。

2.若为运算符,需看当前OS的栈顶元素:

.若当前运算符的优先数大于OS的栈顶运算符,则将当前运算符压入OS栈。

.若当前运算符的优先数不大于OS的栈顶运算符,则从NS栈中弹出两个操作数,设为x,y,再从OS中弹出一个运算符,设为θ,由此构成一条机器操作指令:

xθy→T,并将结果T送如NS栈。

.若当前运算符为“;”,且OS栈顶也为“;”,则表示表达式处理结束,此时Ns栈顶元素即为此表达式值。

设表达式A/B**C+D;其求值过程如图所示。

PUSF(s,m,top,x)//将元素x入栈//

1.if(top=m)then{‘上溢’,return}

2.top=top+1

3.s[top]=x

4.return

POP(s,top,y)//退栈,将栈顶元素送入y中//

1.if(top=0)then{‘下溢’,return}

2.y=s[top]

3.top=top-1

4.return

表达式求值的算法如下:

EXP(OS,topO,NS,topN)//topO,topN为OS,NS

栈顶指示器,初态为零//

1.PUSH(OS,topO,';')

2.t←0//t=0表示扫描下一个符号//

3.while(t<>2)do

4.if(t=0)thenread(w)//w中存放当前读入符号//

5.if(w为操作数)thenPUSH(NS,topN,w)

6.else

7.{POP(OS,topO,q)//查看当前OS栈顶元素q//

8.if(w>q)then{PUSH(OS,topO,w),t←0}

8.else

9.if(q=';')and(w=';')then

10.{POP(NS,topN,z),t←2}//t=2表示处理结束//

10.else

POP(NS,topN,x)POP(NS,topN,y)

13.POP(OS,topO,q);x←yqx;

//构成一条机器指令//

14.PUSH(NS,topN,x);t←1}

//t=1表示继续处理当前符号//

15.}

16.end(while)

17.return

其中TOP(OS,topO,q)为读栈顶元素,算法如下:

TOP(s,top,x)

1.if(top=0)then{'栈空',return}

2.x←s[top]

2.return

(2)过程嵌套和递归调用

1(n=1,2)

Fib(n)=

Fib(n-1)+Fib(n-2)(n>2)

Fibonacci序列

Fib(n)

1.if(n=1)or(n=2)thenFib←1

2.elseFib←Fib(n-1)+Fib(n-2)

3.return

 

D3,3

D4,3

D2,4

D2,4

D2,4

D2,4

D2,4

D5,4

D7,7

D8,3

D1,5

D1,5

D1,5

D1,5

D1,5

D1,5

D1,5

D1,5

D1,5

D6,5

D6,5

D6,5

D6,5

D6,5

(3)回溯求解算法

设有n件体积分别w1,w2,…wn的物品和一个能装载总体积为T的背包,要求从n件物品中挑选出若干件物品,其体积之和恰好装满背包。

W[1:

n]存放n件物品的体积

S[1:

n]存放放入背包内物品的序号

T为背包能容纳的体积,

I为待选物品序号

每进栈一件物品,就从T中减去该物品的体积,若T-W[i]>=0,则该物品可选,若T-W[i]<0,则该物品不可选,若i>n,则需退栈,若此时栈空,则说明无解。

算法如下:

 

PACK(T,n,W,S,top)

1.top←0;i←1

2.while(T>0)and(i<=n)do

3.if(T-W[i]=0)or((T-W[i]>=0)and(i

then

{top←top+1;s[top]←i;T←T-W[i]}

if(T=0)then{'背包有解'return}

else{if(i=n)and(top>0)then//取

出栈顶物品//

{i←s[top];top←top-1,T←T+W[i]}

i←i+1//准备挑选下一件物品//}

4.end(while)

5.'背包无解'return

2.3.2队的结构和运算

1.队的定义

只允许在一端进行插入,在另一端进行删除的线性表。

插入端:

队尾(rear)

删除端:

排头(front)

用移动rear与front指示器来进行插入和删除

称队为先进先出(FIFO,firstinfirstout)线性表。

1.顺序队

Q[1:

m]存放队列元素

m:

允许的最大容量。

初始状态:

front=rear=0,队空

假溢出:

入队时rear增1,出队时front增1,当front=rear时队空,当rear=m时无法再继续入队,但此时队中空间并不一定满(只是当rear-front=m时才真正为满)

循环队列:

存放队列的数组形成头尾相接的环形。

设CQ[0:

m-1]表示最大容量的循环队列,其中头、尾指示器(front,rear)均按顺时针方向前进,rear=front=m-1为初态。

循环队列的插入和删除算法如下:

ADDCQ(CQ,m,front,rear,x)//将x插入队列CQ中//

1.rear←(rear+1)modm//mod为模除运算,保证rear循环计数//

2.if(front=rear)then{'队满'return}

3.CQ[rear]←x

4.return

DELCQ(CQ,m,front,rear,y)//删除队首元素送入y中//

1.if(front=rear)then{'队空'return}

2.front←(front+1)modm

3.y←CQ[front]

4.return

为了辨别队满与队空,循环队列中永远会空一个位置。

3.链队

当队的容量无法预先估计时,可以采用链表作存储结构,称为链队。

链队的插入、删除算法如下:

ADDLINK(rear,front,x)//在链队中插入x结点//

1.GETNODE(p)

2.data(p)←x;next(p)←nil//设置新的队尾元素//

3.next(rear)←p;rear←p//设置新的队尾指针//

4.return

DELLINK(front,rear,y)//删除排头元素赋给y//

1.if(rear=front)then{'队空'return}

2.y←data(next(front));

next(front)←next(next(front))//删除排头结点,把头结点链向下一个结点//

3.if(next(front)=nil)thenrear←front

4.return

 

4.队的应用

1.划分子集问题

已知集合A={a1,a2,…,an},并已知此集合上的关系R={(ai,aj)|ai,aj∈A,i≠j},其中(ai,aj)表示ai与aj之间存在冲突关系。

现要求将A划分成互不相交的子集A1,A2,…,Ak(k≤n),使任何子集的元素均无冲突关系,同时要求划分子集的个数尽可能少。

这类问题可以有各种实际应用背景,例如在安排运动会比赛日程时,需要考虑如何安排比赛项目,才能使同一运动员参加的不同项目不在同一日进行,同时又使比赛总的日程最短。

如运动会共设9个比赛项目,规定每个运动员最多可以参加三个项目,则

A={1,2,3,4,5,6,7,8,9}

R={(2,8),(9,4),(2,9),(2,1),(2,5),(6,2),(5,9),(5,6),(5,4),(7,5),(7,6),(3,7),(6,3)}

可行的子集划分为:

A1={1,3,4,8}A2={2,7}A3={5}A4={6,9}

算法思想:

采用循环筛选的方法,先以第一个元素开始,凡与第一个元素无冲突的元素划归一组,再将剩下的元素重新找出互不冲突的划归第二组,以此类推,直到所有的元素都进组。

在计算机实现时,首先要将集合中元素的冲突关系设置一个冲突矩阵,由一个二维数组R[1:

n,1:

n]表示,若第i与第j元素有冲突,则R[i,j]=1,否则R[i,j]=0。

对应于上述例子的关系矩阵见图

循环队列cq[0:

n-1],存放集合A的元素;数组Result[1:

n]用以存放每个元素的分组号;newr[1:

n]为工作数组。

以上述例子来说明工作过程:

初试状态:

集合A元素放入cq中,Result及newr置零,设置组号group=1。

如图 (a)所示。

当第1个元素出队时。

将R矩阵中第1行元素中的“1”拷入newr向量对应位置,得到:

凡是与第一元素有冲突的元素处均置为“1”。

这里说明序号为2的元素不能进入第一组,则应将元素2出队后重新入cq的队尾。

继续将元素3出队,并将R矩阵中第三行元素中的“1”拷入newr向量对应位置,得到:

如此继续,直到9个元素依次出队后,由newr单元中为“0”的单元序号构成第1组,将“1”标志放入Result向量对应单元中,见图(b)。

将group=2,newr清零,重新对cq中剩余的元素重复上述操作,可得第2组元素,第3组元素……直到cq中front=rear,队空,运算结束(见图(c),(d),(e))。

PROCEDUREDIVISION(R,n,cq,newr,Result);

FORk=0TOn-1cq[k]←k+1;//n个元素存入循环队列cq//

front←n-1;rear←n-1;//头尾指针赋初值//

FORK=1TOnnewr[k]←0//newr向量置初值//

group←1;pre←0;//group为当前组号,pre为前一个出队元素编号,初值为零//(pre←9);

fi=.t.

WHILErear≠front.or.fi=.t.DO//队列非空//

Fi=.f.

front←front+1;IFfront=n+1THENfront←1;

I←cq[front];//I为当前出队元素//

IFI

THEN//重新开辟新组//

group←group+1;Result[I]←group;//记录组号//

FORk=1TOnnewr[k]←R[I,k]

ELSE

IFnewr[I]≠0

THEN//发生冲突元素,重新入队//

rear=rear+1;IFrear=n+1THENrear=1;

cq[rear]←I

ELSE//可以分在当前组//

Result[I]←group;

FORk=1TOn

Newr[k]←newr[k]+R[I,k];

pre←I

END(WHILE);

 

cq[k]Result[I]

 

 

1

2

3

4

5

6

7

8

9

0

1

0

0

0

0

0

0

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

9

 

2.4数组

2.4.1数组的定义

一个m行n列的数组可以表示为

2.4.2数组的顺序存储结构

1.按行优先顺序存放

假设每个元素仅占一个单元地址,则元素aij的存储地址可以通过以下关系式计算:

二维数组:

Loc(aij)=Loc(a11)+(i-1)*n+(j-1)

(1≦i<≦m,1≦j<≦n)

三维数组:

Loc(aijk)=Loc(a111)+(i-1)*m*n+(j-1)*n+(k-1)

(1≦i≦l,1≦j<≦m,1≦k≦n)

2.按列优先顺序存放

二维数组:

Loc(aij)=Loc(a11)+(j-1)*m+(i-1)

(1≦i<≦m,1≦j<≦n)

三维数组:

Loc(aijk)=Loc(a111)+(k-1)*l*m+(j-1)*l+(i-1)

(1≦i<≦l,1≦j<≦m,1≦k<≦n)

3.特殊矩阵的存放方式

(1)下三角阵的存储方式

设下三角阵An,n为

若将其中非零元素按行顺序存放为

{a11,a21,a22,a31,a32,…an1,an2,…,ann}

从第1行至第i-1行的非零元素个数为

因此求取其中非零元素aij的地址可按下列公式计算:

Loc(aij)=Loc(a11)+i(i-1)/2+(j-1)

(1≦j≦i≦n)

(2)三对角阵的存储方式

设An,n为三角阵:

若将其中非零元素按行顺序存放为

{a11,a12,a21,a22,a23,a32,a33,a34,…an,n-1,ann}

求取其中非零元素aij地址的关系式为:

Loc(aij)=Loc(a11)+(i-1)*2+(j-1)[Loc(a11)+3(i-1)-1+j-(i-2)-1]

(i=1,j=1,2或i=n,j=(n-1),n或1

2.4.3稀疏矩阵

1.三元组表示

用三元组表示为(A阵)

1

1

3

1

5

7

2

3

-1

3

1

-1

3

2

-2

5

4

2

转置后的B阵

1

1

3

1

3

-1

2

3

-2

3

2

-1

4

5

2

5

1

7

 

TRANSMAT(A,B)

1.if(tu<>0)then

2.{q←1//q为转置以后B的行号//

3.forcol=1ton

4.forp=1totu//p为转置前A的行号//

5.ifA[p].j=colthen

6.{B[q].i←A[p].j;B[q].j←A[p].i;

7.B[q].v←A[p].v;q←q+1]

8.end(p)

9.end(col)}

11.return

2.带辅助向量的三元组表示

设两个辅助向量POS和NUM满足下列关系:

POS

(1)=1

POS(i)=POS(i-1)+NUM(i-1),2≤i≤m

POS(i)表示稀疏矩阵中第i行的第一个非零元素在三元组中的行号;

NUM(i)表示稀疏矩阵中第i行的非零元素个数。

稀疏矩阵A对应的POS与NUM向量值如下:

i

12345

POS

13466

NUM

21

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1