A[i][j]=0;
解:
该程序段的时间复杂度为O(m*n)。
【例1-4】分析以下程序段的时间复杂度。
i=1;①
while(i<=n)
i=2*i;②
解:
其中语句①的执行次数是1,设语句②的执行次数为f(n),则有:
。
得:
T(n)=O(
)
【例1-5】设语句x++的时间是单位时间,则以下语句的时间复杂度为(B)。
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
x++;
A.O
(1)B.O(
)C.O(n)D.O(
)
第2章表
2.3.表的顺序存储结构及其运算的实现。
【例3-1】一个向量第一个元素的存储地址是100,每个元素的长度为2,则第5个元素的地址是(B)
(A)110(B)108(C)100(D)120
【例3-2】表长为n的顺序存储的线性表,当在任何位置上插入一个元素的概率相等时,插入一个元素所需移动元素的平均个数为(B)
A.nB.n/2
C.(n-1)/2D.(n+1)/2
【例3-3】在一个长度为n的顺序表的表尾插入一个新元素的渐进时间复杂度为(B)。
A.O(n)B.O
(1)
C.O(n2)D.O(log2n)
2.4.表的链接存储结构及其运算的实现
单链表中的插入与删除
插入
第一种情况:
在第一个结点前插入
newnode→link=first;
first
first
newnode
newnode
first=newnode;
(插入前)(插入后)
第二种情况:
在链表中间插入
newnode→link=p→link;
p→link=newnode;
(插入前)(插入后)
第三种情况:
在链表末尾插入
newnode→link=p→link;
p→link=last=newnode;
(插入前)(插入后)
2.5.单链表、循环链表、双向链表的特点。
【例3-4】1.线性表L在情况下适用于使用链式结构实现。
(B)
(A)需经常修改L中的结点值(B)需不断对L进行删除插入
(C)L中含有大量的结点(D)L中结点结构复杂
【例3-5】2.在一个单链表中,若删除p所指结点的后续结点,则执行____。
A
(A)p—>next=p—>next—>next;
(B)p=p—>next;p—>next=p—>next—>next;
(C)p—>next=p—>next;
(D)p=p—>next—>next;
【例3-6】3.在一个单链表中,若p所指结点不是最后结点,在p之后插入s所指结点,则执行。
B
(A)s—>next=p;p—>next=s;
(B)s—>next=p—>next;p—>next=s;
(C)s—>next=p—>next;p=s;
(D)p—>next=s;s—>next=p;
【例3-7】设单链表中结点的结构为(data,link)。
已知指针q所指点是指针p所指结点的直接前驱,若在*q与*p之间插入结点*s,则应执行下列哪一个操作?
(B)。
A.s->link=p->link;p->link=s
B.q->link=s;s->link=p
C.p->link=s->link;s->link=p
D.p->link=s;s->link=q
【例3-8】4.在循环双链表的p所指结点之后插入s所指结点的操作是d____。
A.p—>right=s;s—>left=p;p—>right—>left=s;s—>right=p—>right;
B.p—>right=s;p—>right—>left=s;s—>left=p;s—>right=p—>right;
C.s—>left=p;s—>right=p—>right;p—>right=s;p—>right—>left=s;
D.s—>left=p;s—>right=p—>right;p—>right—>left=s;p—>right=s;
2.6.单链表算法设计
【例3-9】1.设计算法,求带表头的单循环链表的表长。
解:
intlength(LinklistL)
{
intI;
listnode*p;
I=0;
P=L;
while(p->next!
=L){
p=p->next;
I++;
}
returnI;
}
【例3-10】2.已知单链表L,写一算法,删除其重复结点。
算法思路:
用指针p指向第一个数据结点,从它的后继结点开始到表的结束,找与其值相同的结点并删除之;p指向下一个;依此类推,p指向最后结点时算法结束。
算法如下:
解:
voidpur_LinkList(LinkListH)
{LNode*p,*q,*r;p=H->next;/*p指向第一个结点*/
if(p==NULL)return;
while(p->next)
{q=p;
while(q->next)/*从*p的后继开始找重复结点*/
{if(q->next->data==p->data)
{r=q->next;/*找到重复结点,用r指向,删除*r*/
q->next=r->next;
free(r);
}/*if*/
elseq=q->next;
}/*while(q->next)*/
p=p->next;/*p指向下一个,继续*/
}/*while(p->next)*/
}
该算法的时间性能为O(n2)。
【例3-11】4.写一算法,将一带有头结点的单链表就地逆置,即要求逆置在原链表上进行,不允许重新构造新链表。
(b)
函数原型如下:
voidLinkList_reverse(LinkList&L);
答:
voidLinkList_reverse(LinkList&L)
{
LinkListp,q,s;
p=L->next;q=p->next;s=q->next;p->next=NULL;
while(s->next)
{
q->next=p;p=q;
q=s;s=s->next;
}
q->next=p;s->next=q;L->next=s;
}
【例3-12】5.写一算法,将带有头结点的非空单链表中数据域值最小的那个结点移到链表的最前面。
要求:
不得额外申请新的链结点。
函数原型如下:
voiddelinsert(LinkList&L);
答:
voiddelinsert(LinkList&L)
{
p=L->next;//p是链表的工作指针
pre=L;//pre指向链表中数据域最小值结点的前驱
q=p;//q指向数据域最小值结点,初始假定是第一结点
while(p->next!
=NULL)
{
if(p->next->datadata)//找到新的最小值结点
{pre=p;q=p->next;}
p=p->next;
}
if(q!
=L->next)//若最小值是第一元素结点,则不需再操作
{
pre->next=q->next;//将最小值结点从链表上摘下
q->next=L->next;//将q结点插到链表最前面
L->next=q;
}
}
【例3-13】【例2-2】写一算法实现单链表的逆置。
解:
假设单链表的表头指针用head表示,其类型为上面定义的LinkList,并且单链表不带头结点。
逆置后原来的最后一个结点成为第一个结点,于是从第一个结点开始逐个修改每个结点的指针域进行逆置,且刚被逆置的结点总是新链表的第一个结点,故令head指向它(如图2-1所示)。
具体算法描述如下:
(b)第三个结点逆置
示示
图
voidcontray(LinkList*head)
{//将head单链表中所有结点按相反次序链接
LinkList*p,*q;
p=head;//p指向未被逆序的第一个结点,初始时指向原表头结点
head=NULL;
while(p!
=NULL)
{q=p;//q指向将被逆序链接的结点
p=p->next;
q->next=head;
head=q;
}
}
【例3-14】试设计实现删除单链表中值相同的多余结点的算法。
解:
该例可以这样考虑,先取开始结点的值,将它与其后的所有结点值一一比较,发现相同的就删除掉,然后再取第二结点的值,重复上述过程直到最后一个结点。
设单链表(其类型为LinkList)的头指针head指向头结点,则可按下列步骤执行:
首先,用一个指针p指向单链表中第一个表结点,然后用另一个指针q查找链表中其余结点元素,由于是单链表,故结束条件为p==NULL,同时让指针s指向q所指结点的前趋结点,当查找到结点具有q->data==p->data时删除q所指的结点,然后再修改q,直到q为空;然后使p指针后移(即p=p->next),重复进行,直到p为空时为止。
算法描述如下:
del(LinkList*head)
{//删除单链表中值相同的多余结点
LinkList*p,*s,*q;
p=head->next;
while(p!
=NULL&&p->next!
=NULL)
{s=p;//s指向要删除结点的前趋
q=p->next;
while(q!
=NULL)
{if(q->data==p->data)}//查找值相同的结点并删除
{s->next=q->next;
free(q);
q=s->next;
}
else
{s=q;
q=q->next;
}
}
p=p->next;
}
}
第3章栈
3.1.栈的顺序实现及其运算
【例3-15】1.判定一个栈ST(最多元素为m0)为空的条件是(B)
A.ST->top<>0B.ST->top=0C.ST->top<>m0D.ST->top=m0
【例3-16】2.设一个栈的入栈序列是ABCD,则借助于一个栈所得到的出栈序列不可能是( )。
A.ABCDB.DCBAC.ACDBD.DABC
3.2.栈和队列的链接实现及其运算的实现。
3.3.栈的应用。
【例3-17】1.设一个栈的入栈序列是ABCD,则借助于一个栈所得到的出栈序列不可能是( )。
A)ABCDB)DCBAC)ACDBD)DABC
【例3-18】2.设栈最大长度为3,入栈序列为1、2、3、4、5、6,则不可能的出栈序列是( )。
A)1、2、3、4、5、6B)2、1、3、4、5、6
C)3、4、2、1、5、6D)4、3、2、1、5、6
第4章队列
•考点
3.4.队列的顺序实现(循环队列)及其运算的实现。
【例3-19】1.数组Q[n]用来表示一个循环队列,f为当前队列头元素的前一位置,r为队尾元素的位置,假定队列中元素的个数小于n,计算队列中元素的公式为(D)
(A)r-f;(B)(n+f-r)%n;(C)n+r-f;(D)(n+r-f)%n
【例3-20】2.判定一个队列QU(最多元素为m0)为满队列的条件是(A)
A.QU->rear-QU->front==m0B.QU->rear-QU->front-1==m0
C.QU->front==QU->rearD.QU->front==QU->rear+1
3.5.队列的链接实现及其运算的实现。
3.6.队列的应用
【例3-21】若循环队列以数组Q[0..m-1]作为其存储结构,变量rear表示循环队列中的队尾元素的实际位置,其移动按rear=(rear+1)Modm进行,变量length表示当前循环队列中的元素个数,则循环队列的队首元素的实际位置是(C)
A.rear-length
B.(rear-length+m)Modm
C.(1+rear+m-length)Modm
D.M-length
第5章递归
递归的概念与应用
1.数学函数F(n)的递归定义如下:
1当n<=4时
F(n)=
5*F(n–2)+3当n>4时
试用C语言写出计算F(n)之值的递归函数F();并写出F(5)的值。
第6章排序与选择
6.1.排序的基本概念(内外排序、稳定性、时间效率、空间效率)
【例3-22】8.若一组记录的排序码为(46,79,56,38,40,84),则利用快速排序的方法,以第一个记录为基准得到的一次划分结果为(C)
A.38,40,46,56,79,84B.40,38,46,79,56,84
C.40,38,46,56,79,84D.40,38,46,84,56,79
【例3-23】2.在对一组记录(54,38,96,23,15,72,60,45,83)进行直接插入排序时,当把第7个记录60插入到有序表时,为寻找插入位置至少需比较6次。
6.2.选择排序的方法(简单选择排序、堆排序)
【例3-24】12.若一组记录的排序码为(46,79,56,38,40,84),则利用堆排序的方法建立的初始堆为(B)
A.79,46,56,38,40,84B.84,79,56,38,40,46
C.84,79,56,46,40,38D.84,56,79,40,46,38
6.3.插入排序的方法(直接插入排序)
直接插入排序是稳定排序。
【例3-25】【例8-1】已知关键字序列(12,77,21,65,38,7,38,53),给出采用直接插入排序方法按关键字递增序排列时的每一趟结果。
解:
初始127721653873853
1趟127721653873853
2趟122177653873853
3趟122165773873853
4趟122138657773853
5趟712213865773853
6趟712213838657753
7趟712213838536577
(表示有序区)
【例3-26】1.写出对线性表(65,15,48,6,34,97,1,26)进行直接插入排序的每一趟结果。
第一趟:
1565(4863497126)
第二趟:
154865(63497126)
第三趟:
6154865(3497126)
第四趟:
615344865(97126)
第五趟:
61534486597(126)
第六趟:
161534486597(26)
第七趟:
16152634486597
【例3-27】2.写出对线性表(37,15,98,25,10,47,83,32)进行冒泡排序的每一趟结果。
第一趟:
1537251047833298
第二趟:
1525103747328398
第三趟:
1510253732478398
第四趟:
1015253237478398
第五趟:
1015253237478398
【例3-28】3.写出对线性表(69,45,8,16,74,27,1,29)进行简单选择排序的每一趟结果。
第一趟:
1(4581674276929)
第二趟:
18(451674276929)
第三趟:
1816(4574276929)
第四趟:
181627(74456929)
第五趟:
18162729(456974)
第六趟:
1816272945(6974)
第七趟:
18162729456974
6.4.交换排序的方法(冒泡排序、快速排序)
【例3-29】【例8-3】已知序列(17,18,60,40,7,32,73,65,85),请给出采用冒泡排序法对该序列作升序排序时的每一趟的结果。
解:
初始1趟2趟3趟4趟5趟
1717171777
18181871717
60407181818
40732323232
73240404040
326060606060
736565656565
657373737373
858585858585
(表示有序区)
【例3-30】27、给定一个关键字序列{24,19,32,43,38,6,13,22},请写出快速排序第一趟的结果;堆排序时所建的初始堆;然后回答上述两种排序方法中哪一种方法使用的辅助空间最小,在最坏情况下哪种方法的时间复杂度最差?
快速排序的第一趟结果为{22,19,13,6,24,38,43,12};堆排序时所建立的初始大顶堆如所图所示:
两种排序方法所需辅助空间:
堆是O
(1),快速排序是O(logn),可见堆排序所需辅助空间较少;在最坏情况下两种排序方法所需时间:
堆是O(nlogn),快速排序是O(n2),所以,可见快速排序时间复杂度最差。
注意:
快速排序的平均时排序速度最快,但在最坏情况下不一定比其他排序方法快。
【例3-31】【例8-4】已知关键字序列(38,12,21,77,65,7,38,53)给出采用快速排序方法按关键字增序排序时的第一趟块排过程,并举出一个反例说明快速排序是不稳定排序。
解:
(1)
初始381221776573853
↑↑
lowhigh
第一次交换
从high开始比较,得到的结果:
712217765□3853
↑↑
lowhigh
从low开始比较,得到的结果:
71221□65773853
↑↑
lowhigh
第二次交换
从high开始比较,得到的结果:
71221□65773853
↑↑
lowhigh
low=high,所以第一趟快速排序的结果为:
712213865773853
(2)关键字序列(2,2,1)可以作为一个反例。
取第一个关键字作为支点,在一趟快排之后的结果是(1,2,2),由于2已在排序后的最终位置,2在2划分出的前一部分子表中,所以2不可能再出现在2之后,即不可能与原始序列中两者的顺序一致。
此反例说明快速排序不是稳定排序。
【例3-32】(例12—32)已知序列{25,18,60,40,7,21,32,73,68},请给出分别采用冒泡排序方法、直接选择排序方法和快速排序方法对该序列做升序排列时的每一趟结果。
解析:
(1)采用冒泡排序方法排序的各趟结果如下:
(加框为每次冒出元素)
初始序列:
25,18,60,40,7,21,32,73,68
第——趟:
,25,18,60,40,21,32,68,73
第二趟:
7,,25,21,60,40,32,68,73
第三趟:
7,18,,25,32,60,40,68,73
第四趟:
7,18,21,,32,40,60,68,73
第五趟:
7,18,21,25,32,40,60,68,73
第五趟无元素交换,排序结束。
(2)采用直接选择排序方法排序的各趟结果如下:
(加框为每次选出元素)
初始序列:
25,18,60,40,,21,32,73,68
第——趟:
[7],60,40,25,2l,32,73,68
第二趟:
[7,18