排序算法

冒泡排序 Bubble Sort

  一种简单的排序算法
  动图演示在这里插入图片描述

  比较相邻的元素
  一趟冒泡排序确定一个数的最终位置
  当输入的数据已经是正序时,排序最快
  当输入的数据是反序时,排序最慢 (for 循环反序输出数据)

时间复杂度:平均和最坏情况:O(N^2)
      最好情况:O(N)
空间复杂度:O(1)

  当有n个数要冒泡排序时,要进行n-1趟冒泡

for(int i=1;i<=n-1;i++){
	for(int j=1;j<=n-i;j++{
		if(a[j]>a[j+1]) swap(a[j],a[j+1]);	//从小到大排序
		if(a[j]<a[j+1]) swap(a[j],a[j+1]);	//从大到小排序
	}
}

优化

  立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。

for(int i=1;i<=n-1;i++){
	bool flag=false;
	for(int j=1;j<=n-i;j++{
		if(a[j]>a[j+1]) swap(a[j],a[j+1]);	//从小到大排序
		if(a[j]<a[j+1]) swap(a[j],a[j+1]);	//从大到小排序
		flag=true;
	}
	if(!flag) break;
}

选择排序 Selection Sort

  一种简单的排序算法
  动图演示在这里插入图片描述
  在未排序列中找到最小(大)元素,存放到序列的起始位置。
  一趟选择排序确定一个数的最终位置
  当有n个数要选择排序时,要进行n-1趟选择

时间复杂度:O(N^2)
空间复杂度:O(1)

for(int i=1;i<=n-1;i++){
	int x=i;
	for(int j=i;j<=n;j++){ 
		if(a[j]<a[x]) x=j;
	}
	swap(a[i],a[x]);
}

插入排序 Insertion Sort

  一种最简单直观的排序算法
  动图演示
在这里插入图片描述
  将第一个元素看做有序序列,把第二个元素到最后一个元素当做排序序列。
  当有n个数要插入排序时,要进行n-1趟插入

时间复杂度:平均和最坏情况:O(N^2)
      此时待排序列为逆序,或者说接近逆序
      最好情况下为O(N),此时待排序列为升序,或者说接近升序。
空间复杂度:O(1)

for(int i=2;i<=n;i++){
	int x=a[i];
	int j=i-1;
	while(j>=1&&a[j]>x){ //降序a[j]<x
		a[j+1]=a[j];
		j--;
	}
	a[j+1]=x;
}

希尔排序 Shell Sort

  希尔排序是插入排序的一种,它是针对直接插入排序算法的改进。
  希尔排序目的为了加快速度改进了插入排序,交换不相邻的元素对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。
  在此我们选择增量 gap=length/2,缩小增量以 gap = gap/2 的方式,用序列 {n/2,(n/2)/2…1} 来表示。
(1)初始增量第一趟 gap = length/2 = 4
在这里插入图片描述
(2)第二趟,增量缩小为 2
在这里插入图片描述
(3)第三趟,增量缩小为 1,得到最终排序结果
在这里插入图片描述

桶排序

  用数组做统计 (桶)
  动图演示
在这里插入图片描述

  当输入的数据可以均匀的分配到每一个桶中,排序最快
  当输入的数据被分配到了同一个桶中,排序最慢
  数组下标的范围:输入数字的范围

时间复杂度:O(N+K),K是桶的数量
空间复杂度:O(N+K),K是桶的数量

for(int i=1;i<=n;i++){
	cin>>x;
	a[x]++;
}
for(int i=0;i<=100;i++){ //降序 for(int i=100;i>0;i--)
	while(a[i]!=0){
		cout<<i<<" ";
		a[i]--;
	}
}

计数排序 Counting Sort

  线性排序算法
在这里插入图片描述

  1. 找出待排序的数组中最大和最小的元素;

   2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;

   3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);

   4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

基数排序 Radix Sort

  一种非比较排序算法
   1. 确定数组中的最大元素有几位(MAX)(确定执行的轮数)
  2. 创建0 ~ 9个桶(桶的底层是队列),因为所有的数字元素都是由0 ~ 9的十个数字组成
  3. 依次判断每个元素的个位,十位至MAX位,存入对应的桶中,出队,存入原数组;直至MAX轮结束输出数组。
在这里插入图片描述
在这里插入图片描述

时间复杂度:O(N*K),K是桶的数量
空间复杂度:O(N+K),K是桶的数量

sort排序

  STL排序函数
  sort(第一个下标 ,最后一个下标+1,比较函数名)
  sort无比较名,则默认为从小到大

bool cmp(int a,int b){
	return a<b; //从小到大
	return a>b; //从大到小
}
sort(a+1,a+n+1,cmp); 

归并排序 Merge Sort

  采用分治法的排序算法
  动图演示在这里插入图片描述
  分而治之在这里插入图片描述

时间复杂度:O(NlogN)
空间复杂度:O(n)

  不停的把序列分成两组,直到将序列分为一个个元素为止,再将一个个元素有序排序

int n,a[100010],temp[100010],cnt;
void mergesort(int l,int r){
	if(l<r){
		int mid=(l+r)/2;
		mergesort(l,mid);
		mergesort(mid+1,r);
		int i=l,j=mid+1,k=l-1;
		while(i<=mid&&j<=r){
			if(a[i]<=a[j]) temp[++k]=a[i++];
			else temp[++k]=a[j++];
		while(i<=mid) temp[++k]=a[i++];
		while(j<=r) temp[++k]=a[j++];
		for(int i=l;i<=r;i++){
			a[i]=temp[i];
		}
	}
}

快速排序 Quick Sort

  采用分治法的排序算法
  在冒泡排序基础上的递归分治法。

在这里插入图片描述
  从数列中挑出一个元素,称为 “基准”。
  重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。
  在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区操作;
  递归地把小于基准值元素的子数列和大于基准值元素的子数列排序;

时间复杂度:平均和最好情况:O(NlogN)
      最坏情况:O(N^2)
空间复杂度:O(1)

void quicksort(int l,int r){
	if(l>=r) return;
	int i=l,j=r;
	int k=a[i];
	while(i<j){
		while(i<j&&a[j]>=k) 
			j--;
		swap(a[i],a[j]);
		while(i<j&&a[i]<=k) 
			i++;
		swap(a[i],a[j]);
	}
	quicksort(l,i);
	quicksort(i+1,r);
	
	
}

堆排序 Heap Sort

  利用堆这种数据结构所设计的一种排序算法
  子结点的值总是小于(或者大于)它的父节点

   1. 升序排列:大顶堆:每个节点的值都大于或等于其子节点的值
   2. 降序排列:小顶堆:每个节点的值都小于或等于其子节点的值

   1. 将待排序序列构造成一个大顶堆
   2. 此时整个序列的最大值就是顶堆的根节点
   3. 将其与末尾元素进行交换,此时末尾就为最大值
   4. 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

1.假设给定无序序列结构如下
在这里插入图片描述
2.此时我们从最后一个非叶子节点开始。从左至右,从下至上进行调整,观察6的两个子节点,从右至左,9大于6就和6互换
在这里插入图片描述
3.找到第二个非叶子节点4,由于[4,9,8]中9元素最大,4和9交换
在这里插入图片描述
4.此时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6
在这里插入图片描述
5.此时我们就将一个无序序列构造成了一个大顶堆
6.将堆顶元素与末尾元素进行交换,使末尾元素最大,然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素,如此反复进行交换,重建,交换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

  稳定性:排序过程中,相同元素在排序后的相对位置保持不变
在这里插入图片描述

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值