学习 严蔚敏讲数据结构笔记10

150 篇文章 0 订阅
28 篇文章 0 订阅

第五章数组和广义表

5.1 数组的类型定义

5.2 数组的顺序表示和实现

5.3 稀疏矩阵的压缩存储

5.4 广义表的类型定义

5.5 广义表的表示方法

5.6 广义表操作的递归函数

 

1.1  数组的类型定义

//没有记全

ADT Array

{

数据对象:D={aj1,j2…j  |ji=0,…bi-1,i=1,2,…n}

数据关系:R={R1,R2,…Rn}

Ri={<aj}

基本操作:

} ADT Array

基本操作:

InitArray(&A, n, bound1,…,boundn)

DestoryArray(&A)

Value(A, &e, index1,…,indexn)

Assign(&A, e, index1,…,indexn)

 

Value(A, &e, index1,…,indexn)

初始条件:An维数组,e为元素变量,随后是n个下标值。

操作结果:若各个下标不超界,则e赋值为所指定的A的元素值,并返回OK

Assign(&A, e, index1,…,indexn)

初始条件:An维数组,e为元素变量,随后是n个下标值。

操作结果:若下标不超界,则将e的值赋值给所指定的A元素,并返回OK.

 

5.2 数组的顺序表示和实现

类型特点:

1)  只有引用型操作,没有加工型操作

2)  数组是多维的结构,而存储空间是一个一维的结构

有两种顺序映象的方式

1)  以行序为主序(低下标优先)

2)  以列序为主序(高下标优先)

 

行序为主序

二维数组A中任意元素aij的存储位置

LOC[i,j] = LOC[0,0]+(b2*i+j)L 其中LOC[0,0]称为基地址或基址

推广到一般情况,可以得到n维数组数据元素的存储位置

 

5.3稀疏矩阵的压缩存储

假设mn列的矩阵含t个非零元素,则称为稀疏因子,通常认为<=0.05的矩阵为稀疏矩阵。

以常规方法,即以二维数组表示高阶的稀疏矩阵时,产生的问题:

1)  零值元素占的空间很大

2) 计算中进行了很多和零值的运算

解决问题的原则

1) 尽可能少存或不存值为零值元素

2) 尽可能减少没有实际意义的运算

3) 运算方便;即:尽可能快地找到与下标值(i,j)对应的元素;尽可能快地找到同一行或同一列的非零值元。

 

1) 特殊矩阵的压缩存储

例如:三角矩阵 对角矩阵

2) 随机稀疏矩阵的压缩存储

随机矩阵中的非零元分布不规则

1))三元组顺序表

13_001

#define MAXSIZE 12500

typedef struct

{

         int  i,j; //该非零元的行下标和列下标

         ElemType  e;

}Triple; //三元组类型

typedef union

{

         Triple  data[MAXSIZE+1];

         int  mu,nu,tu;

}TSMatrix; //稀疏矩阵类型

求矩阵转置的操作:

用常规的二维数组表示时的算法

for(col = 1; col <= nu; ++ col)

         for(row= 1; row <= mu; ++ row)

                   T[col][row]= M[row][col];

其时间复杂度为O(mu*nu)

14_001

Status FastTransposeSMatrix(TSMatrix M,  TSMatrix &T)

{

         T.mu  = M.nu;

         T.nu  = M.mu;

         T.tu  = M.tu;

         if(T.tu)

         {

                   for(col  = 1; col <= M.nu; ++ col)

                            num[col]  = 0;

                   for(t  = 1; t <= M.tu; ++ t)

                            ++  num[M.data[t].j];

                   cpot[1]  = 1;

                   for(col  = 2; col <= M.nu; ++ col)

                            cpot[col]  = cpot[col-1] + num[col-1];

                   for(p  = 1; p <= M.tu; ++ p)

                   {

                            //转置矩阵元素

                   }//for

         }//if

         return  OK;

}//FastTransposeSMatrix

三元组顺序表又称有序的双下标法,它的特点是,非零元在表中按行序存储,因此便于进行依行顺序处理的矩阵运算。然而,若需随机存取某一行中的非零元,则需从头开始进行查找。

 

二、行逻辑联接的顺序表

修改前述的稀疏矩阵的结构定义,增加一个数据成员rpos,其值在稀疏矩阵的初始化函数中确定。

14_002

#define MAXMN 500

typedef struct

{

         Triple  data[MAXSIZE+1];

         int  rops[MAXMN+1];

         INT  mu,nu,tu;

}RLSMatrix; //行逻辑链接顺序表类型

矩阵乘法的经典算法:

for(i = 1; i <= m1; ++ i)

         for(j= 1; j <= n2; ++ j)

         {

                   Q[i][j]= 0;

                   for(k= 1; k <= n1; ++ k)

                            Q[i][j]+= M[i][k] * N[k][j];

         }

其时间复杂度为:O(m1*n2*n1)

两个稀疏矩阵相乘(Q = M*N

Q初始化

If Q是非零矩阵

{

         //逐行求积

         for(arow= 1; arow < M.mu; ++ arow)

         {

                   //处理M的每一行

                   ctem[]= 0; //累加器清零

                   //计算Q中第arow行的积并存入ctemp[]中;

                   //ctemp[]中非零元压缩存储到Q.data;

         }//forarow

}//if

 

14_003

Status MultSMatrix(RLSMatrixM, RLMatrixN, RLSMartrix &Q)

{

         if(M.nu  != N.mu)

         {

                   return  ERROR;

         }

         Q.mu  = M.mu;

         Q.nu  = N.nu;

         Q.tu  = 0;

         if(M.tu  * N.tu != 0)

         {

                   //Q是非零矩阵

                   for(arow  = 1; arow <= M.mu; ++ arow)

                   {

                            //处理M的每一行

                            //...

                            ctemp[]  = 0; //当前行各元素累加器清零

                            Q.rpos[arow]  = Q.tu + 1;

                            for(p  = M.rpos[arow]; p < M.rpos[arow+1]; ++ p)

                            {

                                     //当前行中每一个非零元

                                     brow  = M.data[p].j;

                                     if(brow  < N.nu)

                                               t  = N.rpos[brow+1];

                                     else

                                               for(q  = N.rpos[brow]; q < t; ++ q)

                                               {

                                                        ccol  = N.data[q].j; //乘积元素在Q中列号

                                                        ctemp[ccol]  += M.data[p].e * N.data[q].e;

                                               }  //for q

                            }  //求得Q中第crow(=arow)行的非零元

                            for(ccol  = 1; ccol <= Q.nu; ++ ccol)

                                     if(ctemp[ccol])

                                     {

                                               if(++  Q.tu > MAXSIZE)

                                                        return  ERROR;

                                               Q.data[Q.tu]  = {arow, ccol, ctemp[ccol]);

                                     }//if

                   }//for  arow

         }//if

         return  OK;

}//MultSMatrix

分析上述算法的时间复杂度

累加器ctemp初始化的时间复杂度为O(M.mu<N.nu),Q的所有非零元的时间复杂度为O(M.tu*N.tu/N.mu),进行压缩存储的时间复杂度为O(M.mu*N.nu),总的时间复杂度就是O(M.mu*N.nu+M.tu*N.tu/N.mu)。若Mmn列的稀疏矩阵,Nnp列的稀疏矩阵,则M中非零元的个数N中非零元的个数

相乘算法的时间复杂度就是

1.      了解数组的两种存储表示方法,并掌握数组以行为主的存储结构中地址计算方法。

2.      掌握对特殊矩阵进行压缩存储时下标变换公式

3.      了解稀疏矩阵的两种压缩存储方法的特点和适用范围,领会以三元组表示稀疏矩阵时进行矩阵运算采用的处理方法。

 

 

第六章树

6.1树的类型定义

6.2二叉树的类型定义

6.3二叉树的存储结构

6.4 二叉树的遍历

6.5 线索二叉树

6.6 树和森林的表示方法

6.7 树和森林的遍历

6.8哈夫曼树与哈夫曼编码

 

6.1树的类型定义

数据对象D

D是具有相同特性的数据元素的集合

数据关系R

D为空集,则称为空树;

否则:

(1)D中存在唯一的称为根的数据元素root

(2)n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,tm,其中每一棵子集本身又是一棵复合本定义的树,称为根root的子树。

基本术语

结点:数据元素+若干指向子树的分支

结点的度:分支的个数

树的度:树中所有结点的度数的最大值

叶子结点:度为零的结点

分支结点:度大于零的结点

从根到结点的路径:由从根到该结点所经分支和结点构成

孩子结点,双亲结点,兄弟结点,祖先结点,子孙结点

结点的层次:假设根结点的层次为1,第L层的结点的子树跟结点的层次为L+1

树的深度:树中叶子结点所在的最大层次

森林:是m(m>=0)棵互不相交的树的集合

任何一棵非空树是一个二元组

Tree=(root,F) 其中:root被称为根结点,F被称为子树森林

 

基本操作:

查找插入删除

查找:

Root(T);

Parent(T,cur_e)

LeftChild(T,cur_e)

RightSibling(T,cur_e)

TreeEmpty(T)

TreeDepth(T);

TraverseTree(T,visit());

Value(T,cur_e);

插入:

InitTree(&T);

CreateTree(&T,definition);

Assign(T,cur_e,value);

InsertChild(&T,&p,i,c);

删除:

ClearTree(&T);

DestoryTree(&T);

DeleteChild(&T,&p,i);

有向树:

1)  有确定的根;

2)  树根和子树根之间为有向关系

有序树和无序树的区别在于:

子树之间是否存在次序关系?

一般情况下讨论无序树

 

和线性结构的比较

线性结构

第一个数据元素(无前驱)

最后一个数据元素(无后继)

其它数据元素(一个前驱,一个后继)

树结构

根结点(无前驱)

多个叶子结点(无后继)

树中其它结点(一个前驱,多个后继)

 

6.2二叉树的类型定义

二叉树或为空树;或是由一个根结点加上两科分别称为左子树和右子树的、互不相交的二叉树组成。

二叉树的物种基本形态

2.4已知:A=(a1,a2,…,an)B=(b1,b2,…bm)均为顺序表,试编写一个比较A,B大小的算法

分析:1.算法的目标是分析两个的大小,则算法中不应当破坏原表;

1.      按题意,表的大小指的是“词典次序”,则不应当先比较两个表的长度

2.      算法中的几百呢操作为:同步比较两个表中相应的数据元素

假设int compare(SqList La, SqlList Lb)

这主要操作为:

if(La.elem[i] == Lb.elem[i])

         i++;

else if(La.elem[i]<Lb.elem[i])

         return-1;

else return 1;

循环条件:(i<=La.length) && (i<=Lb.Length)

循环结束时可能有三种情况

1.i>La.Length && i>Lb.Lengthreturn 0;

2.i<=La.Length && i>Lb.Lengthreturn 1;

3.i>La.Length && i<=Lb.Lengthreturn -1;

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值