说明:《数据结构题集(C语言版)》(严蔚敏等编著,清华大学出版社,旧版电子书封面为蓝灰色,简称《题集》)是《数据结构(C语言版)》(严蔚敏等编著,清华大学出版社,封面为紫色,下称“主书”)的配套书籍。《题集》的习题篇与主书相对应,分为12章。
题号后的带圈数字表示难度系数,难度级别从①至⑤逐渐加深。题号前有标注◆的题目是编者自认为值得向读者推荐的“好题”。(难度系数与“好题”均为《题集》编者标注,非本人标注)
部分算法使用了主书的配套代码中定义的数据类型和函数,在这些算法的头部省略了#include指令。
《题集》第1章为绪论,理论知识较多,本人也进行了自解答,不公开发布。本文是第2章(线性表)习题的部分自解答。后续章节不再进行自解答。本自解答在完成后参考了《题集》中的提示和答案、康建伟给出的自解答来进行订正,并经过简单测试运行。如发现错误,可留言指出。
2020年4月2日更新,2020年2-3月编写
int ListCompare_Sq(SqList A,SqList B)
{
//本算法比较顺序表A和B的大小
int la=A.length,lb=B.length;
int i=0,d=0;
while(i<la&&i<lb&&d==0)
{
d=A.elem[i]-B.elem[i];
i++;
}
if(d!=0) return d;
else return la-lb;
}
Status ListConnect(LinkList ha,LinkList hb,LinkList &hc){
//本程序将以hb为头结点的链表连接到以ha为头结点的链表之后,
//并用hc返回连接后链表的头结点,已知两个链表的长度分别为m和n
LinkList p,q;//p指向短链表,q指向长链表
if(m<n) {
p=ha;q=hb;}
else{
p=hb;q=ha;}
hc=p;
while(p->next) p=p->next;
p->next=q->next;
free(q);
return OK;
}
时间复杂度:O(min(m,n))
注释中有标明本算法与主书P29算法2.9的不同之处。
Status ListInsert(LinkList &L,int i,ElemType e) // 算法2.9。不改变L
{
// 在无头结点的单链线性表L中第i个位置之前插入元素e
int j=1;//主书:j=0
LinkList p=L,s;
while(p&&j<i-1) // 寻找第i-1个结点
{
p=p->next;
j++;
}
if(!p L&&p==NULL||j>i-1&&i!=1) // 此条件不同,空表的L=NULL;i小于1或者大于表长(i=1时j>0)
return ERROR;
s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
if(!s) return OVERFLOW;
s->data=e; // 插入L中
if(i==1)//增加此段
{
s->next=p;//插在p的前面
L=s;
}
else
{
s->next=p->next;
p->next=s;
}
return OK;
}
注意:无头结点的单链表的InitList(LinkList &L)
函数简化为一句话:L=NULL;
注释中有标明本算法与主书P30算法2.10的不同之处。
Status ListDelete(LinkList L,int i,ElemType &e) // 算法2.10。不改变L
{
// 在无头结点的单链线性表L中,删除第i个元素,并由e返回其值
int j=1;//主书:j=0
LinkList p=L,q;
if(!p) return ERROR;//此句新增,空表:出错
while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
{
p=p->next;
j++;
}
if(!p->next||j>i-1&&i!=1) // 此句不同,删除位置不合理
return ERROR;
if(i==1)//此段新增
{
q=p;//首元结点无前驱
L=p->next;
}
else
{
q=p->next; // 删除并释放结点
p->next=q->next;
}
e=q->data;
free(q);
return OK;
}
Status ListDelete(LinkList L,int mink,int maxk)
{
//本算法删除单链表L中所有值大于mink且小于maxk的元素
if(mink>maxk) return ERROR;
LinkList p=L,q=p->next,r;
while(q&&q->data<=mink)
{
p=q;
q=q->next;
}//使p指向删除段的前驱
while(q&&q->data<maxk)
{
r=q;
q=q->next;//使q指向删除段的后继
free(r);
}
p->next=q;
return OK;
}
Status ListDelete(LinkList &L)
{
//本算法删除递增有序的单链表L中所有值相同的多余元素
LinkList p=L->next,q,r;
while(p)//p指向删除段前驱
{
q=p->next;
while(q&&q->data==p->data)
{
r=q;
q=q->next;
free(r);
}//出循环时,q指向删除段后继
p->next=q;
p=p->next;
}
return OK;
}
时间复杂度:O(n)
void Reverse(SqList &L)
{
//本算法实现顺序表的就地逆置
ElemType t;
ElemType *p=L.elem,*q=p+L.length-1;
while(p<q)
{
t=*p;
*p=*q;
*q=t;
p++;
q--;
}
}
对单链表实现就地逆置。
第一次写出的算法如下。
void Reverse(LinkList &L){
if(!L->next) return;
LinkList p=L->next,q=p->next,r;
while(q){
r=q->next;
q->next=p;
p=q;
q=r;
}
L->next->next=NULL;
L->next=p;
}
(答案提示)正确做法:将原链表中的头结点和第一个元素结点断开,先构成一个新的空表,然后将原链表中各结点依次插入新表的头部。
以下为根据此提示写出的算法。
void Reverse(LinkList L){
LinkList p=L->next,q;
L->next=NULL;
while(p){
q=p->next;
p->next=L->next;
L->next=p;
p=q;
}
}
void ListMerge_OrderReverse(LinkList