判断题
1、仅基于比较的算法能得到的最好的“最坏时间复杂度”是O(NlogN)
。
T
2、对N个记录进行简单选择排序,比较次数和移动次数分别为O(N2)
和O(N)
。
T
3、对N个不同的数据采用冒泡排序进行从大到小的排序,当元素基本有序时交换元素次数肯定最多。
F 当元素基本有序时,交换元素元素肯定较少。
4、要从50个键值中找出最大的3个值,选择排序比堆排序快。
T 选择排序就是在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
5、对N个记录进行快速排序,在最坏的情况下,其时间复杂度是O(NlogN)
。
F 对N个记录进行快速排序,在最坏的情况下,其时间复杂度是O(n^2)
。
6、直接插入排序算法在最好情况下的时间复杂度为O(n)。
T
单选题
1、下列排序算法中,哪种算法可能出现:在最后一趟开始之前,所有的元素都不在其最终的位置上?(设待排元素个数N>2)
A.冒泡排序
B.插入排序
C.堆排序
D.快速排序
B
在插入排序中,如果待排序列中的最后一个元素其关键字值为最小,则在最后一趟开始之前,前n-1个排好序的元素都不在其最终位置
上,与排好序后的位置相差一个位置。
2、对于7个数进行冒泡排序,需要进行的比较次数为:
A.7
B.14
C.21
D.49
C
6+5+4+3+2+1+0=21
3、排序方法中,从未排序序列中依次取出元素与已排序序列中的元素进行比较,将其放入已排序序列的正确位置的方法称为:
A.插入排序
B.选择排序
C.快速排序
D.归并排序
A
4、对于10个数的简单选择排序,最坏情况下需要交换元素的次数为:
A.9
B.36
C.45
D.100
A
简单选择排序在最坏情况下,会经过n-1次选取最值,才能完成排序。
由于交换只发生在找到最值后,因此交换次数等于找到最值的次数,为n-1。
5、若数据元素序列{ 12, 13, 8, 11, 5, 16, 2, 9 }是采用下列排序方法之一得到的第一趟排序后的结果,则该排序算法只能是:
A.快速排序
B.选择排序
C.堆排序
D.归并排序
D
快速排序一次后,有两个值相同,有一个数存放在临时变量,因此不是快速排序。
前2个元素和后2个元素均不是最小或最大的2个元素并按序排列,因此不是冒泡排序和选择排序。
对该元素序列建堆,发现不符合堆排序第一趟排序后的结果,因此不是堆排序。
序列中两两元素有序排列,因此是2路归并排序。
6、设有1000个元素的有序序列,如果用二分插入排序再插入一个元素,则最大比较次数是:
A.1000
B.999
C.500
D.10
D
二分查找的时间复杂度为O(logN)
。
对log1000向上取整为10,向下取整为9。
则比较次数为10,二分次数为9。
7、对初始状态为递增序列的表按递增顺序排序,最费时间的是()算法。
A.快速排序
B.归并排序
C.插入排序
D.堆排序
A
快速排序:最好情况一趟比较可以划分两等份nlogn,最坏相对有序n^2
归并排序:最好最坏都是nlogn
插入排序:最好相对有序n,最坏n^2
堆排序:最好最坏都是nlogn
8、对序列{15,9,7,8,20,-1,4}进行排序,进行一趟后数据的排列变为{4,9,-1,8,20,7,15},则采用的是()排序法。
A.快速
B.希尔
C.冒泡
D.选择
B
希尔排序:
{15,9,7,8,20,-1,4}
第一趟
{4,9,7,8,20,-1,15}
{4,9,-1,8,20,7,15}
第二趟:
{-1,9,4,8,15,7,20}
{-1,7,4,8,15,9,20}
{-1,4,7,8,9,15,20}
9、就平均性能而言,目前最好的内排序方法是()排序法。
A.希尔
B.冒泡
C.快速
D.交换
C
书P206第二段第二行
10、对序列{15,9,7,8,20,-1,4,} 用希尔排序方法排序,经一趟后序列变为{15,-1,4,8,20,9,7}则该次采用的增量是()。
A.2
B.1
C.4
D.3
C
11、下列排序算法中,()算法可能会出现下面情况:在最后一趟开始之前,所有元素都不在其最终的位置上。
A.快速排序
B.堆排序
C.冒泡排序
D.插入排序
D
在插入排序中,如果待排序列中的最后一个元素其关键字值为最小,则在最后一趟开始之前,前n-1个排好序的元素都不在其最终位置
上,与排好序后的位置相差一个位置。
12、数据序列{ 3, 1, 4, 11, 9, 16, 7, 28 }只能是下列哪种排序算法的两趟排序结果?
A.冒泡排序
B.快速排序
C.插入排序
D.堆排序
B
冒泡排序和选择排序:不符合,两边都不是最大最小,排除。
插入排序:数组开头并未有序,排除。
所以是快速排序。
13、若数据元素序列{ 11,12,13,7,8,9,23,4,5 }是采用下列排序方法之一得到的第二趟排序后的结果,则该排序算法只能是:
A.冒泡排序
B.选择排序
C.插入排序
D.归并排序
C
前2个元素和后2个元素均不是最小或最大的2个元素并按序排列,因此不是冒泡排序和选择排序。
第一趟排序结束后不存在若干个有序子序列,因此不是归并排序。
14、对于快速排序,当待排记录有序时,每回划分均以第一个元素作为枢轴,如下说法正确的是:
A.适用于顺序存储结构,算法时间复杂度是O(N)
B.适用于链式存储结构,算法时间复杂度是O(N)
C.适用于顺序存储结构,算法时间复杂度是O(N^2)
D.适用于链式存储结构,算法时间复杂度是O(N^2)
C
快速排序适用于数组(顺序存储结构)排序。
快速排序的最坏(序列有序)时间复杂度为O(n^2)。
15、在对N个元素进行排序时,基于比较的算法中,其“最坏时间复杂度”中最好的是:
A.O(logN)
B.O(N)
C.O(NlogN)
D.O(N^2)
C
基于比较操作的排序算法有插入排序,冒泡排序,快速排序,归并排序。
其中归并排序的最坏时间复杂度最小,为O(nlogn)
。
16、在基于比较的排序算法中,哪种算法的最坏情况下的时间复杂度不高于O(NlogN)
?
A.冒泡排序
B.归并排序
C.希尔排序
D.快速排序
B
冒泡排序的最坏时间复杂度为O(n^2)
归并排序的最坏时间复杂度为O(nlogn)
希尔排序的最坏时间复杂度为O(nlog2n)
快速排序的最坏时间复杂度为O(n^2)
程序填空题
1、冒泡排序
本题要求用冒泡排序将一组整数按增序排序。冒泡排序每次从头到尾扫描待排序列,检查相邻两数的顺序,如果顺序不对就交换。请补全下列冒泡排序的代码。
typedef struct node *nodeptr;
struct node{
int value;
nodeptr next;
/* 一些其他的项,在此忽略 */
};
nodeptr BubbleSort (nodeptr h)
{/* h 是带空头结点的链表的头指针 */
nodeptr p, q;
int flag_swap;
if (!h->next) return h;
do{
flag_swap = 0;
p = h;
while (p->next->next){
if ( p->next->value>p->next->next->value ){//p->next->value>p->next->next->value
flag_swap++;
q = p->next;
p->next=q->next;//p->next=q->next
q->next=p->next->next;//q->next=p->next->next
p->next->next=q;//p->next->next=q
}
else p = p->next;
}
} while (flag_swap > 0);
return h;
}
2、希尔排序的分步结果
本题要求给出希尔排序对给定初始序列{9, 8, 7, 6, 5, 4, 3, 2, 1}利用增量序列{1, 3, 7}进行排序的分步结果。将每步结果填在下列空中。注
意:相邻数字间必须有一个空格,开头结尾不得有多余空格。
原始序列 | 9 8 7 6 5 4 3 2 1 |
---|---|
增量7排序后 | 2 1 7 6 5 4 3 9 8 |
增量3排序后 | 2 1 4 3 5 7 6 9 8 |
增量1排序后 | 1 2 3 4 5 6 7 8 9 |
2 1 7 6 5 4 3 9 8
2 1 4 3 5 7 6 9 8
3、归并排序(递归法)
归并排序(递归法)。
#include <iostream>
#define MAXSIZE 1000
using namespace std;
typedef struct
{
int key;
char *otherinfo;
}ElemType;
typedef struct
{
ElemType *r;
int length;
}SqList;
void Create_Sq(SqList &L)
{
int i,n;
cin>>n; //输入的值不大于 MAXSIZE
for(i=1;i<=n;i++)
{
cin>>L.r[i].key;
L.length++;
}
}
void show(SqList L)
{
int i;
for(i=1;i<=L.length;i++)
if(i==1)
cout<<L.r[i].key;
else
cout<<" "<<L.r[i].key;
}
void Merge(ElemType R[],ElemType T[],int low,int mid,int high)
{
int i,j,k;
i=low; j=mid+1;k=low;
while(i<=mid&&j<=high)
{
if(R[i].key<=R[j].key) T[k++]=R[i++];
else T[k++]=R[j++];
}
while(i<=mid)
T[k++]=R[i++];
while(j<=high)
T[k++]=R[j++];
}
void MSort(ElemType R[],ElemType T[],int low,int high)
{
int mid;
ElemType *S=new ElemType[MAXSIZE];
if(low==high)
T[low]=R[low];//T[low]=R[low]
else
{
mid=(low+high)/2;
MSort(R,S,low,mid);//MSort(R,S,low,mid)
MSort(R,S,mid+1,high);//MSort(R,S,mid+1,high)
Merge(S,T,low,mid,high);//Merge(S,T,low,mid,high)
}
}
void MergeSort(SqList &L)
{
MSort(L.r,L.r,1,L.length);
}
int main()
{
SqList R;
R.r=new ElemType[MAXSIZE+1];
R.length=0;
Create_Sq(R);
MergeSort(R);
show(R);
return 0;
}
输入样例:
第一行输入一个数n,接下来输入n个数。
7
24 53 45 45 12 24 90
输出样例:
输出排序结果。
12 24 24 45 45 53 90
编程题
1、快速排序
本题要求实现快速排序的一趟划分函数,待排序列的长度1<=n<=1000。
函数接口定义:
int Partition ( SqList L, int low, int high );
其中L是待排序表,使排序后的数据从小到大排列。 ###类型定义:
typedef int KeyType;
typedef struct
{
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
裁判测试程序样例:
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct
{
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
void CreatSqList(SqList *L);/*待排序列建立,由裁判实现,细节不表*/
int Partition ( SqList L,int low, int high );
void Qsort ( SqList L,int low, int high );
int main()
{
SqList L;
int i;
CreatSqList(&L);
Qsort(L,1,L.Length);
for(i=1;i<=L.Length;i++)
printf("%d ",L.elem[i]);
return 0;
}
void Qsort ( SqList L,int low, int high )
{
int pivotloc;
if(low<high)
{
pivotloc = Partition(L, low, high ) ;
Qsort (L, low, pivotloc-1) ;
Qsort (L, pivotloc+1, high );
}
}
/*你的代码将被嵌在这里 */
输入样例:
第一行整数表示参与排序的关键字个数。第二行是关键字值 例如:
10
5 2 4 1 8 9 10 12 3 6
输出样例:
输出由小到大的有序序列,每一个关键字之间由空格隔开,最后一个关键字后有一个空格。
1 2 3 4 5 6 8 9 10 12
//书P208
int Partition(SqList L,int low,int high)
{
int flag=L.elem[low];//选定低位为轴值
L.elem[0]=L.elem[low];//将轴值存放在临时变量中
while(low!=high){//开始分割,low、high不断向中间移动,直到相遇
while(L.elem[high]>=flag&&low<high)//当前元素大于轴值且指针未相遇
high--;//high指针向左移动一步
L.elem[low]=L.elem[high];//将逆置元素放到左边的位置
while(L.elem[low]<=flag&&low<high)//当前元素小于轴值且指针未相遇
low++;//low指针向右移动一步
L.elem[high]=L.elem[low];//将逆置元素放到右边的位置
}
L.elem[low]=L.elem[0];//把轴值回填到分界位置上
return low;//返回分界位置
}
2、堆排序
本题要求实现堆排序中的筛选函数,待排序列的长度1<=n<=1000。
函数接口定义:
void HeapAdjust( HeapType H, int s, int m);
其中L是待排序表,使排序后的数据从小到大排列。 ###类型定义:
typedef int KeyType;
typedef struct {
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
typedef SqList HeapType;
裁判测试程序样例:
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct {
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
typedef SqList HeapType;
void CreatSqListHeapType *L);/*待排序列建立,由裁判实现,细节不表*/
void HeapAdjust( HeapType H, int s, int m);
void HeapSort( HeapType H);
int main()
{
HeapType L;
int i;
CreatSqList(&L);
HeapSort(L);
for(i=1;i<=L.Length;i++)
{
printf("%d ",L.elem[i]);
}
return 0;
}
void HeapSort( HeapType H)
{ /*堆顺序表H进行堆排序*/
int i; KeyType rc;
/*建立初始堆*/
for( i=H.Length/2;i>0; i--)
{
HeapAdjust(H, i, H.Length);
}
for(i=H.Length;i>1;i--)
{
rc=H.elem[1];
H.elem[1]=H.elem[i];
H.elem[i]=rc;
HeapAdjust(H, 1, i-1);
}
}
/*你的代码将被嵌在这里 */
输入样例:
第一行整数表示参与排序的关键字个数。第二行是关键字值 例如:
10
5 2 4 1 8 9 10 12 3 6
输出样例:
输出由小到大的有序序列,每一个关键字之间由空格隔开,最后一个关键字后有一个空格。
1 2 3 4 5 6 8 9 10 12
//书P123,P125(最小堆)
//本题要求为最大堆
void HeapAdjust(HeapType H,int s,int m)//该函数在HeapSort函数中循环进行
{//s为父节点,i=2*s为左子节点,i+1=2*s+1为右子结点
KeyType temp=H.elem[s];//保存父结点
for(int i=2*s;i<=m;i*=2){//过筛
if(H.elem[i]<H.elem[i+1]&&i<m)//若有右子结点且key值大于左子结点
i++;//指向右子结点
if(temp>=H.elem[i])//如果父结点比左(右)子结点的key值大,退出循环
break;
H.elem[s]=H.elem[i];
s=i;//将key值大的结点变为父结点
}
H.elem[s]=temp;
//将父结点与key值大的结点交换位置
//temp=H.elem[s]
//H.elem[s]=H.elem[i]
//H.elem[s]=temp;
}
3、冒泡法排序
将N个整数按从小到大排序的冒泡排序法是这样工作的:从头到尾比较相邻两个元素,如果前面的元素大于其紧随的后面元素,则交换它们。通过一遍扫描,则最后一个元素必定是最大的元素。然后用同样的方法对前N−1个元素进行第二遍扫描。依此类推,最后只需处理两个元素,就完成了对N个数的排序。
本题要求对任意给定的K(<N),输出扫描完第K遍后的中间结果数列。
输入格式:
输入在第1行中给出N和K(1≤K<N≤100),在第2行中给出N个待排序的整数,数字间以空格分隔。
输出格式:
在一行中输出冒泡排序法扫描完第K遍后的中间结果数列,数字间以空格分隔,但末尾不得有多余空格。
输入样例:
6 2
2 3 5 1 6 4
输出样例:
2 1 3 4 5 6
#include<iostream>
using namespace std;
int main(void)
{
int a[10086],N,K,item;
cin>>N>>K;
for(int i=0;i<N;++i)
cin>>a[i];
for(int i=0;i<K;++i){
for(int j=0;j<N-1;++j){
if(a[j]>a[j+1]){
item=a[j];
a[j]=a[j+1];
a[j+1]=item;
}
}
}
for(int i=0;i<N-1;++i)
cout<<a[i]<<" ";
cout<<a[N-1];
return 0;
}
4、快速排序
给定包含n个元素的整型数组a[1],a[2],...,a[n],利用快速排序算法对其进行递增排序,请输出排序过程,即每次Partition之后的数组。每次选择所处理的子数组的第一个元素作为基准元素。
输入格式:
输入为两行,第一行为一个整数n(1<n≤1000),表示数组长度。第二行为n个空格间隔的整数,表示待排序的数组。
输出格式:
输出为若干行,每行依次输出Partition后的数组,每个元素后一个空格。
输入样例:
5
4 5 3 2 1
输出样例:
2 1 3 4 5
1 2 3 4 5
1 2 3 4 5
#include<iostream>
using namespace std;
int n;
void print(int *arr)//输出
{
for(int i=0;i<n;++i)
cout<<arr[i]<<" ";
cout<<endl;
}
void swap(int &a,int &b)//交换位置
{
int temp=a;
a=b;
b=temp;
}
void quicksort(int *arr,int left,int right)//快速排序
{
if(left>=right)
return;//递归出口
int l=left;//left为数组首位下标:0
int r=right;//right为数组末尾下标:n-1
int key=arr[left];//设定轴值为数组第一个元素
while(l<r){//或l!=r
while(l<r&&arr[r]>key)//arr[r]>key
r--;
while(l<r&&arr[l]<=key)//arr[l]<=key
l++;
swap(arr[r],arr[l]);
}
//设定新轴值,此时左边数都小,右边数都大
swap(arr[l],arr[left]);//arr[l]也可换成arr[r],因为此时l=r
print(arr);//输出每次快速排序后的数组
quicksort(arr,left,l-1);//对轴值左侧进行快速排序
quicksort(arr,l+1,right);//对轴值右侧进行快速排序
}
int main(void)
{
cin>>n;
int arr[n];
for(int i=0;i<n;++i)
cin>>arr[i];
quicksort(arr,0,n-1);
for(int i=0;i<n;++i)
cout<<arr[i]<<" ";
return 0;
}
5、寻找大富翁
胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。
输入格式:
输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。
输出格式:
在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。
输入样例:
8 3
8 12 7 3 20 9 5 18
输出样例:
20 18 12
#include<iostream>
using namespace std;
#define MAXN 1000000
int num[MAXN];
int main(void)
{
int n,m,count=0;
cin>>n>>m;
for(int i=0;i<n;++i)
cin>>num[i];
for(int i=0;i<n;++i){//选择排序
int max=i;//设定最大值下标为i
for(int j=i+1;j<n;++j)
if(num[j]>num[max])
max=j;//修改最大值下标为j
int temp=num[i];//将最大值放到数组前
num[i]=num[max];
num[max]=temp;
count++;
if(count==1)
cout<<num[i];
else
cout<<" "<<num[i];
if(count==m)
break;
}
return 0;
}