排序总结
排序是最基础的东西啦,一定要记板子!记板子!记板子
目录
1.操作
每一趟从待排序的数据元素中选出最小(或最大)的一个元素放到待排序的序列的最前面,直到所有元素都排序完毕。
2.特点
<1>稳定性:不稳定
<2>时间复杂度:O(n2)
<3>辅助空间:O(1)
3.应用
n较小,且对稳定性无要求时宜用选择排序。
4.代码实现
1 #include<iostream> 2 using namespace std; 3 int a[100],n; 4 int main(){ 5 int num,mid; 6 cin>>n; 7 for(int i=1;i<=n;i++) 8 cin>>a[i]; 9 for(int i=1;i<=n;i++){ 10 num=i; 11 for(int j=i+1;j<=n;j++) 12 if(a[j]<a[num]) num=j;//找出最小的元素 13 if(num!=i){ 14 mid=a[i]; 15 a[i]=a[num]; 16 a[num]=mid; 17 }//把最小的元素排到前面 18 } 19 for(int i=1;i<=n;i++) 20 cout<<a[i]<<" "; 21 return 0; 22 }
1.操作
两层循环每次把最大的数排到最后,像气泡上升。
2.特点
<1>稳定性:稳定
<2>时间复杂度:O(n2),最好为O(n)
<3>辅助空间:O(1)
3.应用
待排序的序列整体或局部有序时能达到较快的速度。n较小,且对稳定性有要求时宜用冒泡排序。
4.代码实现
1 #include<iostream> 2 using namespace std; 3 int a[100],n; 4 int main(){ 5 cin>>n; 6 for(int i=1;i<=n;i++) 7 cin>>a[i]; 8 bool change; 9 for(int i=n-1;i>=1;i--){ 10 change=1;//使用布尔变量判断是否要交换 11 for(int j=1;j<=i;j++) 12 if(a[j]>a[j+1]) swap(a[j],a[j+1]),change=0; 13 if(change) break; 14 //如果没有交换就说明已经是有序的,直接退出以减少排序次数(主要针对局部或整体有序的序列) 15 } 16 for(int i=1;i<=n;i++) 17 cout<<a[i]<<" "; 18 return 0; 19 }
1.操作
当读入一个元素时,在已经排好序的序列中,搜寻它正确的位置,再插入读入的元素。(注意:插入前要把后面所有的后移一位)
2.特点
<1>稳定性:稳定
<2>时间复杂度:O(n2),最好为O(n)
<3>辅助空间:O(1)
3.应用
待排序的序列整体或局部有序时能达到较快的速度。n较小,且对稳定性有要求时宜用插入排序。
4.代码实现
1 #include<iostream> 2 using namespace std; 3 int n,a[100]; 4 int main(){ 5 cin>>n; 6 int mid; 7 for(int i=1;i<=n;i++) 8 cin>>a[i]; 9 for(int i=1,j;i<=n;i++){//现在要插入第i个元素 10 for(j=i-1;j>=1;j--) 11 if(a[j]<a[i]) break;//在i位置前面的有序区间中找a[i]应该所在的位置 12 if(j!=i-1){ 13 mid=a[i]; 14 int k; 15 for(k=i-1;k>=j;k--) 16 a[k+1]=a[k];//后移 17 a[k+1]=mid;//把a[i]放到正确的位置上 18 } 19 } 20 for(int i=1;i<=n;i++) 21 cout<<a[i]<<" "; 22 return 0; 23 }
1.操作
若待排序值在一个明显有限范围内(整型)时,可设计有限个有序桶,待排序的值装入对应的桶(每个桶可以装入若干个值),桶号就是待排序的值,按顺序输出各桶的值就可以得到有序序列。
2.特点
<1>稳定性:不稳定
<2>时间复杂度:O(n)
<3>辅助空间:O(n) (用空间换时间)
3.应用
若待排序的记录的关键字在一个明显有限范围内且空间允许时宜用桶排序。
4.代码实现
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int main(){ 5 int b[100],n,k;//b为桶 6 cin>>n; 7 for(int i=1;i<=n;i++){ 8 cin>>k; 9 b[k]++;//把等于k的元素全部装进编号为k的桶里 10 } 11 for(int i=0;i<=100;i++){ 12 while(b[i]>0){ 13 cout<<i<<" "; 14 b[i]--; 15 } 16 cout<<endl; 17 } 18 return 0; 19 }
1.操作
快速排序是对冒泡排序的一种改进。通过一趟排序将待排序序列记录分割成独立的两部分,其中一部分记录的关键字皆比另一部分小,则可分别对这两部分进行排序。(二分的思想)
2.特点
<1>稳定性:不稳定
<2>时间复杂度:O(nlog2n),最坏为O(n2)
<3>辅助空间:O(log2n),最坏为O(n)
3.应用
快排在待排序的序列整体或局部有序时反而慢了。n较大,元素随机,且对稳定性无要求时宜用快速排序。
4.代码实现
一般来说直接用sort就可以啦……QWQ
1 #include<iostream> 2 using namespace std; 3 void qsort(int,int); 4 int a[100],n; 5 int main(){ 6 cin>>n; 7 for(int i=1;i<=n;i++) 8 cin>>a[i]; 9 qsort(1,n); 10 for(int i=1;i<=n;i++) 11 cout<<a[i]<<" "; 12 return 0; 13 } 14 void qsort(int l,int r){ 15 int mid=a[(l+r)/2];//定义当前区间中间的数为分隔数 16 int i=l,j=r; 17 do{ 18 while(a[i]<mid) i++;//如果左边的数<分隔数,则继续找 19 while(a[j]>mid) j++;//如果右边的数>分隔数,则继续找 20 if(i<=j){ 21 swap(a[i],a[j]);//交换两个不符合条件的数 22 i++;j--;//继续找 23 } 24 }while(i<=j); 25 if(l<j) qsort(l,j);//分割成左右两个区间再继续找 26 if(i<r) qsort(i,r); 27 return; 28 }
1.操作
先使每个子序列有序,再使子序列段区间有序。
2.特点
<1>稳定性:稳定
<2>时间复杂度:O(nlog2n)
<3>辅助空间:O(n)
3.应用
可以解决逆序对问题。
4.代码实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[100],ans[100]; 4 void msort(int l,int r){ 5 if(l==r) return; 6 int mid=(l+r)/2; 7 msort(l,mid);//分解左边子序列 8 msort(mid+1,r);//分解右边子序列 9 int i=l,j=mid+1,k=l;//合并 10 while(i<=mid&&j<=r){ 11 if(a[i]<=a[j]){ 12 ans[k]=a[i];k++;i++; 13 } 14 else{ 15 ans[k]=a[j];k++;j++; 16 } 17 } 18 while(i<=mid){//复制左边子序列剩余 19 ans[k]=a[i]; 20 k++; 21 i++; 22 } 23 while(j<=r){//复制右边子序列剩余 24 ans[k]=a[j]; 25 k++; 26 j++; 27 } 28 for(i=l;i<=r;i++) 29 a[i]=ans[i]; 30 } 31 int n; 32 int main(){ 33 cin>>n; 34 for(int i=1;i<=n;i++) 35 cin>>a[i]; 36 msort(1,n); 37 for(int i=1;i<=n;i++) 38 cout<<a[i]<<" "; 39 return 0; 40 }
这里再放一个求逆序对的代码吧QWQ
1 void msort(int l,int r){ 2 if(l==r) return; 3 int mid=(l+r)/2; 4 msort(l,mid); 5 msort(mid+1,r); 6 int i=l,j=mid+1,k=l; 7 while(i<=mid&&j<=r){ 8 if(a[i]<=a[j]){ 9 r[k]=a[i];k++;i++; 10 } 11 else{ 12 r[k]=a[j];k++;j++; 13 ans+=mid-i+1;//统计产生逆序对的数量 14 //右边区间在合并过程中如果是较小的值,那么它和左边区间剩余的元素就存在逆序对关系 15 } 16 } 17 while(i<=mid){ 18 r[k]=a[i];k++;i++; 19 } 20 while(j<=r){ 21 r[k]=a[j];k++;j++; 22 } 23 }
1.操作
利用大(小)根堆的性质排序。
2.特点
<1>稳定性:不稳定
<2>时间复杂度:O(nlog2n)
<3>辅助空间:O(1)
3.应用
n较大,并且元素本身可能有序,对稳定性无要求时宜用堆排序。
4.代码实现
对于堆的操作主要就是两个,一个是插入,一个是删除,这里先放一个插入操作的核心代码,提供不用STL和使用STL两个版本
1 //插入元素 2 void put(int d){//将元素d加入堆中 3 int now,next; 4 heap[++heap_size]=d;//先放到堆底 5 now=head_size; 6 while(now>1){//heap[1]是堆顶 7 next=now>>1; 8 if(heap[now]>=heap[next]) break; 9 //堆是完全二叉树,性质:左二子的编号是父亲的两倍,右儿子的编号是父亲的两倍加一 10 swap(heap[now],heap[next]); 11 now=next; 12 } 13 } 14 15 //使用STL的版本 16 void put(int d){ 17 heap[++heap_size]=d; 18 //push_heap(heap+1,heap+heap_size+1); //大根堆 19 push_heap(heap+1,heap+heap_size+1,greater<int>());//小根堆 20 }
下面的是删除操作的核心代码,同样有不用STL和使用STL两个版本
1 //取出并删除元素 2 int get(){ 3 int now,next,res; 4 res=heap[1];//取出最小元素,即小根堆的堆顶 5 heap[1]=heap[heap_size--];//把最后一个元素放到堆顶 6 now=1; 7 while(now*2<=head_size){//调整堆的排列 8 next=now*2; 9 if(next<heap_size&&heap[next+1]<heap[next]) next++; 10 if(heap[now]<=heap[next]) break; 11 swap(heap[now],heap[next]); 12 now=next; 13 } 14 return res; 15 } 16 17 //使用STL的版本 18 int get(){ 19 //pop_heap(heap+1,heap+heap_size+1); //大根堆 20 pop_heap(heap+1,heap+heap_size+1,greater<int>()); 21 return heap[heap_size--]; 22 }