第十章排序--交换类排序与选择类排序

本文深入探讨了排序算法中的关键概念,包括堆排序、冒泡排序等的实现原理与时间复杂度分析,提供了详细的代码示例。

一、判断题

1、

答案:F

解析:堆排序的空间复杂度是O(1),所以需要的额外空间就是O(1)


2、

答案:T


3、

答案:F


4、

答案:F

解析:基本有序一般指的是基本都是升序,不是完全。所有基本有序次数不一定最多,完全有序次数才最多。


二、单选题

1、

答案:C

解析:如果左右指针都会停止移动,也就意味着停下来就交换,这种情况对应的时间复杂度为O(nlogn)


2、

答案:D

解析:左右指针不停止移动的话,也就是假设第一个数为基准数,那么从左边开始移动指针的时候,最终将一直移动到第一个元素,选择的枢轴在序列的某一端,这种情况对应的时间复杂度为最差为O(n方)

每次都划分得很均匀,那么就是最优时间复杂度


3、

答案:D

解析:一个指针会移动,另一个指针根本没来得及动,会造成选择的主元在序列的某一端,这种情况对应的时间复杂度为最差为O(n方)


4、

答案:A


5、

答案:C

解析: 需要比较的次数为:N(N-1)/2


6、

答案:D

解析:

 

建堆的话,默认是建立大顶堆


7、

答案:C

解析:递归次数与初始数据的排列次序有关,与每次划分后得到的分区处理顺序无关


8、

答案:C


9、

答案:D

解析:以最左边位置的数据为基准,也就是46为基准

  • 46(左)、79、56、38、40、84(右)
  • 右指针移动,找到第一个比基准数小的,放到左边的位置    40(左)、79、56、38、40(右)、84
  • 左指针移动,找到第一个比基准数大的,放到右边的位置    40、79(左)、56、38、79(右)、84
  • 右指针移动,找到第一个比基准数小的,放到左边的位置    40、38(左)、56、38(右)、79、84
  • 左指针移动,找到第一个比基准数大的,放到右边的位置    40、38、56(左)、56(右)、79、84
  • 第一次移动的最终次序是  40、38、46(左)、56(右)、79、84

注意:开始移动的时候,不能除去第一个数据,应当加上基准数据

不动的值反而改变了


10、

答案:B

解析:493865、97、761327、50

491327、50、763865、97

注意:步长为4的意思是,从下个数开始数其,长度为4,而不是从这个数开始数起,长度为4


11、

答案:D

解析:挨个试一试就可以了


12、

答案:A

解析:对于交换次数而言,当最好的时候,交换为0次,最差的时候,也就初始排序,交换次数为n-1次,复杂度为O(n)。


13、

答案:A

解析:简单选择排序它最大的特点是交换移动数据次数相当少,这样也就节约了相应的时间,无论最好最坏的情况,其比较次数都是一样多。第 i 次排序需要进行n-i 次关键字的比较,此时需要比较n-1+n-2+...+1=n(n-1)/2次,时间复杂度为O(n^2)。对于交换次数而言,当最好的时候,交换为0次,最差的时候,也就初始排序,交换次数为n-1次,复杂度为O(n)


14、

答案:C


15、

答案:A


三、编程题

1、寻找大富翁 (25 分)

胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。

输入格式:

输入首先给出两个正整数N(≤10​6​​)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。

输出格式:

在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。

输入样例:

8 3
8 12 7 3 20 9 5 18

输出样例:

20 18 12

答案:

#include <bits/stdc++.h>

using namespace std;
//按照从小到大排序
void HeapAdjust(long A[],int parent,int length)
{
    int temp=A[parent];//temp保存当前父节点
    int child=2*parent+1;//先获得左孩子

    while(child<length) // 如果有右孩子结点
    {
        if(child+1<length&&A[child]>A[child+1])//右孩子结点的值小于左孩子结点,则选取右孩子结点
        {
            child+=1;
        }
        if(temp<A[child])
        {
            break;// 如果父结点的值已经小于孩子结点的值,则直接结束
        }
        A[parent]=A[child];
        // 选取孩子结点的左孩子结点,继续向下筛选
        parent=child;
        child=2*child+1;
    }
    A[parent]=temp;
}
void heapSort(long A[],int N)
{
    for(int i=N/2; i>=0; i--)
    {
        HeapAdjust(A,i,N);
    }
    for(int i=N-1; i>=0; i--) // 进行n-1次循环,完成排序
    {
        int temp=A[i];// 最后一个元素和第一元素进行交换
        A[i]=A[0];
        A[0]=temp;
        // 筛选R[0]结点,得到i-1个结点的堆
        HeapAdjust(A,0,i);
    }
}
int main()
{
    int N,M;
    long a[1000000];
    scanf("%d%d",&N,&M);
    for(int i=0; i<N; i++)
    {
        scanf("%ld",&a[i]);
    }
    heapSort(a,N);
    if(N<M)
    {
        for(int i=0; i<N; i++)
        {
            if(i==0)
                printf("%ld",a[i]);
            else
                printf(" %ld",a[i]);
        }
    }
    else
    {
        for(int i=0; i<M; i++)
        {
            if(i==0)
                printf("%ld",a[i]);
            else
                printf(" %ld",a[i]);
        }
    }
    return 0;
}

2、冒泡法排序 (20 分)

将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<bits/stdc++.h>
using namespace std;


int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int A[100000];
    for(int i=0; i<n; ++i)
        scanf("%d",&A[i]);
    int s=0;
    for(int j=1; j<n; j++)
    {
        for(int k=0; k<n-j; k++)
        {
            if(A[k]>A[k+1])
            {
                int l=A[k];
                A[k]=A[k+1];
                A[k+1]=l;
            }
        }
        s+=1;
        if(s==m)
        {
            for(int i=0; i<n; i++)
            {
                if(i==0)
                    printf("%d",A[i]);
                else
                    printf(" %d",A[i]);
            }
        }
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值