算法05-排序算法

news2024/12/24 21:08:02

算法05-排序算法

    • 总结
    • 大纲要求
    • 【 3 】排序的基本概念
      • 各种排序算法
    • 【 3 】冒泡排序(Bubble Sort)
      • 冒泡排序
        • 排序规则
        • 冒泡排序优化
    • 【 3 】选择排序(Selection Sort)
    • 【 3 】插入排序(Insertion Sort)
        • 题目描述
    • 【 3 】计数排序(Counting Sort)
      • 1. 基本思想
      • 2. 实现逻辑
      • 3. 复杂度分析
      • 题目描述
    • 【 3 】 桶排序-附加
      • 桶排序
        • 桶排序应用
        • 模板
        • 题目描述-模板桶排序
        • 题目描述-带负数桶排序
        • 题目描述-年龄排序去重
        • 题目描述-统计得分
        • 题目描述-欢乐的跳
        • 题目描述-[NOIP1998 提高组] 拼数
    • 作业

在这里插入图片描述

总结

本系列为C++算法学习系列,会介绍 算法概念与描述,入门算法,基础算法,数值处理算法,排序算法,搜索算法,图论算法, 动态规划等相关内容。本文为排序部分。

大纲要求

【 3 】排序的基本概念
【 3 】冒泡排序
【 3 】选择排序
【 3 】插入排序
【 3 】计数排序

参考;https://www.cnblogs.com/itsharehome/p/11058010.html

【 3 】排序的基本概念

1、排序的概念:

就是将一组杂乱无章的数据按照一定的规律(升序或者降序)组织起来

2、排序码

通常数据元素有多个属性域,其中有一个属性域可用来区分元素,作为排序依据,该域即为排序码
作为排序依据的数据项称为“排序码”,也即数据元素的关键码。若关键码是主关键码,则对任意待排序序列,经排序后得到的结果是唯一的;若关键码是次关键码,排序结果可能不唯一,这是因为具有相同关键码的数据元素,这些元素再排序结果中,它们之间的位置关系与排序前不能保持。

3、术语解释
稳定排序、原地排序、时间复杂度、空间复杂度:

1、稳定排序:如果 a 原本在 b 的前面,且 a==b,排序之后 a 仍然在 b 的前面,则为稳定排序。
2、非稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 可能不在 b 的前面,则为非稳定排序。
3、原地排序:原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
4、非原地排序:需要利用额外的数组来辅助排序。
5、时间复杂度:一个算法执行所消耗的时间。
6、空间复杂度:运行完一个算法所需的内存大小。

4、内部排序

数据元素全部放在内存中的排序

5、外部排序

数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

各种排序算法

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
常见的内部排序算法有:
插入排序:
插入排序(Insertion Sort)、希尔排序(Shell Sort)
选择排序:
选择排序(Selection Sort)、堆排序(Heap Sort)
交换排序:
冒泡排序(Bubble Sort)、快速排序(Quick Sort)
归并排序(Merge Sort)
基数排序(Radix Sort)
计数排序(Counting Sort)
桶排序(Bucket Sort)

用一张图概括:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
In-place:占用常数内存,不占用额外内存
Out-place:占用额外内存
在这里插入图片描述

【 3 】冒泡排序(Bubble Sort)

冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有元素再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换像气泡一样慢慢“浮”到数列的顶端。

排序规则

每次比较相邻的元素,如果第一个比第二个大,就交换他们两个。对每—对相邻元素做同样的工作,从开始第一对到结尾的最后一对。经过一轮排序后,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每轮对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较,也就是已经是按照从小到大的顺序排列了。

在这里插入图片描述

每轮比较都会确定一个数字的位置,因此N个数字需要比较N-1轮。如如果是5个数比较,则

第一轮比较了4次,
第二轮比较3次,
第三轮比较2次,
第四轮比较1次,
那么第i轮比较的次数为N-i次。
每次比较均是对相邻两个数字作比较,直至最后。

#include <iostream>

using namespace std;

int main()
{
    int n;
    int a[6]={0,3,4,1,5,2};
    n=sizeof(a)/sizeof(int);
    cout<<n<<endl;
    int outres=0;
    for(int i=1;i<=n;i++)
    {
        outres++;
        int innerres=0;
        for(int j=1;j<=n-i;j++)
        {
            innerres++;
            if(a[j]>a[j+1])
            {
                swap(a[j],a[j+1]);
            }
            cout<<"执行的外循环次数-->"<<outres<<"执行的内循环次数-->"<<innerres<<endl;
        }
    }
    for(int i=1;i<=5;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

在这里插入图片描述

冒泡排序优化

参考:冒泡排序的三种优化
刚才对于序列{12,35,99,18,76}的排序过程中,我们不难发现,第二轮排序进行完之后,整个序列已经是有序的了,也就是说第二轮排序结束就可以不用接着进行接下来的比较了。

因此我们可以对刚才的程序进行优化,那么什么时候就可以结束排序过程呢?根据观察,我们发现当某轮排序过程中没有交换的发生,那么就说明序列已经有序,无需再次比较了。

#include <iostream>

using namespace std;

int main()
{
    int n;
    int a[6]={0,3,4,1,5,2};
    n=sizeof(a)/sizeof(int);
    cout<<n<<endl;
    int outres=0;
    for(int i=1;i<=n;i++)
    {
        bool flag=0;// 优化 标记是否有交换
        outres++;
        int innerres=0;
        for(int j=1;j<=n-i;j++)
        {
            innerres++;
            if(a[j]>a[j+1])
            {
                flag=1;//优化 有交换标记1
                swap(a[j],a[j+1]);
            }
            cout<<"执行的外循环次数-->"<<outres<<"执行的内循环次数-->"<<innerres<<endl;
        }
        if(flag==0)break;//优化 有交换标记1
    }
    for(int i=1;i<=5;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

如:
在这里插入图片描述

【 3 】选择排序(Selection Sort)

过程简单描述:

首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。其次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法我们称之为选择排序。

在这里插入图片描述

在这里插入图片描述
(从前向后,升序)每次从边界出发,第一个元素作为擂主(不动),和第二个元素进行比较,如果擂主小,那么不交换值,cur 继续向后走,下一个值继续和擂主比,直到最后一个元素和擂主比较完,这个时候第二个元素称为擂主,从第三个元素开始比较,直到比到最后。每一次打擂台都有可能打乱原有符合排序规则元素之间的原有位置,所以不稳定。

#include<iostream>
using namespace std;

// 选择排序 升序
// [0, bound)  是有序区间
// [bound, size) 是待排序区间
void SelectSort(int arr[], int size)
{
    if(arr == NULL || size <= 0){
        return;
    }
    int bound = 0;
    for(; bound < size; bound ++){
        int cur = bound + 1;
        for(; cur < size; cur ++){
            if(arr[bound] > arr[cur]){
                swap(arr[bound], arr[cur]);
            }
        }
    }
    return;
}

int main(){
	int a[10]{ 5,7,9,6,3,1,4,8 };
	SelectSort(a, 8);
	for (int i = 0; i < 8; i++)
	{
		cout << a[i]<<" ";
	}
}

在这里插入图片描述

【 3 】插入排序(Insertion Sort)

插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法—插入排序法。
插入排序的基本操作就是将一个数据插入到已经排好序的有序数列中,从而得到一个新的、个数加一的有序数列,算法适用于少量数据的排序。
在这里插入图片描述

1、从第一个元素开始,该元素被认为已被排序。
2、取出下一个元素,在已排序的序列中从后往前扫描。
3、如果该元素大于新元素,将该元素移到下一个位置。
4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。5、将新元素插入后,重复步骤2~5。

接下来我们以对序列{5,6,3,7,8,1}从小到大排序为例来讲解插入排序的具体过程。

第一步:有序序列为{5}。
第二个数6开始进行插入排序。因为5是小于6的,所以位置不
用改动。在第二个位置插入数字6,得到有序序列{5,6}。
第二步:有序序列为{5,6}。
第三个数3开始进行插入排序。由于5,6均大于3,因此数字5、6需要往后挪一个位置。然后再将3放到第一个位置。得到有序序列{3,5,6}。
第三步:有序序列为{3,5,6}。
第四个数1开始进行插入排序。由于3,5,6均大于1,因此数字3、5、6需要往后挪一个位置。然后再将1放到第一个位置。得到有序序列{1,3,5,6}。
第四步:有序序列为{1,3,5,6}。
第五个数8开始进行插入排序。由于1、3、5、6都是小于8的,所以位置不用改动。在最后一个位置插入数字8,得到有序序列{1,3,5,6,8}。
第五步:有序序列为{1,3,5,6,8}。
第七个数7开始进行插入排序。因为1、3、5、6都是小于7的,所以位置不用改动,由于8大于7,因此往后挪一个位置,然后在6和8之间插入数字7。得到有序序列{1,3,5,6,7,8}。
至此,整个插入排序过程完成。

#include <iostream>

using namespace std;

int a[10005];

int main()
{
    int n;
    int key,j;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=2;i<=n;i++){//从第二个开始排序
        key=a[i]; //待记录插入的数字
        j=i-1;//令j=已有序列的尾位置
        while(j>=1&&key<a[j]) //从后往前遍历序列已有序列,直到第一个比key小的位置
        {
            a[j+1]=a[j];//当前元素比关键字大,则往前插空
            j--;
        }
        a[j+1]=key;//直到无法前移的时候,将key插入空出的位置
    }
    for(int i=1;i<=n;i++) cout<<a[i]<<' ';
    return 0;
}

在这里插入图片描述

题目描述

在这里插入图片描述

在这里插入图片描述

【 3 】计数排序(Counting Sort)

计数排序(Counting sort)是一种稳定的线性时间排序算法。是桶排序的特殊情况,只需要划分,不需要进行桶排序的第二步的排序操作。
快排、堆排、归并等排序算法都是基于比较的排序算法,时间复杂度最好情况也只能降到O(nlogn)。
计数排序是一种线性排序算法,不需要进行比较,时间复杂度为O(n)。(注意是计数排序不是基数排序,两者不同)
基本思想是:对于每个元素x,找出比x小的数的个数,从而确定x在排好序的数组中的位置。此算法需要辅助数组,是以空间换时间。

1. 基本思想

计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),然后进行分配、收集处理:

① 分配。扫描一遍原始数组,以当前值-minValue作为下标,将该下标的计数器增1。
② 收集。扫描一遍计数器数组,按顺序把值收集起来。

2. 实现逻辑

① 找出待排序的数组中最大和最小的元素
② 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
③ 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
④ 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

在这里插入图片描述
举个例子
假设有无序数列nums=[2, 1, 3, 1, 5], 首先扫描一遍获取最小值和最大值,maxValue=5, minValue=1,于是开一个长度为5的计数器数组counter
(1) 分配

统计每个元素出现的频率,得到counter=[2, 1, 1, 0, 1],例如counter[0]表示值0+minValue=1出现了2次。

(2) 收集

counter[0]=2表示1出现了两次,那就向原始数组写入两个1,counter[1]=1表示2出现了1次,那就向原始数组写入一个2,依次类推,最终原始数组变为[1,1,2,3,5],排序好了。

3. 复杂度分析

平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n + k)
空间复杂度:O(n + k)

当输入的元素是n 个0到k之间的整数时,它的运行时间是 O(n + k)。。在实际工作中,当k=O(n)时,我们一般会采用计数排序,这时的运行时间为O(n)。

计数排序需要两个额外的数组用来对元素进行计数和保存排序的输出结果,所以空间复杂度为O(k+n)。

计数排序的一个重要性质是它是稳定的:具有相同值的元素在输出数组中的相对次序与它们在输入数组中的相对次序是相同的。也就是说,对两个相同的数来说,在输入数组中先出现的数,在输出数组中也位于前面。

计数排序的稳定性很重要的一个原因是:计数排序经常会被用于基数排序算法的一个子过程。我们将在后面文章中介绍,为了使基数排序能够正确运行,计数排序必须是稳定的。

题目描述

统计关键字的个数,放入数组C-图1
在这里插入图片描述

对C进行累加处理,为了找对应A的排好序的位置-图2
在这里插入图片描述

详细操作过程
在这里插入图片描述

 #include<string.h>
 #include<iostream>

  // 任何比较排序算法的时间复杂度的上限为O(NlogN), 不存在比o(nlgN)更少的比较排序算法。
  // 如果想要在时间复杂度上超过O(NlogN)的时间复杂度,肯定需要加入其它条件。计数排序就加入
  // 了限制条件,从而使时间复杂度为O(N).
  //
  // 计数排序的核心思想(来自算法导论):
  // 计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).
  // 对于每一个输入元素x, 确定小于等于x的个数为i。利用这一信息,就可以把元素x放到输出数组
  // 的正确位置,即把元素x放到输出数组下标为i-1的位置。
  //
  // 重要说明:
  // 1. 计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).
  // 此时使用计数排序可以把时间复杂度降到O(n)上。
  // 2. 计数排序不是基于比较的排序算法,它基于计数策略。
  // 3. 写计数排序算法时,应该把它写成稳定排序的。
  // 4. 计数排序还是原址排序,它需要借助额外的内存空间。
  //
  // 计数排序代码如下:
  // 参数说明:array表示数组指针,nLength_表示数组的最大长度,nMaxNumber_表示数组元素中的最大>  值;
  void CountingSort(int array[], int nLength_, int nMaxNumber_)
  {
      // 参数的合法化检测
      if (nullptr == array || nLength_ <= 1 || nMaxNumber_ <= 0)
          return;

      // 统计待排序数组中每一个元素的个数
      // 注意:此处new出来的数组的大小为nMaxNumber_ + 1, 用于统计[0, nMaxNumber_]范围内的元素
      int* ArrayCount = new int[nMaxNumber_ + 1]{0};
      for (int i = 0; i < nLength_; ++i)
      {
          ++ArrayCount[array[i]];
      }

      // 此处计算待排序数组中小于等于第i个元素的个数.
      // 备注:如果要进行大到小的排序,就计算大于等于第i个元素的个数, 也就从后向前进行累加;
      for (int i = 1; i < nMaxNumber_ + 1; ++i)
      {
          ArrayCount[i] += ArrayCount[i-1];
      }

      // 把待排序的数组放到输出数组中, 为了保持排序的稳定性,从后向前添加元素
      int* ArrayResult = new int[nLength_];
      for (int i = nLength_ - 1; i >=0; --i)
      {
          int _nIndex = ArrayCount[array[i]] - 1; // 元素array[i]在输出数组中的下标
          ArrayResult[_nIndex] = array[i];

          // 因为可能有重复的元素,所以要减1,为下一个重复的元素计算正确的下标;
          --ArrayCount[array[i]];
      }

      // 交换数据并释放内存空间
      memcpy(array, ArrayResult, sizeof(int) * nLength_);
      delete [] ArrayCount;
      ArrayCount = nullptr;
      delete [] ArrayResult;
      ArrayResult = nullptr;
  }

  // 测试代码
  /***************    main.c     *********************/
  static void PrintArray(int array[], int nLength_);
  int main(int argc, char* argv[])
  {
      int test[10] = {12, 12, 4, 0, 8, 5, 2, 3, 9, 8};
      std::cout << "排序前:" << std::endl;
      PrintArray(test, 10);
      CountingSort(test, 10, 12);
      std::cout << "排序后:" << std::endl;
      PrintArray(test, 10);

      return 0;
  }

  // 打印数组函数
  static void PrintArray(int array[], int nLength_)
  {
      if (nullptr == array || nLength_ <= 0)
          return;

      for (int i = 0; i < nLength_; ++i)
      {
          std::cout << array[i] << " ";
      }

      std::cout << std::endl;
  }

在这里插入图片描述

在这里插入图片描述

#include <iostream>
#include <vector>
using namespace std;

void CountSort(vector<int> &arr, int maxVal) {
	int len = arr.size();
	if (len < 1)
		return;
	vector<int> count(maxVal+1, 0);
	vector<int> tmp(arr);
	for (auto x : arr)
		count[x]++;
	for (int i = 1; i <= maxVal; ++i)
		count[i] += count[i - 1];
	for (int i = len - 1; i >= 0; --i) {
		arr[count[tmp[i]] - 1] = tmp[i];
		count[tmp[i]]--;				//注意这里要减1
	}
}

int main()
{
	vector<int> arr = { 1,5,3,7,6,2,8,9,4,3,3 };
	int maxVal = 9;
	CountSort(arr,maxVal);
	for (auto x : arr)
		cout << x << " ";
	cout << endl;
	return 0;
}

在这里插入图片描述

【 3 】 桶排序-附加

桶排序

参考:https://blog.csdn.net/m0_64036070/article/details/123826962
https://blog.csdn.net/Passerby_XX/article/details/123147928
桶排序是计数排序的升级版,也是分治算法。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。简言之,将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。

设置一个定量的数组当作空桶子。
寻访序列,并且把项目一个一个放到对应的桶子去。
对每个不是空的桶子进行排序。
从不是空的桶子里把项目再放回原来的序列中

桶排序算法中,待排序的数据量和桶的数量并不一定是简单的“一对一”的关系,更多场景中是“多对一”的关系,
在这里插入图片描述

桶排序应用

我们可以利用桶来完成去重计数的任务。
解决去重问题时,只需将每个数据装入桶中后,再根据桶中是否有数据( tong[i]>0),来输出对应的桶的编号,只输出1次而不要多次输出。
解决计数问题的时候,我们只需要输出桶中的数据即为元素出现的次数。
所以,桶排序其实类似于计数,利用了桶的编号天然有序的性质,过程类似于“唱票”。

模板

#include <bits/stdc++.h>
using namespace std;
int n;            //要给n个数排序
int bucket[1005]; //满足所有数不超过 bucket[x]的x

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		bucket[a]++; //进入相应的区域(桶)
					 //如果题目要求把重复的数删掉(去重)
		             //可以写 bucket[a]=1;
	}

	for(int i=0;i<=1005;i++) //要把所有区域里的数“拽”出来
		while(bucket[i]>0)
		{
			cout<<i<<' '; //i指的是数
			bucket[i]--;  //bucket[i]指的是区域 i里剩余数的数量
		}

	return 0;
}

在这里插入图片描述

题目描述-模板桶排序

【描述】有n个正整数,数字范围在1~10000之间,请你将这n个数字从小到大输出。n<=100000000。
【输入】输入共2行,第1行是n。第2行是n个整数.
【输出】1行。所有整数从低到高排序后的结果。
【样例输入】
10
1 2 3 4 6 5 9 8 7 0
【输出】
0 1 2 3 4 5 6 7 8 9

#include <bits/stdc++.h>
using namespace std;
int n;            //要给n个数排序
int bucket[10005]; //满足所有数不超过 bucket[x]的x

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		bucket[a]++; //进入相应的区域(桶)
					 //如果题目要求把重复的数删掉(去重)
		             //可以写 bucket[a]=1;
	}

	for(int i=0;i<=10000;i++) //要把所有区域里的数“拽”出来
//		while(bucket[i]>0)
//		{
//			cout<<i<<' '; //i指的是数
//			bucket[i]--;  //bucket[i]指的是区域 i里剩余数的数量
//		}
        for(int j=1;j<=bucket[i];j++)
        {
            cout<<i<<" ";
        }
	return 0;
}

题目描述-带负数桶排序

【描述】有n个正整数,数字范围在-1000~1000之间,请你将这n个数字从小到大输出。n<=100000000。
【输入】输入共2行,第1行是n。第2行是n个整数.
【输出】1行。所有整数从高到低排序后的结果。
【样例输入】
6
11 22 33 -44 -32 1
【输出】
33 22 11 1 -32 -44

#include <bits/stdc++.h>
using namespace std;
int n;            //要给n个数排序
int bucket[2001]; //满足所有数不超过 bucket[x]的x.-1000 1000 变化为0-2000

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		bucket[a+1000]++; //进入相应的区域(桶)
					 //如果题目要求把重复的数删掉(去重)
		             //可以写 bucket[a]=1;
	}

	for(int i=2000;i>=0;i--) //要把所有区域里的数“拽”出来
        for(int j=1;j<=bucket[i];j++)
        {
            cout<<i-1000<<" "; //减去1000
        }
	return 0;
}

在这里插入图片描述

题目描述-年龄排序去重

【描述】小明所在的学校近期统计了师生的年龄数据,教务处主任希望你帮忙把这些年龄按从小到大的顺序排序,重复的年龄只保留一个。作为编程小高手的你能帮他解决这个问题吗?
【输入】输入共2行,第1行是n。第2行是n个整数.
【输出】1行。所有整数去重后从低到高排序后的结果。
【样例输入】
6
11 12 12 10 11 13
【输出】
10 11 12 13

#include <bits/stdc++.h>
using namespace std;
int n;            //要给n个数排序
int bucket[105]; //满足所有数不超过 bucket[x]的x.-1000 1000 变化为0-2000

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		bucket[a]++; //进入相应的区域(桶)
					 //如果题目要求把重复的数删掉(去重)
		             //可以写 bucket[a]=1;
	}

	for(int i=1;i<=100;i++) //要把所有区域里的数“拽”出来
        if(bucket[i]) cout<<i<<" ";

	return 0;
}

在这里插入图片描述

题目描述-统计得分

【描述】北京市中小学刚刚结束期中测试,信息学老师想统计全市学生信息学成绩的得分情况,即某些分数的人数,以便改进教学内容和方法,提高同学们的信息学成绩,同学们写个程序,帮助老师实现吧。【输入】输入共3行,第1行是n和k。第2行是n个整数,第3行是k个得分;
【输出】1行k个整数,分别为k个得分的人数;
【样例输入】
6 2
11 12 12 10 11 13
12 13
【输出】
2 1

#include <bits/stdc++.h>
using namespace std;
int n,k,score;            //要给n个数排序
int bucket[105]; //满足所有数不超过 bucket[x]的x.-1000 1000 变化为0-2000
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		bucket[a]++; //进入相应的区域(桶)
					 //如果题目要求把重复的数删掉(去重)
		             //可以写 bucket[a]=1;
	}
	for(int i=1;i<=k;i++)
    {
        cin>>score;
        cout<<bucket[score]<<" ";
    }

	return 0;
}

在这里插入图片描述

题目描述-欢乐的跳

【题目描述】
一个 n n n 个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了 [ 1 , n − 1 ] [1,n-1] [1,n1] 之间的所有整数,则称之符合“欢乐的跳”,如数组 { 1 , 4 , 2 , 3 } \{1,4,2,3\} {1,4,2,3} 符合“欢乐的跳”,因为差的绝对值分别为: 3 , 2 , 1 3,2,1 3,2,1

给定一个数组,你的任务是判断该数组是否符合“欢乐的跳”。

【输入格式】

每组测试数据第一行以一个整数 n ( 1 ≤ n ≤ 1000 ) n(1 \le n \le 1000) n(1n1000) 开始,接下来 n n n 个空格隔开的在 [ − 1 0 8 , 1 0 8 ] [-10^8,10^8] [108,108] 之间的整数。

【输出格式】

对于每组测试数据,输出一行若该数组符合“欢乐的跳”则输出 Jolly,否则输出 Not jolly

【样例 #1】

【样例输入 #1】

4 1 4 2 3

【样例输出 #1】

Jolly

【样例 #2】

【样例输入 #2】

5 1 4 2 -1 6

【样例输出 #2】

Not jolly

【 提示】

1 ≤ n ≤ 1000 1 \le n \le 1000 1n1000
在这里插入图片描述在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int a[1100],b[1100],n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int j=1;j<=n-1;j++)
    {
        b[j]=abs(a[j]-a[j+1]);
    }
    sort(b+1,b+1+n-1);
    int s =0;
    for(int k=1;k<=n-1;k++)
    {
        if(b[k]==k)s++;
    }
    if(s==n-1)cout<<"Jolly";
    else cout<<"Not jolly";
	return 0;
}

在这里插入图片描述

题目描述-[NOIP1998 提高组] 拼数

【 题目描述】
设有 n n n 个正整数 a 1 … a n a_1 \dots a_n a1an,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。
【 输入格式】
第一行有一个整数,表示数字个数 n n n
第二行有 n n n 个整数,表示给出的 n n n 个整数 a i a_i ai
【 输出格式】
一个正整数,表示最大的整数

【 样例 】1
【 样例输入 】1

3
13 312 343

【 样例输出 】1

34331213

【 样例 】2

【 样例输入 】2

4
7 13 4 246

【 样例输出 】2

7424613

【 提示】

对于全部的测试点,保证 1 ≤ n ≤ 20 1 \leq n \leq 20 1n20 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1ai109
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
bool cmp(string a,string b){
    return a+b>b+a;
}
int main()
{
    string a[22];
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n.cmp);
    for(int i=1;i<=n;i++) cout<<a[i];

	return 0;
}
#include <bits/stdc++.h>
using namespace std;
bool cmp(string a,string b){
    return a+b>b+a;
}
int main()
{
    string a[22],key;
    int n,j;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=2;i<=n;i++)
    {
        key =a[i];
        for(j=i-1;j>=1;j--)
        {
            if(key+a[j]>a[j]+key) a[j+1]=a[j];//key要插入到a[j]前
            else break;
        }
        a[j+1]=key;
    }
    for(int i=1;i<=n;i++) cout<<a[i];
	return 0;
}

在这里插入图片描述

作业

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/686433.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么高效编写企业内部FAQ文档呢?

企业内部FAQ文档是指包含常见问题和答案的文档&#xff0c;旨在为企业内部员工提供帮助和解答。编写这样的文档可以帮助企业内部员工更好地理解和掌握公司的政策和流程&#xff0c;提高工作效率。 编写企业内部FAQ文档的一些高效方法&#xff1a; 确定文档的范围和目标受众 …

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境 安装Visual Studio 2022 Community安装oneAPI建立Fortran工程项目测试建立单核运行的Fortran运行算例建立并行运行的Fortran运行算例 结语 安装Visual Studio 2022 Community 访问微软Visual Studio官网&#xff…

SpringBoot 如何使用 Redis 作为缓存?

SpringBoot 如何使用 Redis 作为缓存&#xff1f; 引言 在今天的互联网应用中&#xff0c;缓存是一个非常重要的概念。缓存可以减轻数据库的负担&#xff0c;提高系统的性能。Redis 是一个非常流行的内存数据库&#xff0c;它可以用作缓存&#xff0c;提供快速的读写速度和高…

【C语言初阶(1)】分支语句

文章目录 前言1. if 语句1.1 if 语法结构1.2 悬空 else1.3 “ ” 号引发的错误1.4 if 语句练习题 2. switch 语句2.1 switch 语法结构2.2 在switch语句中的 break2.3 default 子句2.4 switch 语句练习题 前言 C语言是一门结构化的程序设计语言&#xff1b; 它分为&#xff1a;…

【MySQL】不就是多表查询综合练习

前言 嗨咯大家好&#xff01;我们学习完毕了多表查询&#xff0c;今天我们就要对我们所学的成果进行测验&#xff0c;本期主要是对多表查询相关内容的练习课程。可以先试着自己敲&#xff0c;遇到不会可以查看查考代码。 目录 前言 目录 练习题 1.查询员工的姓名、年龄、职位…

生物制药厂洁净区环境监测超限的标准是多少?

对于一些生物制药企业来说&#xff0c;质量管理部门应加深对环境监测的质量认识&#xff0c;掌握环境监测的技术手段&#xff0c;定期评估环境监测程序的有效性和完整性&#xff0c;并且对环境监测数据进行趋势分析以寻找可以更好控制的区域&#xff0c;以保证企业的生产符合GM…

网络安全合规-网络安全工程师(一)

网络安全工程师的工作种类很多&#xff0c;当前这个图片说明了具体的工程师的工作种类有哪些&#xff0c;列举了一下。 互联网时代网络及科技迅速发展&#xff0c;随之而来的首要问题就是网络安全&#xff0c;因为已经出现的网络问题带来了巨大的经济损失&#xff0c;甚至各种…

ModaHub魔搭社区:安装、启动 Milvus 服务(CPU版)教程

目录 安装、启动 Milvus 服务 安装前提 操作系统 硬件 软件 确认 Docker 状态 拉取 Milvus 镜像 下载配置文件 启动 Milvus Docker 容器 常见问题 接下来你可以 安装、启动 Milvus 服务 CPU 版 MilvusGPU 版 Milvus 安装前提 操作系统 操作系统 版本 CentOS 7…

node 单线程、多线程和多进程模型

文章目录 node 启动过程单线程多线程node 启动过程相关线程node 多线程特点创建多线程 多进程创建多进程cluster进程守护 node 启动过程 C 层引导&#xff1a;Node.js 启动时&#xff0c;会初始化 C 层的结构和依赖项&#xff0c;如 V8 引擎、Libuv 事件循环、核心模块等。此外…

TCP/IP 协议详解

文章目录 简介应用层传输层网络层网络接口层数据包发送过程TCP 三次握手四次挥手三次握手为什么是三次握手四次挥手为什么是四次挥手 简介 TCP/IP传输协议&#xff0c;即传输控制/网络协议&#xff0c;也叫作网络通讯协议。它是在网络的使用中的最基本的通信协议。 TCP/IP传输…

【Nginx基础与应用】

文章目录 Nginx基础与应用1 Nginx 概述1.1 介绍1.2 下载与安装1.3 目录结构 2 Nginx 命令3 Nginx 配置文件结构4 Nginx 具体应用4.1 部署静态资源4.2 反向代理4.3 负载均衡(基于反向代理实现) Nginx基础与应用 1 Nginx 概述 1.1 介绍 Nginx是一款轻量级的web服务器/反向代理…

如何在 Linux 中安装、设置和使用 SNMP?

概要 SNMP&#xff08;Simple Network Management Protocol&#xff09;是一种用于管理和监控网络设备的协议。它允许网络管理员通过远程方式收集设备的运行状态、性能数据和错误信息&#xff0c;以便进行故障排除和网络优化。在Linux系统中&#xff0c;我们可以安装、设置和使…

vue3-element-admin 项目说明文档

vue3-element-admin官方文档 | 在线预览 项目介绍 vue3-element-admin 是基于 Vue3 Vite4 TypeScript5 Element-Plus Pinia 等最新主流技术栈构建的后台管理前端模板&#xff08;配套后端源码&#xff09;。 项目有以下特性&#xff1a; 基于 vue-element-admin 升级到…

共建信创安全生态|安全狗正式加入麒麟软件安全生态联盟

5月25日&#xff0c;麒麟软件安全生态联盟第二次工作会议顺利举办。 作为国内云原生安全领导厂商&#xff0c;安全狗以安全生态联盟成员单位应邀参会并发表重要观点。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&#xff09;成立于2013年&#xff0c;致力于…

无向图G的邻接矩阵法和邻接表法以及遍历输出无向图G包括两种存储的FirstNeighbor和NextNeighbor两种基本操作

一.邻接矩阵法 将下列图G用邻接矩阵法进行存储 圆圈中的字符&#xff1a;是顶点的值 圆圈旁边的数字&#xff1a;是顶点的序号 边线上的值&#xff1a;是两个顶点之间的权值 1.结构体 #define MaxVertexNum 10 typedef char VerTexType;//顶点的数据类型 typedef int Edg…

prometheus + grafana + node_exporter + alertmanager 的安装部署与邮件报警

背景介绍 Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发&#xff0c;是Google BorgMon监控系统的开源版本。 Prometheus的特点 多维度数据模型。 灵活的查询语言。 不依赖分布式存储&#xff0c;单个服务器节点是自主的。 通…

二值化的mask生成yolov5-7.0的实例分割训练标签

背景&#xff1a;要用yolov5-7.0训练分割&#xff0c;这里使用自己的数据&#xff0c;mask是二值化的数据&#xff0c;要先转换成COCO格式&#xff0c;这里用imantics实现。 详见&#xff1a;https://zhuanlan.zhihu.com/p/427096258 截取部分代码如下图&#xff0c;读取image图…

C++之引用、指针引用、常引用

引用 引用的概念引用的定义引用的使用引用的应用引用的本质&#xff08;就是C内部的一个常指针(type * const 名)&#xff09;指针引用&#xff08;其类型还是指针type *&#xff09;常引用&#xff08;采用const修饰的引用&#xff09; 引用的概念 1、通常我们说的引用指的是…

和鲸社区数据分析每周挑战【第九十五期:奈飞股价预测分析】

和鲸社区数据分析每周挑战【第九十五期&#xff1a;奈飞股价预测分析】 文章目录 和鲸社区数据分析每周挑战【第九十五期&#xff1a;奈飞股价预测分析】一、前言1、背景描述2、数据说明3、数据集预览 二、数据读取和数据预处理三、历史股价数据可视化四、利用sklearn中LinearR…

Linux 系统下的df、du、fdisk、lsblk指令

文章目录 1 查看磁盘与目录容量&#xff08;df、du&#xff09;2 查看磁盘分区&#xff08;fdisk、lsblk&#xff09;3 df、du、fdisk、lsblk的区别 1 查看磁盘与目录容量&#xff08;df、du&#xff09; df -h //列出文件系统的整体磁盘使用量在显示的结果中要特别留意根目录…