Transcript Document

数据结构课程的内容
线性结构(线性表、栈、队列、串、数组)
逻辑结构
树形结构
非线性结构 图(网)状结构
数据
结构
顺序存储
物理(存储)结构
链式存储
数据运算 (插入、删除、修改、查找、排序)
运算的实现依赖于存储结构
第二章 线性表
一、教学内容:
1、线性表的定义和性质及基本运算;
2、线性表的顺序存储结构
3、线性表的链式存储结构
4、多项式的代数运算
第二章 线性表
二、教学要求:
1、掌握线性结构特点,了解线性表的抽象数据类
型定义;
2、熟练掌握两种存储结构的描述方法。链表是本
章的重点和难点。
3、熟练掌握顺序表的定义与实现,包括查找、插
入、删除算法的实现;
4、熟练掌握在各种链表结构中实现线性表操作的
基本方法,能在实际应用中选用适当的链表结构;
5、能够从时间和空间复杂度的角度综合比较线性
表两种存储结构的不同特点及其适用场合。
第二章 线性表
2.1 线性表的类型定义
2.2 线性表的顺序表示和实现
2.3 线性表的链式表示和实现
2.4 应用举例
2.1 线性表的类型定义
线性表的定义:是n个数据元素的有限序列
(a1, a2, … ai-1,ai, a i+1 ,…, an)
数据元素
线性起点
下标,是元素
的序号,表示元
素在表中的位置
ai的直接前趋 ai的直接后继
n=0时称为 空表
线性终点
n为元素总个
数,即表长
例
例
分析26 个英文字母组成的英文表
( A, B, C, D, …… , Z)
数据元素都是字母; 元素间关系是线性
分析学生情况登记表
学号
姓名
性别
2001011810205
于春梅
女
18
2001级电信016班
2001011810260
何仕鹏
男
18
2001级电信017班
2001011810284
王 爽
女
18
2001级通信011班
2001011810360
王亚武
男
18
2001级通信012班
:
:
:
数据元素都是记录;
年龄
:
班级
:
元素间关系是线性
同一线性表中的元素必定具有相同特性
2.1 线性表的类型定义
从以上例子可看出线性表的逻辑特征是:
 在非空的线性表,有且仅有一个开始结点a1,它
没有直接前趋,而仅有一个直接后继a2;
 有且仅有一个终端结点an,它没有直接后继,而
仅有一个直接前趋a n-1;
 其余的内部结点ai(2≦i≦n-1)都有且仅有一个直
接前趋a i-1和一个直接后继a i+1。
 线性表是一种典型的线性结构。
数据的运算是定义在逻辑结构上的,而运算
的具体实现则是在存储结构上进行的。
2.1 线性表的类型定义
线性表的抽象数据类型的定义:
ADT List{
数据对象:D={ai|ai∈Elemset,i=1,2,…,n,n≥0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}
基本操作:
InitList(&l)
操作结果:构造一个空的线性表L
DestroyList(&l)
初始条件:线性表已存在
操作结果:销毁线性表L
ClearList(&l)
初始条件:线性表已存在
操作结果:置线性表L为空表
ListEmpty(L)
初始条件:线性表已存在
操作结果:若线性表L为空表,则返回TRUE,否则返回
FALSE
ListLenght(L)
初始条件:线性表已存在
操作结果:返回线性表L数据元素个数
GetElem(L,i,&e)
初始条件:线性表已存在(1≤i≤ListLenght(L))
操作结果:用e返回线性表L中第i个数据元素的值
locatElem(L,e,comare())
初始条件:线性表已存在,comare()是数据元素判定函数
操作结果:返回线性表L中第1个与e满足关系comare()的数
据元素的位序
PriorElem(L,cur_e,&pre_e)
初始条件:线性表已存在
操作结果:若cur_e是线性表L的数据元素,且不是第一个,
则用pre_e返回它的前驱,否则操作失败,pre_e无定义
NextElem(L,cur_e,&)
初始条件:线性表已存在
操作结果:若cur_e是线性表L的数据元素,且不是第最后一
个,则用next_e返回它的后继,否则操作失败,next_e无定义
ListInsert(&L,i,e)
初始条件:线性表已存在(1≤i≤ListLenght(L)+1)
操作结果:在线性表L中第i个数据元素之前插入新元素
e,L长度加1
ListDelete(&L,i,&e)
初始条件:线性表已存在(1≤i≤ListLenght(L))
操作结果:删除线性表L中第i个数据元素,用e返回其
值,L长度减1
ListTraverse(L,visit())
初始条件:线性表已存在
操作结果:依次对线性表L的每个数据元素调用visit()
函数,一旦visit()失败,则操作失败
}ADT List
2.1 线性表的类型定义
复杂的操作可用基本操作实现。
例2-1 利用两个线性表LA和LB分别表示两个
集合A和B,现要求一个新的集合A=A∪B。
算法思想:扩大线形表LA,将存在于线形表
LB中而不存在于线形表LA中的数据元素插入
到线形表LA中。
算法细化后得到下列三步操作:
1、从线性表LB中依次取得每个数据元素:
GetElem(LB,i)->e
2、依值在线性表LA中进行查访:
LocateElem(LA,e,equal())
3、若不存在,则插入之:
ListInsert(LA,n+1,e)
最后用类C语言描述为:
void union(List &La,List Lb)
{//La=La+Lb
la-len=ListLength(La);
lb-len=ListLength(Lb);
for(i=1;i<=lb-len;i++)
{
GetElem(Lb,I,e);
if(!LocateElem(La,e,equal))
ListInsert(La, ++la-en,e);
}
}
例2-2
已知一个非纯集合B,试构造一个纯
集合A,使A中只包含B中所有值各不相同
的数据元素。
算法描述为:
void purge(List &La,List Lb)
{//构造一个纯集合La,使La中只包含非纯集合Lb中所有
值各不相同的数据元素。
InitList(La);
la-len=ListLength(La);
lb-len=ListLength(Lb);
for(i=1;i<=lb-len;i++)
{
GetElem(Lb,i,e);
if(!LocateElem(La,e,equal))
ListInsert(La, ++la-en,e);
}
}
例2-3
已知一个有序非纯集合B,试构造一
个纯集合A,使A中只包含B中所有值各不
相同的数据元素。
算法描述为:
void purge(List &La,List Lb)
{//
InitList(La);
la-len=ListLength(La);
lb-len=ListLength(Lb);
for(i=1;i<=lb-len;i++)
{
GetElem(Lb,i,e);
if(ListEmpty(La)||!equal(en,e))
{
ListInsert(La, ++la-en,e);
en=e;
}
}
}
例2-4
有线性表LA和LB,其元素均按非递减有序排列,
编写一个算法将它们合并成一个线性表LC,且LC
的元素也是按非递减有序排列。
算法思路:依次扫描通过LA和LB的元素,比较当
前的元素的值,将较小值的元素赋给LC,如此直
到一个线性表扫描完毕,然后将未完的那个顺序
表中余下部分赋给LC即可。LC的容量要能够容纳
LA、LB两个线性表相加的长度。
算法描述 为:
void MergeList(List la,List lb,list &lc)
{ IninList(lc); i=j=1;k=0;
la_len=ListLength(la);lb_len=ListLength(lb);
while(i<=la_len&&j<=lb_len)
{GetElem(la,i,ai);GetElem(lb,j,bj);
if(ai<=bj){ListList(lc,++k,ai);i++;}
else {ListInsert(lc, ++k,bj);j++;}
}
while(i<=la_len)
{GetElem(la,i++,ai);ListInsert(lc, ++k,ai);}
while(j<=lb_len)
{GetElem(lb,j++,bj);ListInsert(lc, ++k,bj);}
}
2.2 线性表的顺序表示和实现
线性表的顺序表示又称为顺序存储结构或顺
序映像。
用一组地址连续的存储单元依次存储线性表
中的数据元素。
a1
a2
...
ai-1
ai
ai+1
...
an
线性表的起始地址,称作线性表的基地
址
2.2 线性表的顺序表示和实现
用LOC(a1)、LOC(a2)、LOC(ai)分别表示第
1个、第2个和第i个数据元素的存储位置,用L表示
每个数据元素需占用的存储单元,则有:
LOC(a2)=LOC(a1)+L
LOC(ai)=LOC(a1)+(i-1)×L
所有数据元素的存储位置均取决于第一个数
据元素的存储位置。所以线性表的顺序存储结构是
一种随机存取的存储结构。
线性表的顺序存储结构定义(静态)
#define List_Maxsize 100
typedef struct
{
ElemType elem[List_Maxsize];
int length;
}SqList;
线性表的顺序存储结构定义(动态)
#define List_Init_size 100
#define Listincrement 10
typedef struct
{ ElemType *elem;
int length;
int listsize;
}SqList;
顺序表基本运算的实现
1、初始化
Status InitList_Sq(Sqlist &L)
{
L.elem=(ElemType *)
malloc(List_init_size*sizeof(ElemType));
if (!L.elem) exit (overflow);
L.length=0;
L.listsize=List_init_size;
return OK;
}
2、插入 在线性表的第i个位置前插入一个元素
长度为n的线性表变为长度为n+1的线性表
(a1,a2,…,ai-1,ai,…,an)
(a1,a2,…,ai-1,x,ai,…,an)
实现步骤:
• 将第n至第i 位的元素向后移动一个位置;
• 将要插入的元素写到第i个位置;
• 表长加1。
注意:事先应判断: 插入位置i 是否合法?表是
否已满?
插入算法:
Status ListInsert_sq(SqList &L, int i, Elemtype x)
{
if (i<1||i>L.length+1) return ERROR;
if (L.length>=L.listsize)
return OVERFLOW;
for(j=L.length;j>=i;j--)
L.elem[j]=L.elem[j-1];
L.elem[j]=x;
L.length++;
return(OK);
}
插入算法分析:
上述算法for循环语句的执行次数为n-i+1;
若i=1,需移动全部n个结点(最坏:O(n))
若i=n+1(在表尾插入),无需用移动结点,
直接插入即可。(最好O(1))
移动结点的平均次数:
按等概率考虑:
可能的插入位置为i=1,2,……n,n+1共n+1个,
则pi=1/(n+1)
所以
顺序表插入算法平均约需移动一半结点。
3、删除 删除线性表的第i个位置上的元素
长度为n的线性表变为长度为n-1的线性表。
(a1,a2,…,ai-1,ai,ai+1,…,an)
(a1,a2,…,ai-1,ai+1,…,an)
实现步骤:
 将第i +1至第n 位的元素向前移动一个位置;
 表长减1。
注意:事先需要判断,删除位置i 是否合法?
删除算法:
Status ListDelete_sq(Sqlist &L,int i, ElemType &e)
{
if(i<1 || i>L.length)
return ERROR;
e=L.elem[i-1];
for(j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j];
L.length--;
return OK;
}
删除算法分析:
上述算法for循环语句的执行次数为n-i;
若i=1,最坏:O(n)
若i=n,无需用移动结点,直接删除即可。
(最好O(1))
移动结点的平均次数:
按等概率考虑:
可能的删除位置为i=1,2,……n共n个,则pi=1/n,所以
顺序表删除算法平均约需移动一半结点。
小结:顺序表插入、删除算法平均约需移动
一半结点,当n很大时,算法的效率较低。
显然,顺序表的空间复杂度S(n)=O(1)
(没有占用辅助空间)
本节小结
线性表顺序存储结构特点:逻辑关系上相邻的
两个元素在物理存储位置上也相邻;
优点:可以随机存取表中任一元素O(1);存储
空间使用紧凑
缺点:在插入,删除某一元素时,需要移动大
量元素O(n);预先分配空间需按最大空
间分配,利用不充分;表容量难以扩充
为克服这一缺点,我们引入另一种存储形式:
链式存储结构
作业
1、编写从顺序表中删除其值等于X的所有元素的算法。
2、设计一个算法,将x插入到一个有序(从小到大排序)的线
性表(顺序存储结构)的适当位置上,并保持线性表的有序
性。
3、设将n(n>1)个整数存放到一维数组R中。设计一个在时间和
空间两方面尽可能高效的算法。将R中的序列循环左移P
(0<P<n)个位置,即将R中的数据由(X0, X1, ……Xn-1)
变换为(Xp, Xp+1 …Xn-1,X0, X1……Xp-1)要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C++或JAVA语言描述算法,关
键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
2.3 线性表的链式表示和实现
线性链表特点:




用一组任意的存储单元存储线性表的数据元素,
可以是零散分布在内存中的任意位置上的。链表
中结点的逻辑次序和物理次序不一定相同。
利用指针实现了用不相邻的存储单元存放逻辑上
相邻的元素
每个数据元素ai,除存储本身信息外,还需存储
其直接后继的地址(或位置)信息,这个信息称
为指针(pointer)或链(link)
结点
数据域:元素本身信息
指针域:指示直接后继的存储位置
结点
数据域 指针域
链表正是通过每个结点的链域将线性表的n个结点按
其逻辑次序链接在一起的。由于上述链表的每一个结点只
有一个链域,故将这种链表称为单链表(Single Linked)。
显然,单链表中每个结点的存储地址是存放在其前趋
结点next域中,而开始结点无前趋,故应设头指针head指
向开始结点。同时,由于终端结点无后继,故终端结点的
指针域为空,即NULL(图示中也可用^表示)。
单链表是由表头唯一确定,因此单链表可以用头指针
的名字来命名。例如:若头指针名是head,则把链表称为
表head。
例 线性表 (ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG)
存储地址
头指针
H
31
1
7
13
19
25
31
37
43
数据域
指针域
LI
43
QIAN
SUN
13
1
WANG
WU
ZHAO
ZHENG
ZHOU
NULL
37
7
19
25
H
ZHAO
QIAN
SUN
LI
ZHOU
WU
ZHENG
WANG
^
与链式存储有关的术语:
1、结点:数据元素的存储映像。由数据域和指针域两部分组成;
2、链表: n 个结点由指针链组成一个链表。它是线性表的链式存
储映像,称为线性表的链式存储结构。
3、单链表、双链表、多链表、循环链表:
• 结点只有一个指针域的链表,称为单链表或线性链表;
• 有两个指针域的链表,称为双链表;
• 有多个指针域的链表,称为多链表;
• 首尾相接的链表称为循环链表。
循环链表示意图:
head
a1
a2
……
an
head
4、头指针、头结点、首元结点
头指针是指向链表中第一个结点(或为头结点或为
首元结点)的指针。
单链表可由一个头指针唯一确定。
头结点是在链表的首元结点之前附设的一个结点;
数据域内只放空表标志和表长等信息;
首元结点是指链表中存储线性表第一个数据元素a1
的结点。
头指针
头结点 首元结点
a1
例: 一个线性表的逻辑结构为:
(ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG),其存储
结构用单链表表示如下,请问其头指针的值是多少?
答:头指针是指向
链表中第一个结点
的指针,因此关键
是要寻找第一个
结点的地址。
H
31
ZHAO 7
∴头指针的值是31
存储地址
1
7
13
19
25
31
37
43
数据域
LI
QIAN
SUN
WANG
WU
ZHAO
ZHENG
ZHOU
指针域
43
13
1
NULL
37
7
19
25
上例链表的逻辑结构示意图有以下两种形式:
①
H
QIAN
ZHAO
ZHOU
②
WU
SUN
LI
ZHENG
WANG
H
ZHAO
ZHOU
WU
区别:① 无头结点
QIAN
ZHENG
② 有头结点
SUN
WANG
LI
/\
/\
讨论1. 在链表中设置头结点有什么好处?
答: 头结点即在链表的首元结点之前附设的一个结点,
该结点的数据域中不存储线性表的数据元素,其作用
是为了对链表进行操作时,可以对空表、非空表的情
况以及对首元结点进行统一处理,编程更方便。
讨论2. 如何表示空表?
答:
无头结点时,当头指针的值为空时表示空表;
有头结点时,当头结点的指针域为空时表示空表。
头指针
头指针 头结点
^
^
无头结点
有头结点
线性表的链式存储结构定义(单链表)
typedef struct LNode {
ElemType
data;
struct LNode *next;
}LNode, *LinkList;
//数据域
//指针域
//LNode为结点类型 ,*LinkList为指向LNode类型的指针
注意区分指针变量和结点变量这两个不同的概念!
如:LNode *p,q;
LinkList head;
结点
指针
问:p和head的类型是否相同?
p和q呢?
单链表的基本操作(带头结点)
1、初始化
Status InitList_L(LinkList &L)
{
L=(LNode *)malloc(sizeof(LNode));
if(!L) exit (OVERFLOW);
L->next=NULL;
return OK;
}
单链表的基本操作(带头结点)
2、取表元素
难点:单链表中想取得第i个元素,必须从头指针出
发寻找(顺藤摸瓜),不能随机存取 。
Status GetElem_L(LinkList L, int i, ElemType &e)
{
p=L->next; j=1;
while(p&&j<i){p=p->next; ++j;}//顺指针后找
if(!p||j>i)return ERROR;//第i个元素不存在
e=p->data; //取第i个元素
return OK;
}
单链表的基本操作(带头结点)
3、插入
在链表中插入一个元素的示意图如下:
p
a
b
p
p->next
插入步骤(即核心语句):
Step 1:s->next=p->next;
Step 2:p->next=s ;
a
s
b
x
s->next
元素x结点应预先生成:
S=(LinkList)malloc(m);
S->data=x;
S->next=p->next;
单链表插入算法
Status ListInsert(LinkList &L, int i, ElemType e)
{
p=L; j=0;
while(p&&j<i-1){p=p->next; ++j;}
if(!p||j>i-1)return ERROR;
S=(LinkList)malloc(sizeof(Lnode));
S->data=e;
S->next=p->next;
P->next=s;
return OK;
}
单链表的基本操作(带头结点)
4、单链表的删除
在链表中删除某元素的示意图如下:
p
a
×b
× c
p->next
(p->next) -> next
删除步骤(即核心语句):
q = p->next;
//保存b的指针,靠它才能指向c
p->next=q->next; //a、c两结点相连
free(q) ;
//删除b结点,彻底释放
思考: 省略free(q)语句行不行?
删除算法:
Status ListDelete-L(LinkList &L, int i, ElemType &e)
{
p=L; j=0;
while(p->next&&j<i-1){p=p->next; ++j;}
if(!p->next||j>i-1)return ERROR; //删除位置不合理
q=p->next; //删除并释放结点
p->next=q->next;
e=q->data;
free(q);
return OK;
}
建立单链表
动态地建立单链表的常用方法有如下两种:
(1)头插法建表
该方法从一个空表开始,重复读入数据,生成
新结点,将读入数据存放到新结点的数据域中,
然后将新结点插入到当前链表的表头上,直到读
入结束为止。
(2)尾插法建表
头插法建立链表虽然算法简单,但生成的链
表中结点的次序和输入的顺序相反。若希望二者
次序一致,可采用尾插法建表。该方法是将新结
点插入到当前链表的表尾上,为此必须增加一个
尾指针r,使其始终指向当前链表的尾结点。
应用举例:合并两个有序线性表
LC=LA+LB
算法1:抽象数据类型表示的两个有序表的合
并
算法2:两个有序顺序表的合并
算法3:两个有序链表的合并
其它链表形式
讨论1: 链表能不能首尾相连?怎样实现?
答:能。只要将表中最后一个结点的指针域指向头结
点即可 (P->next=head;) 。这种形成环路的链表称
为循环链表。
特点:
1、从任一结点出发均可找到表中其他结点。
2、操作仅有 一 点与单链表不同:( 判定表结束条件 )
单链表 ----- p = NULL 或 p ->next =NULL
循环链表----- p= head 或 p->next = head
head
head
讨论2: 单链表只能查找结点的直接后继,能不能
查找直接前驱?如何实现?
答:能。只要把单链表再多开一个指针域即可(例如
用*next和*prior) 。
prio dat nex
r
a
t
这种有两个指针的链表称为双向链表。其特点是
可以双向查找表中结点。
双向链表在非线性结构(如树结构)中将大量使用。
head
head
P
在双向链表中,若P为指向表中某一结点的指针,
则显然有:P->next->prior=P->prior->next=P
在双向链表中插入、删除结点和单链表有很大
的不同,因需同时修改两个方向上的指针。
删除双向循环链表中的p
结点,应使用下列语句序
列:
在双向循环链表中的p结点之前插
入S结点,应使用下列语句序列:
s->next=p;
p->prior->next=p->next;
s->prior=p->prior;
p->next->prior=p->prior;
p->prior->next=s;
p->prior=s;
静态链表


借用一维数组来描述线性链表。为了和指
针型描述的线性链表相区别,我们称它为
静态链表。
线性表的静态单链表存储结构定义
#define MAXSIZE 100//链表的最大长度
typedef struct{
ElemType data;
int cur;
}componet, SLinkList[MAXSIZE];
课堂作业
1、线性表具有两种存储方式,即顺序方式和链接
方式。现有一个具有五个元素的线性表L={23,
17,47,05,31},若它以链接方式存储在下
列100~119号地址空间中,每个结点由数据
(占2个字节)和指针(占2个字节)组成,如下
图所示。其中指针X,Y,Z的值分别为多少?该
线性表的首结点起始地址为多少?末结点的起始
地址为多少?
05
U
17
X
23
V
31
Y
47
Z
课堂作业
2、有一个带头结点的循环单链表L,设计一
个算法统计其data域值为x的结点个数。
3、有一个带头结点的循环双链表L,设计一
个算法删除第一个data域值为x的结点。
链表的运算效率分析
时间效率分析
1. 查找 因线性链表只能顺序存取,即在查找时
要从头指针找起,查找的时间复杂度为 O(n)。
2. 插入和删除 因线性链表不需要移动元素,只要修
改指针,一般情况下时间复杂度为 O(1)。
但是,如果要在单链表中进行前插或删除操作,
由于要从头查找前驱结点,所耗时间复杂度为
O(n)。
链表的运算效率分析
空间效率分析
链表中每个结点都要增加一个指针空间,相当于总
共增加了n 个整型变量,空间复杂度为 O(n)。
作业
1、设L为单链表的头结点地址,其数据结点的数据都是正整数且无相同的,
试设计利用直接插入的原则把该链表整理成数据递增的有序单链表的算
法。
2、设计一个算法,将一个带头结点的数据域依次为a1,a2,a3,……an
(n≥3)的单链表的所有结点逆置。
link
3、已知一个带有表头结点的单链表,结点结构为 data
假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可
能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若
查找成功,算法输出该结点的data值,并返回1;否则,只返回0;要求:
(1)描述算法的基本设计思想;
(2)描述算法的详细实现步骤;
(3)根据设计思想和实现步骤,采用程序设计语言描述算法(使用C或
C++或JAVA语言实现),关键之处请给出简要注释。
2.4 应用举例(一元多项式的计算)
一元多项式An(x)、Bm(x)按升幂表示:
An(x)= a0+a1x1+ ... +an-1xn-1 + anxn ,
Bm(x)= b0+b1x1+ ... +bm-1xm-1 + bmxm ,
设m<n,则两个多项式相加的结果为:
Cn(x)= (a0+b0)+(a1+b1)x1+ ... +(am+bm)xm
+am+1xm+1+… +anxn
在计算机里,一元多项式可用线性表表示:
A=(a0,a1,...,an-1,an)
存在问题吗?
如:P999(x) = 7x3 - 2x12-8x999
若多项式的阶次很高,而系数ai不为零的很少,则
这种表示浪费空间。
则一元多项式可写为:
An(x)=a0xe0+a1xe1+...+an-1xen-1+anxen
用线性表表示为:
A=((a0,e0),(a1,e1),...,(an-1,en-1),(an,en))
例: P999(x) = 7x3 - 2x12-8x999
表示成: ( (7,3) ,(-2,12), (-8,999))
通过对具体问题实际情况的分析,按照下面
的步骤进行分析和设计.
1、 问题中所涉及的基本数据对象,数据元素的分析
2 、逻辑结构分析:数据元素之间按照一定的顺序
形成一个有序序列,元素之间的逻辑关系与项的
幂的大小有关
3 、抽取数学模型,建立抽象数据类型
4 、分别采用顺序和链式存贮结构实现具体的数据
类型定义和函数定义.
在实际的应用程序中取用哪一种存储方
式,要视多项式作何种运算而定。
若只对多项式进行“求值”等不改变多
项式的系数和指数的运算,则采用顺序存
储结构,否则应采用链式存储结构。
课堂作业
等值连接实现:
A=
1
2
3
3
5
2
3
3
B= 1
6
1
1
1
3
4
C=A
3=1
B=
1
2
3
3
5
1
2
3
3
4
2
3
3
3
5
2
3
3
3
4
1
1
1
1
6
数据抽象和组织
数据结点类型定义
#denfine MaxCol 10//最大列数
typedef struct Node1
{ ElemType data[MaxCol];//存放行中各数
struct Node1 *next;//指向下行对应结点
} DList;
 头结点类型定义
typedef struct Node2
{ int Row,Col;//行数和列数
DList *next;//指向第一个数据结点
} HList ;

本章小结(讨论题形式)
问1:线性表的逻辑结构特点是什么?其顺序存储
结构和链式存储结构的特点是什么?
答: 线性表逻辑结构特点是,只有一个首结点和尾结点;除
首尾结点外其他结点只有一个直接前驱和一个直接后继。
简言之,线性结构反映结点间的逻辑关系是一对一(1:1)
的。
顺序存储时,相邻数据元素的存放地址也相邻(逻辑与物
理统一);要求内存中可用存储单元的地址必须是连续的。
链式存储时,相邻数据元素可随意存放,但所占存储空间
分两部分,一部分存放结点值,另一部分存放表示结点间关
系的指针。
问2:顺序存储和链式存储各有哪些优缺点?
答:
顺序存储的优点是存储密度大(=1),
存储空间利用率高。缺点是插入或删除
元素时不方便。
链式存储的优点是插入或删除元素时
很方便,使用灵活。缺点是存储密度小
(<1),存储空间利用率低。
事实上,链表插入、删除运算的快捷是以
空间代价来换取时间。
问3:在什么情况下用顺序表比链表好?
答:
顺序表适宜于做查找这样的静态操作;
链表宜于做插入、删除这样的动态操作。
若线性表的长度变化不大,且其主要操作是
查找,则采用顺序表;
若线性表的长度变化较大,且其主要操作是
插入、删除操作,则采用链表。