纯小白蓝桥杯备赛笔记--DAY8(必备排序算法)

冒泡排序

在这里插入图片描述

算法思想

  • 每次将最大的一下一下地运到最右边,然后确定这个最大的,接着可以发现该问题变成一个更小的子问题。
  • 具体操作:从左向右扫描,如a[i]>a[i+1],执行swap操作。
  • 代码格式
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N]; 
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    //i表示当前要确定的位置
    for(int i=n;i>=1;i--)
    {
        for(int j=0;j<i-1;j++) // 修改这里,将范围改为从0到i-1
        {
            if(a[j]>a[j+1])swap(a[j],a[j+1]);
        }
     } 
     //输出
     for(int i=0;i<n;i++)cout<<a[i]<<(i==n?"\n":" "); 
    return 0;
}

  • 时间复杂度为平方级,所以适用于数字比较少的情况。

选择排序

在这里插入图片描述

选择排序的思想

  • 与冒泡排序的区别是每次找出最大的放在最右边。
  • 具体操作:
    计算出最大元素的下标,max_id,执行swap操作swap(a[max_id],a[i])

实现

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N]; 
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    //i表示当前要确定的位置
    for(int i=n-1;i>=0;i--) 
    {
        int max_id=0; 
        for(int j=0;j<=i;j++) 
        {
            if(a[j]>a[max_id])max_id=j;
        }
        swap(a[max_id],a[i]);
     } 
     //输出
     for(int i=0;i<n;i++)cout<<a[i]<<(i==n-1?"\n":" "); // 修改这里,将条件改为i==n-1
    return 0;
}

例题讲解

  • 上述代码改成从大到小排序:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N]; 
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    //i表示当前要确定的位置
    for(int i=0;i<n-1;i++) 
    {
        int max_id=i; 
        for(int j=i+1;j<n;j++) 
        {
            if(a[j]>a[max_id])max_id=j;
        }
        swap(a[i],a[max_id]);
     } 
     //输出
     for(int i=0;i<n;i++)cout<<a[i]<<(i==n-1?"\n":" "); // 修改这里,将条件改为i==n-1
    return 0;
}

插入排序

在这里插入图片描述

思想

  • 将待排序的序列依次插入到已排序的序列之中。

实现

//i表示当前要确定的位置 
for(int i=2;i<=n;++i)
{
	//此时[1,i-1]已经为有序数组
	int val=a[i],j;
	//将val和j比较,如果小于就往后移动,为val腾出位置
	for(j=i;j>1&&val<a[j-1];--j)
	{
		a[j]=a[j-1];
	 } 
	 //此时j为给val腾出的位置
	 a[j]=val; 
 } 

实现解释:

从第一个元素开始,该元素可以认为已经被排序;
取出下一个元素,在已经排序的元素序列中从后向前扫描;
如果该元素(已排序)大于新元素,将该元素移到下一位置;
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
将新元素插入到该位置后;
重复步骤2~5。
这段代码中的变量i表示当前要确定的位置,val表示当前要插入的值,j用于在已排序的数组中寻找插入的位置。在每次循环中,都会将val和j-1位置的元素进行比较,如果val小于a[j-1],则将a[j-1]向后移动一位,为val腾出位置。当找到合适的位置后,将val插入到该位置

#include<bits/stdc++.h>
using namespace std;
const int N=100;
int a[N];
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	//i表示当前要确定的位置 
for(int i=2;i<=n;++i)
{
	//此时[1,i-1]已经为有序数组
	int val=a[i],j;
	//将val和j比较,如果小于就往后移动,为val腾出位置
	for(j=i;j>1&&val<a[j-1];--j)
	{
		a[j]=a[j-1];
	 } 
	 //此时j为给val腾出的位置
	 a[j]=val; 
 } 
   for(int i=1;i<=n;++i)cout<<a[i]<<" ";
   return 0;

}

归并排序

在这里插入图片描述

思想

  • 将一个数组
  • 实现:将一个数组分成两个子数组,将子数组再向下递归的排序直至元素个数为1。然后将相邻的元素合并起来。
  • 在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N],b[N];
//归并排序的算法 
void MerageSort(int a[],int l,int r)
{
	//1.递归出口:左右边界相等
	if(l==r)return ;
	//2.取mid 
	int mid=(l+r)/2;
	//3.递归排序:左右两个区间分别排序 
	MerageSort(a,l,mid);
	MerageSort(a,mid+1,r);
	//4.设置指针
	int pl=l;int pr=mid+1;int pb=l;
	//5.两个指针合法,开始循环 
	while(pl<=mid||pr<=r)
	{
		if(pl>mid)
		{
			//左半边已经放完
			b[pb++]=a[pr++]; 
		}
		else if(pr>r)
		{
			//右半边已经放完
			b[pb++]=a[pl++]; 
		}
		else
		{
			//两边都还有元素,取最小值放到b数组中 
			if(a[pl]<a[pr])b[pb++]=a[pl++];
			else b[pb++]=a[pr++];
		}
	 } 
	 //完成后要把b数组复制回去a数组
	 for(int i=l;i<=r;++i)a[i]=b[i]; 
	 
 } 

int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	MerageSort(a,1,n);
	for(int i=1;i<=n;++i)cout<<a[i]<<(1==n?"\n":" ");
    return 0;
} 

快速排序

在这里插入图片描述

思想

快速排序是一种分治法的排序方法,原理是将一个数组分成两个子数组,其中一个子数组的所有元素都小于另一个子数组的元素,然后递归的对这两个子数组进行排序。
时间复杂度为O(nlogn),且不需要额外的空间。

实现

在这里插入图片描述

void QuickSort(int a[],int l,int r)
{
	if(l<r)
	{
		int mid=Partition(a,l,r);
		QuickSort(a,l,mid-1);
		QuickSort(a,mid+1,r);
	}
 } 
 int Partition(int a[],int l,int r)
 {
 	int pivot=a[r];//设a[r]为基准,这一次partition会将a[r]放到正确的位置上
	int i=l,int j=r;//设置两个下标,分别往中间走
	while(i<j)
	{
		while(i<j&&a[i]<=pivot)i++;//左边的小于基准,不需要交换,继续往中间走
		while(i<j&&a[j]>=pivot)j--;
		if(i<j)swap(a[i],a[j]);
		else swap(a[i],a[r]); 
	  }  
	  return i;
 	
 }

在这里插入图片描述- 完整版宝藏排序:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N];
 int Partition(int a[],int l,int r)
 {
 	int pivot=a[r];//设a[r]为基准,这一次partition会将a[r]放到正确的位置上
	int i=l;int j=r;//设置两个下标,分别往中间走
	while(i<j)
	{
		while(i<j&&a[i]<=pivot)i++;//左边的小于基准,不需要交换,继续往中间走
		while(i<j&&a[j]>=pivot)j--;
		if(i<j)swap(a[i],a[j]);
		else swap(a[i],a[r]); 
	  }  
	  return i;
 	
 }
void QuickSort(int a[],int l,int r)
{
	if(l<r)
	{
		int mid=Partition(a,l,r);
		QuickSort(a,l,mid-1);
		QuickSort(a,mid+1,r);
	}
 } 

 int main()
 {
 	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
 	int n;cin>>n;
 	for(int i=1;i<=n;++i)cin>>a[i];
 	QuickSort(a,1,n);
 	for(int i=1;i<=n;++i)cout<<a[i]<<(i==n?"\n":" ");
 	return 0;
 }

桶排序

思想

分类+分治。
把元素的值域分为若干段,每一段对应一个 桶。

操作

  • 将值域分为若干段,每一段对应一个桶。
  • 每个元素放在对应的桶中。
  • 对每个桶分别排序。
  • 按顺序把每个桶中的元素依次取出,合并成最终答案。

实现

  • 每个桶放一个元素
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 9;
int a[N];
int main()
{
 ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 int n;
 cin >> n;
 for(int i = 1; i <= n; i ++){
   int x;
   cin >> x;
   a[x]++;
 }
for(int i = 0; i <= n; i++) 
for(int j = 0; j < a[i]; j++) {
  cout << i << ' ';
}
  return 0;
}

  • 每个桶是一段区间
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+9;
vector<int>a[N];
int main()
{
 ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
 int n;
 cin >> n;
 for(int i = 1; i <= n; i ++){
   int x;
   cin >> x;
   a[x/1000].push_back(x);
 }
for(int i = 0; i <N; i++) //对每一个桶进行排序 
{
	sort(a+1,a+n+1);
}
for(int i=0;i<N;i++)
{
	for(auto item:a[i])
	{
		cout<<item<<" ";
	}
}
cout<<endl;
  return 0;
}

此时的时间复杂度为:每个桶排序的时间复杂度之和。

优势

  • 适用于数据量比较大,但是值域比较小。
  • 一个值 对应一个桶的情况的时间复杂度为O(n),此时很推荐使用桶排序。

例题

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int n,perc;
int bucket[607];
int  main()
{
	cin>>n>>perc;//输入成绩及获奖百分比 
	for(int i=1;i<=n;i++)
	{
		int x,sum=0;
		cin>>x;
		bucket[x]++;//将新成绩放入对应的桶中 
		for(int j=600;j>=0;j--)//从小到大枚举 每一个桶 
		{
			sum+=bucket[j];//统计当前成绩的个数
			if(sum>=max(1,perc*i/100)) 
			{
				cout<<j<<" ";
				break;//如果当前人数大于等于获奖比例,那么此时的分数线就为当前分数 
			}
		 } 
	}
}

未完待续,大家一起加油吧!!

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值