算法设计与结构 第二章 递归与分治策略 作业

知识补充:
在这里插入图片描述

判断题

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(N​2)

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;
} 

猜你喜欢

转载自blog.csdn.net/Jessieeeeeee/article/details/111870060