数据结构月考 1 - 循序表+链表+堆栈+队列+数据结构基本知识点+时间复杂度计算
一.判断题
若一个栈的输入序列为{1, 2, 3, 4, 5},则不可能得到{3, 4, 1, 2, 5}这样的出栈序列。T
空间复杂度是根据算法写成的程序在执行时占用存储单元的长度,往往与输入数据的规T
在用数组表示的循环队列中,front值一定小于等于rear值。F
在存储空间使用上,顺序存储结构比链式存储结构更灵活。F
可以通过少用一个存储空间的方法解决循环队列中队空和队满条件的区分。T
顺序表是一种随机存取的存储结构。T
堆栈适合解决处理顺序与输入顺序相同的问题。F
它适合解决处理顺序与输入顺序相反的问题
抽象数据类型中,描述数据类型的方法与实现操作的算法和编程语言有关。F
线性表采用链式存储结构时,各个数据元素的存储单元地址一定是不连续的。F
栈是后进先出的线性表。T
两个栈共享一片连续空间,可以将两个栈的栈底分别设在这片空间的两端。 T
数据元素是数据的最小单位。F
数据元素还包含数据项,数据项是数据的最小单位
对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。 T
题目字眼 “ 顺序存储 ” ,说明内存单元中分配的存储空间是连续的,所 以该线性表为数组形式存储,所以数组访问时,通过下标可随机访问,时间复杂度为O(1),而增加插入时,需要涉及大量元素的移动,所以时间复杂度为O(N)。
若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用顺序表存储最节省时间。T
将N个数据按照从小到大顺序组织存放在一个单向链表中。如果采用二分查找,那么查找的平均时间复杂度是O(logN)。F
二分查找是不可以用链表存储的
在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。 F
访问为O(N)因为要从头指针遍历,而增加新的结点只需要新申请一块空间即可
(neuDS)在顺序表上进行插入、删除操作时需要移动元素的个数与待插入或待删除元素的位置无关。F
二.单选题
1.以下关于数据结构的说法中错误的是( )。
A.数据结构涉及数据的逻辑结构、存储结构和施加其上的操作3个方面
B.数据结构操作的实现与存储结构有关
C.定义逻辑结构时可不考虑存储结构
D.数据结构相同,对应的存储结构也相同
2.双链表 - 插入结点
在双链表中,将 s 所指新结点插入到 p 所指结点之前,其语句应该为 ▁▁▁▁▁ 。
A.p->prev->next = s; p->prev = s; s->prev = p->prev; s->next = p;
B.s->prev = p->prev; s->next = p; p->prev->next = s; p->prev = s;
C.p->prev = s; p->prev->next = s; s->prev = p->prev; s->next = p;
D.s->prev = p->prev; s->next = p; p->prev = s; p->prev->next = s;
3.循环链表的主要优点是()。
A.已知某个结点的位置后,能够很容易找到它的直接前驱
B.从表中的任意结点出发都能扫描到整个链表
C.在进行插入、删除运算时,能更好的保证链表不断开
D.不再需要头指针了
4.在图状结构中,数据元素之间除同属于一个集合外, ▁▁▁▁▁ 。
A.不存在其他的关系
B.存在多对多的关系
C.存在一对一的关系
D.存在一对多的关系
5.在数据结构中,与所使用的计算机无关的是数据的( )结构。
A.物理
B.逻辑和存储
C.逻辑
D.存储
数据结构中,与所使用的计算机无关的是数据的逻辑结构。数据结构包括逻辑结构和物理(存储)结构两个层次。逻辑结构从逻辑关系上描述数据,与数据的存储无关,是独立于计算机的。
6.下面代码段的时间复杂度是()。
i=1;
while( i<=n ) i=i*3;
A.O(log3n)
B.O(n)
C.O(1)
D.O(n2)
7.若(a-b)*(c+d)-e是中缀表达式,则其后缀表达式是( )。
A.ab-*cd+e-
B.ab-cd+*e-
C.abcde-*+-
D.abcde-+*-
8.假设以行序为主序存储二维数组A=array[1..40,1..20],设每个数据元素占2个存储单元,基地址LOC[1,1]为2000,则LOC[11,14]的存储位置为( ).
A.2468
B.2428
C.2426
D.2466
9.某个车站呈狭长形,宽度只能容下一台车,并且只有一个出入口。已知某时刻该车站状态为
空,从这一时刻开始的出入记录为:“进,出,进,进,出,进,进,进,出,出,进,出”。
假设车辆入站的顺序为1,2,3,……,则车辆出站的顺序为( )。
A.1, 2, 3, 4, 5
B.1, 3, 5, 6, 7
C.1, 3, 6, 5, 7
D.1, 2, 4, 5, 7
E.1, 3, 5, 4, 6
10.设C语言数组Data[m+1]作为循环队列SQ的存储空间, front为队头指针,rear为队尾指针,则执行出队操作的语句为( )。
A.rear=(rear+1)%(m+1)
B.front=(front+1)%(m+1)
C.front=(front+1)% m
D.front=front+1
11.若采用三元组表存储结构存储稀疏矩阵 M,则除三元组表外,下列数据中还需要保存的是
I、 M 的行数
II、 M 中包含非零元素的行数
III、 M 的列数
IV、 M 中包含非零元素的列数
A.仅 I、III
B.仅 I、IV
C.I、II、III、IV
D.仅 II、IV
如果采用三元组表存储稀疏矩阵 M,除了三元组表外,还需要保存的是该稀疏矩阵 M 的行数(rows)和列数(cols),因为三元组表只存储了稀疏矩阵中非零元素的值及其所在的行列下标,而没有存储稀疏矩阵的整体尺寸。因此,需要额外保存稀疏矩阵 M 的行数和列数信息,以便在对其进行各种运算时能正确地按照矩阵的规模进行操作。
12.在单链表L中,若删除p所指结点(非尾结点)的直接后继结点,修改指针的语句应为( )。
A.p=p->next->next;
B.p->next=p->next;
C.p=p->next; p->next=p->next->next;
D.p->next=p->next->next;
13.在树形结构中,数据元素之间除同属于一个集合外, ▁▁▁▁▁ 。
A.存在一对多的关系
B.存在一对一的关系
C.不存在其他的关系
D.存在多对多的关系
14.下列对顺序存储的有序表(长度为 n)实现给定操作的算法中,平均时间复杂度为 O(1) 的是:
A.查找包含指定值元素的算法
B.删除第 i(1≤i≤n)个元素的算法
C.插入包含指定值元素的算法
D.获取第 i(1≤i≤n)个元素的算法
15.阅读下列程序,其功能是()。
typedef struct {
ElemType *list;
int size;
intMaxSize;
}SeqList;
void fun1(SeqList&L) {
inti, j;
ElemType temp;
for (i=0, j= L.sise-1; i<j; i++, j--) {
temp=L.list[i];
L.list[i]=L.list[j];
L.list[j]=temp;
}
}
A.将顺序表原地逆置
B.将顺序表首尾元素对换
C.将链表首尾元素对换
D.将链表原地逆置
16.若线性表最常用的操作是存取第i个元素及其前驱的值,则采用( )存储方式节省时间。
A.顺序表
B.单链表
C.双向链表
D.单循环链表
17.若某线性表最常用的操作是存取任一指定序号的元素和在表尾进行插入和删除运算,则利用
( )存储方式最节省时间。
A.顺序表 B.双向链表 C.带头结点的双向循环链表 D.单循环链表
顺序表的特性,随机存取。另外在表尾删除,顺序表最后一个元素删除不需要移动元素。
18.某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用
( )存储方式最节省运算时间。
A.单链表 B.仅有头指针的单循环链表 C.双链表 D.仅有尾指针的单循环链表
表特点,插入删除方便,修改指针即可。但注意,在最后一个元素插入删除,有顺序表就选顺序表,没有顺序表,选链表就选带尾指针的,因为链表也需要从头结点遍历到尾节点,因此带尾指针的单循环链表最省时间。
19.设一个链表最常用的操作是在末尾插入结点和删除尾结点,则选用( )最节省时间。
A. 单链表 B.单循环链表 C. 带尾指针的单循环链表 D. 带头结点的双循环链表
链表操作,末尾插入删除,选择带尾指针的单循环链表的话,插入操作得遍历一遍;选择带头结点的双循环链表,前后都能到达,时间复杂度O(1).
20.若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点。则采用( )存储方式最节省运算时间。
A.单链表 B.双链表 C.单循环链表 D.带头结点的双循环链表
21.以下说法正确的是( )。
A.数据元素是数据的最小单位
B.数据项是数据的基本单位
C.数据结构是带有结构的各数据项的集合
D.一些表面上很不相同的数据可以有相同的逻辑结构
1.数据元素是指在数据集合中具有独立含义的基本单位,是数据处理的最小单位,也是数据的基本单位。
2.数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
22.通常要求同一逻辑结构中的所有数据元素具有相同的特性,这意味着( )。
A.数据元素所包含的数据项的个数要相等
B.不仅数据元素所包含的数据项的个数要相同,而且对应数据项的类型要一致
C.数据在同一范围内取值
D.每个数据元素都一样
23.与数据元素本身的形式、内容、相对位置、个数无关的是数据的( )。
A.存储结构
B.逻辑结构
C.存储实现
D.运算实现
数据的结构分为逻辑结构和存储结构,逻辑结构是数据元素逻辑关系的整体,与数据元素本身的内容和形式无关。
三.函数题
本题要求实现一个函数,在递增的整数序列链表(带头结点)中插入一个新整数,并保持该序列的有序性。
函数接口定义:
List Insert( List L, ElementType X );
其中List
结构定义如下:
typedef struct Node *PtrToNode; struct Node { ElementType Data; /* 存储结点数据 */ PtrToNode Next; /* 指向下一个结点的指针 */ }; typedef PtrToNode List; /* 定义单链表类型 */
L
是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Insert
要将X
插入L
,并保持该序列的有序性,返回插入后的链表头指针。
裁判测试程序样例:
#include <stdio.h> #include <stdlib.h> typedef int ElementType; typedef struct Node *PtrToNode; struct Node { ElementType Data; PtrToNode Next; }; typedef PtrToNode List; List Read(); /* 细节在此不表 */ void Print( List L ); /* 细节在此不表 */ List Insert( List L, ElementType X ); int main() { List L; ElementType X; L = Read(); scanf("%d", &X); L = Insert(L, X); Print(L); return 0; } /* 你的代码将被嵌在这里 */
输入样例:
5
1 2 4 5 6
3
输出样例:
1 2 3 4 5 6
List Insert(List L,ElementType X) { //首先要分两种情况,第一种,查到链表中间,第二种查到链表尾部 //插入链表中间的 //因为链表从小到大排序,所以我们需要两个指针记住,比插入的数大的 //和比插入的数小的, List p1 = L->Next; //比插入的数大的 List p2 = L; //比插入的数小的 //创建一个新节点,先将要插入的数放进一个新节点 List node = (List)malloc(sizeof(struct Node)); node->Data = X; node->Next = NULL; //让两个指针往后遍历,因为p1在前面,p1会先到链表尾部 //所以以 p1 为空为循环停止条件 while(p1) { //若数比插入的X小的话,就往后找 if(p1->Data<X) { p2=p1; p1=p1->Next; }else{ //此处就是找到了那个位置 node->Next=p1; p2->Next=node; return L ; } } //第二种情况,第二种查到链表尾部 //因为由上述循环已经遍历一次链表,p1已经为空,p2为链表末尾 //所以此时只需将新的结点接到链表尾部即可 p2->Next=node; return L; }
四.编程题
R7-1 两个有序链表序列的合并
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 3 5 -1
2 4 6 8 10 -1
输出样例:
1 2 3 4 5 6 8 10
注:在 C++ 中,结构体或类的构造函数名称必须与结构体或类的名称相同,因为构造函数是特殊的成员函数,用于初始化对象之后其它成员函数、变量的使用。如果构造函数与结构体或类名称不同,那么编译器将无法识别它是构造函数,从而导致编译错误。因此,在这个代码中,
node(int x)
就是struct node
的构造函数,名字需要和结构体名称node
一样。
#include<iostream> using namespace std; struct node { int val; node *next; //C++面对对象操作函数 node(int x):val(x),next(NULL){} }; int main() { //创建两个链表,链表的头部域一般不用来储存数据 node *head1=new node(0); node *head2=new node(0); //用两个指针分别指代head1,head2,因为合并链表时要用到两个链表的头部指针 node *p1=head1,*p2=head2; //进行输入操作 int num; while(cin>>num&&num!=-1) { p1->next=new node(num); p1=p1->next; } while(cin>>num&&num!=-1) { p2->next=new node(num); p2=p2->next; } //创建第三个链表用于合并,并用r指针指代head3; node *head3=new node(0); node *r=head3; //用p,q指代链表1,链表2,的数据节点 node *p=head1->next; node *q=head2->next; while(p&&q) { if(p->val<=q->val) { r->next=p; p=p->next; }else{ r->next=q; q=q->next; } r=r->next; } //因为两个链表长度不一样,那个短的会先遍历完,所以要接上长的链表后的数据 if(p)r->next=p; if(q)r->next=q; //遍历输出新链表,注:输出链表需要从新指针的数据节点开始 node *t=head3->next; if(t==NULL)cout<<"NULL"; while(t) { cout<<t->val; if(t->next)cout<<" "; t=t->next; } return 0; }
R7-2 队列的实现及基本操作
给定一个初始为空的队列和一系列入队、出队操作,请编写程序输出每次出队的元素。队列的元素值均为整数。
输入格式:
输入第1行为1个正整数n,表示操作个数;接下来n行,每行表示一个操作,格式为1 d或0。1 d表示将整数d入队,0表示出队。n不超过20000。
输出格式:
按顺序输出每次出队的元素,每个元素一行。若某出队操作不合法(如在队列空时出队),则对该操作输出invalid。
输入样例:
7
1 1
1 2
0
0
0
1 3
0
输出样例:
1
2
invalid
3
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; queue<int>s; int id,num; for(int i=0;i<n;i++) { cin>>id; if(id==1) { cin>>num; s.push(num); } if(id==0) { if(!s.empty()) { cout<<s.front()<<endl; s.pop(); }else{ cout<<"invalid"<<endl; } } } return 0; }