s+=B[i][j];
sum=s;
答:
O(n^2)
4.下面程序段的时间复杂度是_______。
i=1;
While (i<=n)
i=i*3;
答:
log3n
第二章 线性表
一、 判断题
1.线性表的逻辑顺序与存储顺序总是一致的。
(ERROR)
2.顺序存储的线性表可以按序号随机存取。
(OK)
3.顺序表的插入和删除一个数据元素,因为每次操作平均只有近一半的元素需要移动。
(OK)
4.线性表中的元素可以是各种各样的,但同一线性表中的数据元素具有相同的特性,因此是属于同一数据对象。
(OK)
5.在线性表的顺序存储结构中,逻辑上相邻的两个元素在物理位置上并不一定紧邻。
(ERROR)
6.在线性表的链式存储结构中,逻辑上相邻的元素在物理位置上不一定相邻。
(OK)
7.线性表的链式存储结构优于顺序存储结构。
(ERROR)
8.在线性表的顺序存储结构中,插入和删除时,移动元素的个数与该元素的位置有关。
(OK)
9.线性表的链式存储结构是用一组任意的存储单元来存储线性表中数据元素的。
(OK)
10.在单链表中,要取得某个元素,只要知道该元素的指针即可,因此,单链表是随机存取的存储结构。
(ERROR)
二、 单选题、 (请从下列A,B,C,D选项中选择一项)
11.线性表是( A ) 。
(A) 一个有限序列,可以为空; (B) 一个有限序列,不能为空;
(C) 一个无限序列,可以为空; (D) 一个无序序列,不能为空。
12.对顺序存储的线性表,设其长度为n,在任何位置上插入或删除操作都是等概率的。
插入一个元素时平均要移动表中的(A)个元素。
(A) n/2 (B) (n+1)/2 (C) (n –1)/2 (D) n
13.线性表采用链式存储时,其地址( D ) 。
(A) 必须是连续的; (B) 部分地址必须是连续的;
(C) 一定是不连续的; (D) 连续与否均可以。
14.用链表表示线性表的优点是 (C )。
(A)便于随机存取
(B)花费的存储空间较顺序存储少
(C)便于插入和删除
(D)数据元素的物理顺序与逻辑顺序相同
15. 某链表中最常用的操作是在最后一个元素之后插入一个元素和删除最后一个元素,则采用( D )存储方式最节省运算时间。
(A)单链表
(B)双链表
(C)单循环链表
(D)带头结点的双循环链表
16. 循环链表的主要优点是( D ) 。
(A)不再需要头指针了
(B)已知某个结点的位置后,能够容易找到他的直接前趋
(C)在进行插入、删除运算时,能更好的保证链表不断开
(D)从表中的任意结点出发都能扫描到整个链表
17. 下面关于线性表的叙述错误的是( B )。
(A) 线性表采用顺序存储,必须占用一片地址连续的单元;
(B) 线性表采用顺序存储,便于进行插入和删除操作;
(C) 线性表采用链式存储,不必占用一片地址连续的单元;
(D) 线性表采用链式存储,便于进行插入和删除操作;
18. 单链表中,增加一个头结点的目的是为了(C )。
(A) 使单链表至少有一个结点 (B)标识表结点中首结点的位置
(C)方便运算的实现 (D) 说明单链表是线性表的链式存储
19. 若某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用(D )存储方式最节省运算时间。
(A) 单链表 (B) 仅有头指针的单循环链表
(C) 双链表 (D) 仅有尾指针的单循环链表
20. 若某线性表中最常用的操作是取第i个元素和找第i个元素的前趋元素,则采用( )存储方式最节省运算时间(B )。
(A) 单链表 (B) 顺序表
(C) 双链表 (D) 单循环链表
21. 一个向量(一种顺序表)第一个元素的存储地址是100,每个元素的长度为2,则第5个元素的地址是_______。
A. 110 B. 108
C. 100 D. 120
答:
B
[第5个元素的地址=100+2*(5-1)=108]
22. 不带头结点的单链表head为空的判定条件是______。
A. head = = NULL; B. head->next = = NULL;
C. head->next = = head; D. head!
= NULL;
答:
A
23. 带头结点的单链表head为空的判定条件是______。
A. head = = NULL; B. head->next = = NULL;
C. head->next = = head; D. head!
= NULL;
答:
B
24. 在循环双链表的p所指结点之后插入s所指结点的操作是_____。
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;
答:
D
25. 在一个单链表中,已知q所指结点是p所指结点的前驱结点,若在q和p之间插入s结点,则执行______。
A. s->next=p->next; p->next=s; B. p->next=s->next; s->next=p;
C. q->next=s; s->next=p; D. p->next=s; s->next=q;
答:
C
26. 从一个具有n个结点的单链表中查找其值等于x结点时,在查找成功的情况下,需平均比较_____个结点。
(参见网上讲义:
1.4.2例1_5)
A. n; B. n/2;
C. (n-1)/2; D. (n+1)/2;
答:
D
27. 给定有n个结点的向量,建立一个有序单链表的时间复杂度_______。
A. O
(1); B. O(n);
C. O(n
); D. O(nlog
n);
答:
C
三、 填空题
28. 在一个长度为n的向量中的第i个元素(1≤i≤n)之前插入一个元素时,需向后移动_____个元素。
答:
n-i+1
29. 在一个长度为n的向量中删除第i个元素(1≤i≤n)时,需向前移动_____个元素。
答:
n-i
30.在一个单链表中p所指结点之前插入一个由指针s所指结点,可执行以下操作:
s->next=__p->next_____;
p->next=s;
t=p->data;
p->data=___s->data________;
s->data=___t________;
四、算法设计题:
31. 有一个单链表(不同结点的数据域值可能相同),其头指针为head,编写一个函数计算数据域为x的结点个数。
解:
本题是遍历通过该链表的每个结点,每遇到一个结点,结点个数加1,结点个数存储在变量n中。
实现本题功能的函数如下:
int count (head, x)
node *head;
ElemType x;
{
node *p;
int n=0;
p=head;
while (p!
=NULL)
{
if (p->data= =x) n++;
p=p->next;
}
return(n);
}
32. 有一个有序单链表(从小到大排序),表头指针为head,编写一个函数向该单链表中插入一个元素为x的结点,使插入后该链表仍然有序。
解:
本题算法的思想是先建立一个待插入的结点,然后依次与链表中的各结点的数据域比较大小,找出该结点的位置,最后插入该结点。
实现本题功能的函数如下:
node *insertorder(head, x)
node *head;
ElemType x;
{
node *s, *p, *q;
s=(node *)malloc(sizeof(node));
s->data=x;
s->next=NULL;
if (head= =NULL ‖ xdata)
{
s->next=head;
head=s;
}
else
{
q=head;
p=q->next;
while (p!
=NULL && x>p->data)
if (x > p->data)
{
q=p;
p=p->next;
}
s->next = p;
q->next=s;
}
return(head);
}
33. 编写一个函数将一个头指针为a的单链表A分解成两个单链表A和B,其头指针分别为a和b,使得A链表中含有原链表A中序号为奇数的元素,而B链表中含有原链表A中序号为偶数的元素,且保持原来的相对顺序。
解:
其函数是将单链表A中的所有偶数序号的结点删除,并在删除时把这些结点链接起来构成单链表B。
实现本题功能的函数如下:
void disa(a, b)
node *a, *b;
{
node *r, *p, *q;
p=a;
b=a->next;
r=b;
while (p!
=NULL && p->next!
=NULL)
{
q = p->next;
p->next=q->next;
r->next=q;
r=q
p=p->next;
}
r->next=NULL;
}
34. 假设有两个已排序的单链表A和B,编写一个函数将它们合并成一个链表C而不改变其排序性。
解:
这里采用链表合并的方法,设原两链表的头指针分别为p和q,每次比较p->data和q->data的值,把值较小的结点作为新链表的结点,这一过程直到一个链表为空为止。
当一个链表为空而另一个链表不为空时,只要将不空的链表指针赋给新链表中最后一个结点的指针即可。
实现本题功能的函数如下:
node *mergelink(p, q)
node *p, *q;
{
node *h, *r;
h=(node *)malloc(sizeof(node));
h->next=NULL;
r=h;
while (p!
=NULL && q!
=NULL)
if (p->data<=q->data)
{
r->next=p;
r=p;
p=p->next;
}
else
{
r->next=q;
r=q;
q=q->next;
}
if (p= =NULL)
r->next=q;
if (q= =NULL)
r->next=p;
/*下面三句要去掉链表C的头结点,如果不想去掉,则不要这三句*/
p=h->next;
h=h->next;
free(p);
return h;
}
35.设A=(a
…,a
)和B=(b
…,bn)均为顺序表,A’和B’分别为A和B中除去最大共同前缀后的子表(例如,A=(x,y,y,z,x,z),B=(x,y,y,z,y,x,x,z),则两者中最大的共同前缀为(x,y,y,z),在A’=B’=空表,则A=B;若A’=空表,而B’<>空表,或者两者均不为空表,且A’的首元小于B’的首元,则AB。
(词典次序)试写一个比较A,B大小的算法(在算法中,不要破坏原表A和B,并且不一定先求得A’和B’才进行比较)。
36. 设有一个用向量表示的线性表L,要求写出一个将该表逆置的过程,并允许在原表的存储空间外再增加一个附加的工作单元。
(朱儒荣, C语言版数据结构考研例题)
解:
用数据类型描述Seqlist顺序存储结构:
vold converts(seqlist L)
{ k=L.length;
m = k/2;
for(i = 0;i x = L.element[i];
L.element[i] = L.element[k-i-1];
L.element[k-i-1] = x;
}
} // converts
讨论:
这个算法过程只须进行数据元素的交换操作,其主要时间花费在for循环上,整个算法的时间复杂度为O(k)。
37. 已知两个整数集合A和B,它们的元素分别依元素值递增有序存放在两个单链表HA和HB中,编写一个函数求出这两个集合的并集C,并要求集合C的链表的结点仍依元素值递增有序存放。
(提示:
求并集不是归并!
)
38. 已知两个顺序表A和B分别表示两个集合,其元素递增排列,编写一个函数求出A和B的交集C,要求C同样以元素递增的顺序表形式存储。
void SqList_Intersect(SqList A,SqList B,SqList &C)
//求元素递增排列的线性表A和B的元素的交集并存入C中
{
i=0;j=0;k=0;
while(A.elem[i]&&B.elem[j]) {
if(A.elem[i]if(A.elem[i]>B.elem[j]) j++;
if(A.elem[i]==B.elem[j]) {
C.elem[k++]=A.elem[i];
//当发现了一个在A,B中都存在的元素,
i++;j++;
//就添加到C中
}
}//while
}//SqList_Intersect
算法设计题:
27.假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的队列初始化、入队列和出队列的算法。
解:
voidInitCiQueue(CiQueue&Q)//初始化循环链表表示的队列Q
{
Q=(CiLNode*)malloc(sizeof(CiLNode));
Q->next=Q;
}//InitCiQueue
voidEnCiQueue(CiQueue&Q,intx)//把元素x插入循环链表表示的队列Q,Q指向队尾元素,Q->next指向头结点,Q->next->next指向队头元素
{
p=(CiLNode*)malloc(sizeof(CiLNode));
p->data=x;
p->next=Q->next;//直接把p加在Q的后面
Q->next=p;
Q=p;//修改尾指针
}
StatusDeCiQueue(CiQueue&Q,intx)//从循环链表表示的队列Q头部删除元素x
{
if(Q==Q->next)returnINFEASIBLE;//队列已空
p=Q->next->next;
x=p->data;
Q->next->next=p->next;
free(p);
returnOK;
}//DeCiQueue
28.利用两个栈s1,s2模拟一个队列时,如何用栈的运算来实现该队列的运算:
enqueue:
插入一个元素;
dequeue:
删除一个元素;
queue_empty:
判定队列为空。
解:
由于栈的特点是先进后出,为了模拟先进先出的队列,必须用两个栈,一个栈s1用于插入元素,另下栈s2用于删除元素,每次删除元素时应将前一个栈的所有元素读出然后进入第二个栈中,这样才能达到模拟队列的效果,这里使用栈的一些基本操作如下:
push(ST,x):
栈的压入
ptop(ST,x):
退出栈顶元素赋给x
sempty(ST):
判定栈是否为空
voidenqueue(s1,x)
stacks1;
intx;
{
if(s1->top==m0)printf(“队列上溢出!
\n”);
elsepush(s1,x);
}
voiddequeue(s1,s2,x)
stacks1,s2;
intx;
{
s2->top=0;
while(!
sempty(s1))
push(s2,ptop(s1));
ptop(s2,x);
while(!
sempty(s2))
push(s1,ptop(s2));
}
intqueue_empty(s1)
stacks1;
{
ifsempty(s1)return
(1);
elsereturn(0);
}
29.假设称正读和反读都相同的字符序列为“回文”(即回文是指一个字符序列以中间字符为基准两边字符完全相同),例如,‘abba’和‘abcba’是回文,‘ababab’则不是回文。
试编写一个判断读入的一个以‘@’为结束符的字符序列是否“回文”的算法。
解:
[解题思路:
判断回文算法Palindrome_Test()的思想是:
把字符串中的字符逐个分别存入队列和堆栈,然后逐个出队列和退栈并比较出队列的数据元素和退栈的数据元素是否相等,若全部相等则该字符序列是回文,否则就不是回文。
]
实现本题功能的函数如下(类C编写):
intPalindrome_Test()//判别输入的字符串是否是回文序列,是则返回1,否则返回0
{
Initstack(S);InitQueue(Q);
while((c=getchar())!
=‘@’)
{
Push(S,c);EnQueue(Q,c);//同时使用栈和队列两种结构
}
while(!
StackEmpty(S))
{
Pop(S,a);DeQueue(Q,b);
if(a!
=b)returnERROR;
}
returnOK;
}//Palindrome_Test
数据结构-串(上)
(2010-07-0202:
05:
15)
标签:
校园
判断题:
1.空串是由空白字符组成的串( FALSE )
2. 串的定长顺序结构是用一组地址连续的存储单元存储串值的字符序列,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。
(TRUE )
3.串的堆分配存储表示是用一组地址连续的存储单元存储串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。
(TRUE )
4.串中StrInsert(&S,pos,T)基本操作是最小的操作子集(FALSE)
5.串是由有限个字符构成的连续序列,串长度为串中字符的个数,子串是主串中字符构成的有限序列。
(FALSE)
(错:
子串是主串中连续的字符构成的有限序列)
(题源:
胡元义,C版数据结构课程辅导与习题解析,p80,4.2.1(判