第二章线性表
一. 基本要求、重点、难点
本章主要介绍线性表的逻辑结构和各种存储表示方法,以及定义在逻辑结构上的各种基本运算及其在存储结构上如何实现这些基本算法。本章的重点是熟练掌握顺序表(即线性表的顺序存储)和单链表上实现各种基本算法以及相关的时间复杂度分析,难点是能够使用本章所学到的基本知识设计有效算法,解决与线性表相关的应用问题。
二. 考核目标和考核要求
要求达到识记层次的有:线性表的逻辑结构特征、线性表上定义的基本运算,并能利用基本运算构造出较复杂的运算。
要求达到理解层次的有:顺序表和链表的主要优缺点、针对线性表上所需要执行的主要操作,知道选择顺序表还是链表作为其存储结构才能取得较优的时空性能。
要求达到综合应用层次有:顺序表的含义及特点,即顺序表如何反映线形表中元素之间的逻辑关系;顺序表上的插入、删除操作及其平均时间性能分析;利用顺序表设计算法解决简单的应用问题;链表如何表示线性表中元素之间的逻辑关系;链表中头指针和头结点的使用;单链表、双链表、循环链表链接方式上的区别;单链表上实现的建表、查找、插入和删除等基本算法、并分析其时间复杂度;循环表上尾指针取代头指针的作用,以及单循环链表上的算法与单链表上相应算法的异同点;双链表的定义及其相关的算法;利用链表设计算法解决简单的应用问题。
三. 练习
1. 单项选择题
1.1如果一个顺序表中第一个元素的存储地址为1000,每个元素占4个地址单元,那么,第6个元素的存储地址应是( A )
A) 1020
B) 1010
C) 1016
D) 1024
注释:利用计算存储地址的公式计算为Loc(ai)=Loc(a1)+L*(i-1):1000+4*(6-1)=1020。
1.2带头结点的单链表(以head为头指针)为空的判断条件是( C )
A) head!=NULL
B) head->next==head
C) head->next==NULL
D) head==NULL
注释:带头结点的单链表为空的条件是:head->next==NULL。
1.3对顺序存储的线性表,设其长度为n,在任何位置上删除操作都是等概率的。删除一个元素时大约要移动表中元素的个数是( D )
A) n/2
B)( 1)/2
C) n-1
D)( n-1)/2
注释:对于顺序存储的线性表,设其长度为n,在任何位置上删除操作都是等概率的,插入一个元素大约需要移动n/2个元素,删除一个元素大约需要移动(n-1)/2个元素。
1.4链表不具有的特点是( A )
A) 可随机访问任一元素
B) 插入删除不需要移动元素
C) 不必事先估计存储空间
D) 所需空间与线性表长度成正比
1.5 L是线性表,已知Length(L)的值是5,经运算Delete(L,2),后Length(L)的值是( C )
A) 5
B) 0
C) 4
D) 6
1.6在一个单链表中,若删除p指向结点的后继结点,则执行的操作为( A )
A) q=p->next;p->next=p->next->next;dispose(q);
B) p=p->next;q=p->next;p=q->next;dispose(q);
C) q=p->next->next;p=p->next;dispose(q);
A) p=p->next->next;q=p->next;dispose(q);
1.7在线性表中,哪些元素只有一个直接前驱和一个直接后继( C )
A) 首元素
B) 尾元素
C) 中间的元素
D) 所有的元素
注释:线性表的首元素只有一个直接后继,尾元素只有一个直接前驱,中间的元素只有一个前驱元素和后继元素。
1.8在单循环链表中,已知q指向p指向结点的前驱结点,若在q,p所指结点之间插入一个s所指向的新结点,则执行的操作是( A )
A)q->next=s,s->next=p;
B)p->next=s;s->next=q;
C)s->next=p->next;p->next=s;
D)p->next=s->next;s->next=p;
2. 填空题
2.1在一个长度为n的顺序表中第i个元素之前插入一个元素时,需要后移[n-i+1]个元素
2.2在一个长度为n的顺序表中删除第i个元素需要向前移动[n-1]个元素
2.3顺序表中逻辑相邻的元素,在物理位置上[相邻]
2.4在用p指针访问单链表时,判断表没有访问结束的条件是[p!=NULL]
2.5线性表a的元素长度为L,在顺序存储结构下Loc(ai)=Loc(a1)+[L*(i-1)]
2.6在单链表中除首结点外,任意结点的存储位置都由[直接前驱]结点中的指针表示
2.7在单链表中,设置表头结点的作用是插入或删除首结点时不必对[表头指针]进行处理
2.8循环链表S是空表的条件是[s->next==s]
2.9双向链表S是空表的条件是[s->next==s->prior==s]
3. 简答题
3.1线性表有两种存储结构,即顺序表和链表,这两种存储表示各有什么优缺点?
答:
a,表的顺序存储表示结构简单,不需要额外的存储空间,数据记录在逻辑上相邻,在存储位置上亦相邻,可随机存取,有些运算容易实现;但在做插入和删除运算时要移动大量的元素,表长是固定的,不易扩展。
b.链式存储表示是动态结构,表长可任意扩充,插入和删除不需要移动大量的元素;但不能随机存取,需要增加相应的存储空间。
3.2在链表结构中,头结点与开始结点有什么区别?
答: 在开始结点之前附设的一个结点称为头结点,它的数据域值是无意义的,而开始结点是链表中存储线性表中第一个元素的结点。
3.3哪些链表从尾指针出发可以访问到链表中的任意位置?
答:循环链表和双向链表
4. 算法设计
4.1在顺序表中第i个位置上插入元素x
void InsertList(SeqList *L,DataType x,int i)
{//将新结点x插入L所指的顺序表的第i个结点ai的位置上
int j;
if(i<1||i>L->length+1)
Errr(“position error”); //非法位置,退出运行
if(L->length>=ListSize)
Error(“overflow”); //表空间溢出,退出运行
for(j=L->Length-1;j>=i-1;j--)
L->data[j+1]=L->data[j];
L->data[i-1]=x;
L->length++;}
4.2将顺序表中位置为i的元素删除
voidDeleteList(SeqList *L,int i)
{//从L所指的顺序表中删除第i个结点ai
int j;
if(i<1||i>L->length)
Error(“position error”);//非法位置
for(j=i;j<=L->length-1;j++)
L->data[j-1]=L->data[j];
L->length--; //表长减小
}
4.3头插法建立单链表
LinkList CreateListF(void)
{//返回单链表的头指针
char ch;
LinkList head; //头指针
ListNode *s; //工作指针
head=NULL; //链表开始为空
ch=getchar( ); //读第一个字符
while(ch!=’\n’)
{s=(ListNode *)malloc(sizeof(ListNode));
s->data=ch; //将读入的数据放入新结点的数据域中
s->next=head;
head=s;
ch=getchar( ); //读入下一个字符}
return head; //返回头指针
}
4.4尾插法建立单链表
LinkList CreateListR(void)
{ char ch;
LinkList head;
ListNode *s,*r;
head=NULL;r=NULL; //链表初值为空,尾指针初值为空
while((ch=getchar( ))!=’\n’)
{s=(ListNode *)malloc(sizeof(ListNode));
s->data=ch;
if(head==NULL)
head=s;
else r->next=s;
r=s;}
if(r!=NULL)
r->next=NULL; //对于非空表,将尾结点指针域置空
return head;}
4.5在链表中查找序号为i的结点
ListNode *GetNode(LinkList head,int i)
{//在带头结点的单链表head中查找第i个结点,若找到(0≤i≤n),则返回该结点的存储位置,否则返回NULL
int j;
ListNode *p;
p=head;j=0; //从头结点开始扫描
while(p->next&&j<i)
{ //顺指针向后扫描,直到p->next为NULL或j=i为止
p=p->next;
j++;}
if(i==j) return p; //找到了第i个结点
else return NULL; //当i<0或i>n时,找不到第i个结点}
4.6将值为x的结点插入到单链表的第i个位置上
void InsertList(LinkList head,DataType x,int i)
{//将值为x的新结点插入到带头结点的单链表head的第i个结点的位置上
ListNode *p;
p=GetNode(head,i-1);//寻找第i-1个结点
if(p==NULL)
Error(“position error”); //i<1或i>n+1时插入位置i有错
s=(ListNode*)malloc(sizeof(ListNode));
s->data=x;
s->next=p->next;
p->next=s;}
4.7删除单链表中的第i个结点
voidDeleteList(LinkList head,int i)
{//删去带头结点的单链表head上的第i个结点
ListNode *p, *r;
p=GetNode(head,i-1); //找第i-1个结点
if(p==NULL||p->next==NULL)//i<1或i>n时删除位置有错
Error (“position error”); //退出程序运行
r=p->next;
p->next=r->next;
free(r); //释放结点所占用的空间}