知识补充:
判断题
1-1
算法分析的两个主要方面是时间复杂度和空间复杂度的分析。
T F
1-2
在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。
T F
1-3
仅基于比较的算法能得到的最好的“最坏时间复杂度”是O(NlogN)。
T F
1-4
对N个记录进行快速排序,在最坏的情况下,其时间复杂度是O(NlogN)。
T F
1-5
(neuDS)直接插入排序算法在最好情况下的时间复杂度为O(n)。
T F
单选题
2-1
用二分查找从100个有序整数中查找某数,最坏情况下需要比较的次数是:
A.7
B.10
C.50
D.99
知识补充:
二分查找的最大比较次数是
二分搜索方法充分利用了元素间的次序关系,采用分治策略,可在最坏情况下用 O(logn) 时间完成搜索任务;
解析:log100 + 1 = 6 + 1 = 7;
2-2
用分治法解决一个规模为N的问题。下列哪种方法是最慢的?
A.每步将问题分成规模均为N/3的2个子问题,且治的步骤耗时O(N)
B.每步将问题分成规模均为N/3的2个子问题,且治的步骤耗时O(NlogN)
C.每步将问题分成规模均为N/2的3个子问题,且治的步骤耗时O(N)
D.每步将问题分成规模均为N/3的3个子问题,且治的步骤耗时O(NlogN)
C不仅子问题规模大,数目还多,合并子问题时间还长;
2-3
(NeuDS_C++)对线性表进行二分查找时,要求线性表必须( )。
A.以顺序方式存储
B.以链接方式存储
C.以顺序方式存储,且结点按关键字有序排序
D.以链接方式存储,且结点按关键字有序排序
2-4
下列排序算法中,哪种算法可能出现:在最后一趟开始之前,所有的元素都不在其最终的位置上?(设待排元素个数N>2)
A. 冒泡排序
B. 插入排序
C. 堆排序
D. 快速排序
2-5
给定 100,000,000 个待排记录,每个记录 256 字节,内存为128MB。若采用简单2路归并,需要做多少轮?
(2分)
A.10
B.9
C.8
D.7
1MB有4个记录,内存总共128×4 = 512个记录,512=29,则需要做 log 29 = 9(log以2为底)轮;
2-6
对N个记录进行归并排序,归并趟数的数量级是:
A.O(logN)
B.O(N)
C.O(NlogN)
D.O(N2)
2-7
对N个记录进行归并排序,空间复杂度为:
A.O(logN)
B.O(N)
C.O(NlogN)
D.O(N2)
2-8
采用递归方式对顺序表进行快速排序,下列关于递归次数的叙述中,正确的是:
A.每次划分后,先处理较长的分区可以减少递归次数
B.每次划分后,先处理较短的分区可以减少递归次数
C.递归次数与每次划分后得到的分区处理顺序无关
D.递归次数与初始数据的排列次序无关
2-9
若数据元素序列{ 12, 13, 8, 11, 5, 16, 2, 9 }是采用下列排序方法之一得到的第一趟排序后的结果,则该排序算法只能是:
A.快速排序
B.选择排序
C.堆排序
D.归并排序
2-10
在外排序中,设我们有5个长度分别为2、8、9、5、3的有序段。则下列哪种归并顺序可以得到最短归并时间?
A.归并长度为2和3的有序段,得到段Run#1;将Run#1与长度为5的有序段归并,得到段Run#2;将Run#2与长度为8的有序段归并,得到段Run#3;将Run#3与长度为9的有序段归并
B.归并长度为2和3的有序段,得到段Run#1;将Run#1与长度为5的有序段归并,得到段Run#2;归并长度为8和9的有序段,得到段Run#3;归并Run#2和Run#3
C.归并长度为2和3的有序段,得到段Run#1;归并长度为5和8的有序段,得到段Run#2;归并Run#1和Run#2,得到段Run#3;将Run#3与长度为9的有序段归并
D.归并长度为2和3的有序段,得到段Run#1;归并长度为5和8的有序段,得到段Run#2;将Run#2与长度为9的有序段归并,得到段Run#3;归并Run#1和Run#3
编程题
7-1 找第k小的数 (20分)
设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数。
提示:函数int partition(int a[],int left,int right)的功能是根据a[left]a[right]中的某个元素x(如a[left])对a[left]a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数。因此可以编制int find(int a[],int left,int right,int k)函数,通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。
输入格式:
输入有两行:
第一行是n和k,0<k<=n<=10000
第二行是n个整数
输出格式:
输出第k小的数
输入样例:
在这里给出一组输入。例如:
10 4
2 8 9 0 1 3 6 7 8 2
输出样例:
在这里给出相应的输出。例如:
2
# include <iostream>
using namespace std;
int partition(int a[], int left, int right) {
int i = left, j = right+1;
int x = a[left];
//将小于x的元素交换到左边区域,将大于x的元素交换到右边区域
while(true) {
while(a[++i] < x && i < right);
while(a[--j] > x);
if(i >= j)
break;
swap(a[i], a[j]);
}
a[left] = a[j];
a[j] = x;
return j;
}
int find(int a[], int left, int right, int k) {
int pos = partition(a, left, right);
if(k-1 == pos){
cout << a[k-1];
}else if(k-1 < pos){
find(a, left, pos-1, k);
}else if(k-1 > pos){
find(a, pos+1, right, k);
}
return 0;
}
int main() {
int n, k;
cin >> n >> k;
int a[n];
for(int i=0; i<n; i++){
cin >> a[i];
}
find(a, 0, n-1, k);
return 0;
}