排序大杂烩

七个排序

这里介绍七个排序算法

选择排序

选择排序应该是最简单的排序之一
简单来讲,找到剩余区间内的最小值而后放在一个有序区间的末尾
(不用纠结剩余区间什么意思,模拟一遍后你就会知道数组

  • 模拟一下
    假设给整个区间排序
    区间内数为
    4,3,6,9,8
    先找整个区间中的最小值
    为3,放在第一位,交换3和4
    而后找除了3之外的数的最小值(也就是剩下未排序的元素,第2个数到第5个数即为剩余区间),最小值为4,4就在第二位不用换
    而后继续找最小值(最小值在第3个数到第5个数之间)为6,放在原位
    继续找最小值(最小值在第4个数到第5个数之间)为8,交换8和9
    最终有序区间[3,4,6,8,9]

算法实现

  • code
for(int i=1;i<len;++i){
	int maxi=i; 
	for(int j=i+1;j<=len;++j)//剩余区间
		if(s[j]<s[maxi]) maxi=j;//记录区间中最小值下标
	swap(s[maxi],s[i]);
}
  • 复杂度分析

插入排序

插入排序是经过“插入”来排序函数

经过将一个数插入到一个有序区间的某个位置,从而保证插入后区间有序
设为插入的数为b(插入后区间长度+1
则b在区间知足的条件为 \(a[i]<b<a[i+1]\)spa

  • 证实
    由于\(a[1]<a[2]<....<a[n-1]<a[n]\)
    又由于a序列始终有序,插入后不破坏其性质
    因此插入后\(a[1]<a[2]<...<a[i-1]<b<a[i]<..<a[n+1]\)

举个简单例子指针

  • 现有有个区间1,2,6
    要插入一个数字4
    这个很显然都知道插入到2和6之间就能保证整个区间有序

其实模拟一遍就很容易懂code

  • 假设给整个区间排序
    区间内数为
    4,3,6,9,8
    设此时4为有序区间(一个数固然构成一个有序区间
    找下一个数 3
    与4相比,要比4小,为保证区间有序,因此3须要插入到4的前面即有序区间为[3,4]
    再下一个数 6
    逐个与有序区间内的数相比插入到4后面,有序区间为[3,4,6]
    再下一个数 9
    重复刚刚的步骤 有序区间[3,4,6,9]
    以此类推 最终有序区间[3,4,6,8,9]

算法实现

  • code
for(int i=1;i<len;++i){
      cin>>s;
      for(int j=i-1;j>=1 && a[j]>s;--j) a[j+1]=a[j];//从后往前找
      a[j+1]=s;//此时j为第一个小于s的数的下标
}

复杂度

选择排序

选择排序应该是最简单的排序之一
简单来讲,找到剩余区间内的最小值而后放在一个有序区间的末尾
(不用纠结剩余区间什么意思,模拟一遍后你就会知道blog

  • 模拟一下
    区间内数为
    4,3,6,9,8
    先找整个区间中的最小值
    为3,放在第一位,交换3和4
    而后找除了3之外的数的最小值(也就是剩下未排序的元素,第2个数到第5个数即为剩余区间),最小值为4,4就在第二位不用换
    而后继续找最小值(最小值在第3个数到第5个数之间)为6,放在原位
    继续找最小值(最小值在第4个数到第5个数之间)为8,交换8和9
    最终有序区间[3,4,6,8,9]

算法实现

  • code
for(int i=1;i<len;++i){
	int maxi=i; 
	for(int j=i+1;j<=len;++j)//剩余区间
		if(s[j]<s[maxi]) maxi=j;//记录区间中最小值下标
	swap(s[maxi],s[i]);
}

复杂度

冒泡排序

冒泡排序思想很简单,实现也很简单排序

咱们知道数组下标是有序的,只要咱们在数组中,以这个数的为下标的位置的数标记一下就能够,从1开始找,找到有标记位置就将输出递归

  • 模拟一下
    区间内数为
    4,3,6,9,8
    那么数组t={0,0,0,1,1,0,1,0,1,1}
    对应下标 0,1,2,3,4,5,6,7,8,9
    从t[0]开始到t[9],

算法实现

  • code
bool t[maxn];
for(int i=1;i<=len;++i){
	int num;cin>>num;
	t[num]=1; 
}
  • 复杂度

堆排序

堆排序通常能够直接用优先队列实现(这里不展开讲,有兴趣同窗能够到去看其余blog队列

#include<queue>//须要用到这个头文件
priority_queue<>

快速排序

快速排序实际上是用到了分治的思想

将一个区间分为两个区间,左区间小中间这个数,右区间大于中间这个数
逐次递归分解愈来愈小的区间,最后使整个区间有序

  • 老规矩模拟一遍
    区间内数为
    4,9,5,2,8
    咱们能够找到中间数5,
    把全部小于它的数放在左边,大于它的数放右边则区间为
    4,2,5,9,8
    而后再看左区间,取中间数4,操做后区间则为2,4
    再看右区间,取中间数9,操做后区间则为8,9
    整个区间就为2,4,5,8,9
    (若是还不理解,能够本身多举几组数模拟一下

算法实现

  • code
void sort(int l,int r){ 
	int mid=s[(l+r)>>1];//位运算等价于(l+r)/2;
	int i=l,j=r;
	while(i<=j){//这几步就是使左右区间的数分别知足小于和大于mid 
		while(s[i]<mid) ++i;//i必定不大于 (l+r)/2
		while(s[j]>mid) --j;//j必定不小于 (l+r)/2
		//思考下为何不大于等于 
		if(i<=j){
			swap(s[i],s[j]);
			i++;j--; 
		}
	} 
	//此时区间划分为[l,j] 和[i,r] 
	if(l<j) sort(l,j); 
	if(i<r) sort(i,r);
}

通常不手写由于stl有

#include<algorithm>
bool cmp(int a,int b){//int 可根据数组类型改成double或其余(甚至能够是结构体
  return a<b;//数组按从小到大排序
  return a>b;//数组按从大到小排序
}
sort(a+1,a+1+n,cmp)//a为数组,a+1为须要排序的数组的起始位置,a+1+n为末位置,cmp为自定义函数
  • 复杂度

归并排序

这里主要讲二路归并(还有多路归并

二路归并一样也有分治的思想

将两个有序的区间,合为一个有序的区间,和前面讲过的同样,一个数即为一个有序区间,

  • 模拟。。。(又来了
    假设给整个区间排序 区间内数为
    4,9,5,2,8
    划为两个区间 4,9,5和 2,8
    再继续划分 4,9 和 5和 2和8
    继续划分 4和 9 和 5和 2和8
    不能再划分就中止
    而后开始合并
    怎么合并了?
    4和9本来属于一个[4,9]区间,又要合并回去,且保证有序
    比较4和9,4小于9,先放入区间[4],而后9又放入[4,9]
    好而后此时 [4,9]区间有序了,[5]区间也有序了,这两个又同属于本来的[4,9,5]
    合并回去,比较4和5,4比5小能够直接放入(由于此时4是左区间最小数,5是右区间最小数,因此两个区间合并后的最小数必定在这两个数之间)目前区间[4]
    (但能不能把5直接放入后面,不能,因左区间第2个数可能小于5),而后把5与9比较,9就比5大,因此放入5,区间[4,5],最后放入9,q区间[4,5,9]
    2和8同理合为区间[2,8];
    而后区间[4,5,9]与区间[2,8]合为[2,4,5,8,9]

算法实现

  • code
int m[maxn];//原序列 
int temp[maxn];//存有序区间 
void marge_sort(int l,int r){
	if(l==r) return ;
	int mid=(l+r)>>1;
	marge_sort(l,mid);//左区间 
	marge_sort(mid+1,r);//右区间 
	int i=l,j=mid+1,p=l;//i为左区间左端点,j为右区间左端点 p为合成区间的末端指针 
	while(i<=mid && j<=r){
		if(m[i]<m[j]) temp[p++]=m[i++];//两个序列相比较,小的放 
		else temp[p++]=m[j++]; 
	}
	while(i<=mid) temp[p++]=m[i++];//右区间已经放完,而左区间也是有序的则,直接放入有区间后 
	while(j<=r) temp[p++]=m[j++];//同理,直接放入 
	for(i=l;i<=r;++i) m[i]=temp[i];//把有序序列放置给m 
}

还有不少排序算法没有讲到 若是有不清楚的地方能够发评论私信提问 讲的不行还望海涵

相关文章
相关标签/搜索