• 蒟蒻の常用排序算法总结



    参考题单:洛谷【算法1-2】排序

    update:2020/10/05 增加基数排序


    有比较的排序

    冒泡排序

    基本思想

    两个数比较大小,较大的数下沉,较小的数冒起来、

    过程

    比较相邻的两个数据,如果第二个数小,就交换位置

    从后向前两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置

    继续重复上述过程,依次将第2.3…n-1个最小数排好位置

    时间复杂度

    平均为 O ( n 2 ) O(n^2) O(n2)

    C o d e 1 Code_1 Code1 未优化

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[10010];
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=i;j++){
    			if(a[i]<a[j]){
    				swap(a[i],a[j]);
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		cout<<a[i]<<" ";
        }
    	return 0;
    }
    

    C o d e 2 Code_2 Code2 优化

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[10010];
    bool f;
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(int i=1;i<=n;i++){
    		f=false;
            for(int j=1;j<=i;j++){
    			if(a[i]<a[j]){
    				f=true;
                    swap(a[i],a[j]);
    			}
    		}
            if(!f){
    			break;
            }
    	}
    	for(int i=1;i<=n;i++){
    		cout<<a[i]<<" ";
        }
    	return 0;
    }
    

    例题

    P1116 车厢重组

    思路

    使用冒泡排序思想,每交换一次cnt+1,最后输出cnt即可

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[10010];
    int cnt;
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=i;j++){
    			if(a[i]<a[j]){
    				swap(a[i],a[j]);
    				cnt++;
    			}
    		}
    	}
    	cout<<cnt;
    	return 0;
    }
    

    插入排序

    基本思想:

    在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

    过程:

    时间复杂度

    平均为 O ( n 2 ) O(n^2) O(n2)

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[110];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<n;i++){
    		for(int j=i+1;j>0;j--){
    			if(a[j]<a[j-1]){
    				swap(a[j-1],a[j]);
    			}else{
    				break;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		printf("%d ",a[i]);
    	}
    	return 0;
    }
    

    选择排序

    基本思想:

    在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
    第二次遍历n-2个数,找到最小的数值与第二个元素交换;
    ……
    第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

    过程

    时间复杂度

    平均为 O ( n 2 ) O(n^2) O(n2)

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[110];
    int p;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<n;i++){
    		p=i;
    		for(int j=i+1;j<=n;j++){
    			if(a[j]<a[p]){
    				p=j;
    			}
    		}
    		if(p!=i){
    			swap(a[i],a[p]);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		printf("%d ",a[i]);
    	}
    	return 0;
    }
    

    归并排序

    基本思想:

    归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
    首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

    过程

    img

    时间复杂度

    平均为 O ( n log ⁡ n ) O(nlog{n}) O(nlogn)

    C o d e Code Code

    void inversion(int *c,int l,int mid,int r){
    	int i=l,j=mid+1,k=l;
    	while(i<=mid&&j<=r)
    		if(c[i]<=c[j])d[k++]=c[i++];
    		else{
    			d[k++]=c[j++];
    		}
    	while(i<=mid)
    		d[k++]=c[i++];
    	while(j<=r)
    		d[k++]=c[j++];
    	for(i=l;i<=r;i++)
    		c[i]=d[i];
    }
    void merge(int *c,int l,int r){
    	if(l<r){
    		int mid=(l+r)/2;
    		merge(c,l,mid);
    		merge(c,mid+1,r);
    		inversion(c,l,mid,r);
    	}
    }
    

    例题

    见“逆序对题解”

    快速排序

    基本思想:

    • 先从数列中取出一个数作为key值;
    • 将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
    • 对左右两个小数列重复第二步,直至各区间只有1个数。

    时间复杂度

    平均为 O ( n log ⁡ n ) O(nlog{n}) O(nlogn)

    C o d e Code Code

    void quickSort(int a[],int l,int r){
         if(l>=r)
           return;
         int i = l; int j = r; int key = a[l];//选择第一个数为key
         while(i<j){
             while(i<j && a[j]>=key)//从右向左找第一个小于key的值
                 j--;
             if(i<j){
                 a[i] = a[j];
                 i++;
             }
             while(i<j && a[i]<key)//从左向右找第一个大于key的值
                 i++;
             if(i<j){
                 a[j] = a[i];
                 j--;
             }
         }
         //i == j
         a[i] = key;
         quickSort(a, l, i-1);//递归调用
         quickSort(a, i+1, r);//递归调用
    

    无比较的排序

    桶排序

    基本思想:

    首先创建数组A[MaxValue];然后将每个数放到相应的位置上(例如17放在下标17的数组位置);最后遍历数组,即为排序后的结果。

    过程

    img

    时间复杂度

    平均为 O ( n ) O(n) O(n)

    空间复杂度

    当序列中存在较大值时,BinSort 的排序方法会浪费大量的空间开销。

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[110],x;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&x);
    		a[x]++;
    	}
    	for(int i=1;i<=100;i++){
    		while(a[i]!=0){
    			printf("%d ",i);
    			a[i]--;
    		}
    	}
    	return 0;
    }
    

    基数排序

    基本思想:

    将整数按位数切割成不同的数字,然后按每个位数分别比较。

    过程

    将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

    时间复杂度

    平均为 O ( n ) O(n) O(n)

    空间复杂度

    大大优化了桶排序的做法,空间复杂度更小

    #include<bits/stdc++.h>
    #define maxn 100010
    using namespace std;
    typedef long long ll;
    int n,a[maxn];
    int Gmax(int a[],int n){
    	int ma=a[1];
    	for(int i=2;i<=n;i++){
    		ma=max(ma,a[i]);
    	}
    	return ma;
    }
    void countsort(int a[],int n,int exp){
    	int output[n];
    	int buckets[20]={0};
    	for(int i=1;i<=n;i++){
    		buckets[(a[i]/exp)%10]++;
    	}
    	for(int i=1;i<=9;i++){
    		buckets[i]+=buckets[i-1]; 
    	}
    	for(int i=n;i>=1;i--){
    		output[buckets[(a[i]/exp)%10]]=a[i];
    		buckets[(a[i]/exp)%10]--;
    	}
    	for(int i=1;i<=n;i++){
    		a[i]=output[i];
    	}
    }
    void radixsort(){
    	int exp;
    	int max=Gmax(a,n);
    	for(exp=1;max/exp>0;exp*=10){
    		countsort(a,n,exp);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	radixsort();
    	for(int i=1;i<=n;i++){
    		printf("%d ",a[i]);
    	}
    	return 0;
    }
    

    STL

    sort

    sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为 O ( log ⁡ 2 n ) O(log_{2}{n}) O(log2n),比冒泡之类的排序算法效率要高,sort函数包含在头文件为#include<algorithm>的c++标准库中。

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[110];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	sort(a+1,a+n+1);//sort(a+1,a+n+1,greater<int>())为逆序
    	for(int i=1;i<=n;i++){
    		printf("%d ",a[i]);
    	} 
    	return 0;
    }
    
    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    线程同步 –Mutex和Semaphore
    线程同步 –AutoResetEvent和ManualResetEvent
    线程同步 – lock和Monitor
    .NET垃圾回收 – 非托管资源
    .NET垃圾回收 – 原理浅析
    反射简介—C#特性和反射
    反射简介—类型反射和晚期绑定
    Django REST framework 第一章 Serialization
    Django REST framework 简介
    Python Django 实用小案例2
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/13771237.html
Copyright © 2020-2023  润新知