排序是 CSP 初赛中必考的一个知识点,平时大家一般用 sort,可能对其他的不太熟,所以此处带大家了解一下其他的几种排序。
先把总图放这了。
1.插入排序
思路
- 首先将整个序列分为 1 1 1 和 [ 2 , n ] [2,n] [2,n],此时,前者是有序的,后者无序。
- 从后者依次拿出一个元素插入至前者的某个位置,使得前者始终有序。
- 当后者为空时,前者即为排序完成的原序列。
代码如下:
void insertSort(int a[],int n){
for(int i=1;i<n;i++){
if(a[i]<a[i-1]){
int j=i-1;
int x=a[i];
while(j>=0 && x<a[j]){
a[j+1]=a[j];
j--;
}
a[j+1]=x;
}
}
}
2.希尔排序
思路
希尔排序就是插入排序 Pro Max。
- 将整个序列分为多个子序列。
- 将这些子序列分别进行插入排序。
- 排序完后将子序列进行合并。
- 反复 2 和 3 直到全部合并。
- 排序完成。
代码如下:
void ShellSort(int a[], int len){
int i,j,temp,gap=len;
while(gap>1){
gap=gap/2;
for(i=0;i<len-gap;i++){
j=i+gap;
if (a[i]>a[j]){
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
}
3.选择排序
思路
十分简单啊。
- 从 [ 1 , n ] [1,n] [1,n] 中找出最小值,放在第一个位置。
- 从 [ 2 , n ] [2,n] [2,n] 中找出最小值,放在第二个位置。
- 从
[
3
,
n
]
[3,n]
[3,n] 中找出最小值,放在第三个位置。
……
代码如下:
void SelectSort(int a[],int n){
int mix,temp;
int i,j;
for(i=0;i<n-1;i++){
mix=i;
for(j=i+1;j<n;j++)
if(a[j]<a[mix])
mix=j;
if(i!=mix){
temp=a[i];
a[i]=a[mix];
a[mix]=temp;
}
}
}
4.堆排序
特性
堆排序实在是不常用,故这里只给出几个特性:
- 堆是一种特殊的树,也就意味着堆排序需要建树。
- 时间复杂度为 O ( n l o g n ) O(n\,log\,n) O(nlogn)。
- 堆排序是原地的(即不需要申请多余的空间来排序)。
当然,想学的兄弟们戳这里,我就不在解释了。
5.冒泡排序
思路
冒泡排序与选择排序有异曲同工之妙,两者都是从一定区间内挑取最值并将其放在某个位置。
冒泡排序的排序过程:
从最小下标的元素开始,依次向后,每相邻两个元素进行一次比较,并根据两者的大小来进行换位。
下表中,第一次的比较是 8 和 4,很明显,8 比 4 大,那么将两者的位置进行交换。
交换后,第二次的比较 就变成了 8 和 5,那么 继续将两者位置交换。
……
下标: | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | 7 7 7 |
---|---|---|---|---|---|---|---|
元素: | 8 \color{red}8 8 | 4 \color{red}4 4 | 5 \color{red}5 5 | 1 1 1 | 4 4 4 | 3 3 3 | 9 9 9 |
这样子的交换过程可以将较大的元素逐渐向后移动,就如同水中的大泡泡浮上水面一样。
代码如下:
int BubbleSort(int a[],int len){
bool flag=true;
for(int i=1;i<=len;i++){
flag=true;
for(int j=1;j<=len-i;j++){
if(a[j]>a[j+1]){
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=false;
}
}
if(flag)break;//没有交换就说明排好了,此时直接退出
}
}
6.快速排序
思路
- 先选取一个基准元素 b a s e base base,一般选第一个或最后一个,然后确认左指针 l l l 在最左端,右指针 r r r 在最右端。
- 随后 r r r 向左移,直到遇到一个比 b a s e base base 小的元素,此时将 l l l 所在元素赋值为 r r r 所在元素。
- l l l 向右移,直到遇到一个比 b a s e base base 大的元素,此时将 r r r 所在元素赋值为 l l l 所在元素。
- 重复上述 2、3 部分,直到 l l l 与 r r r 重合,将这个位置 赋值为 b a s e base base。
- 一轮下来后, b a s e base base 左边的都是比 b a s e base base 小的元素,右边都是比 b a s e base base 大的元素。
- 接下来以 b a s e base base 为中间结点,将 b a s e base base 左边部分和右边部分再分别用二分进行上述操作。
我可能讲的不够详细,还是不理解的戳这里。
代码如下:
void quickSort(int nums[],int start,int end) {
if(start<end){
int base=nums[start];
int left=start;
int right=end;
while(left<right){
while(left<right && nums[right]>=base)right--;
nums[left] = nums[right];
while(left<right && nums[left]<=base)left++;
nums[right] = nums[left];
}
nums[left]=base;
quickSort(nums,start,left-1);
quickSort(nums,left+1,end);
}
}
7.归并排序
思路
将整个数组不断拆开,再不断组合,在组合的过程中进行排序。
非常棒的排序,仅次于快速排序。
代码如下:
void Merge(int sa[],int ta[],int l,int mid,int r){
int i=l,j=mid+1,k=l;
while(i!=mid+1 && j!=r+1){
if(sa[i]>sa[j])ta[k++]=sa[j++];
else ta[k++]=sa[i++];
}
while(i!=mid+1)ta[k++]=sa[i++];
while(j!=r+1)ta[k++]=sa[j++];
for(i=l;i<=r;i++)sa[i]=ta[i];
}
void MergeSort(int sa[],int ta[],int l,int r){
int mid;
if(l<r){
mid=l+(r-l)/2;
MergeSort(sa, ta, sa, mid);
MergeSort(sa,ta,mid+1,r);
Merge(sa,ta,l,mid,r);
}
}
分个界:
以上的 7 种排序方式是通过比较来排序的,而接下来的 3 种排序方式是基于运算来排序的。
8.计数排序(是连接)
博主不是很明白,想学的看这里吧。
9.桶排序(同上)
博主实在蒟蒻,这里同样给大家分享一篇博客。
10.基数排序
思路
从低位开始,对每一位上的所有数字进行排序。例如第 1 轮排序后,数字的个位数要有序;第 2 轮排序后,数字的十位数要有序,而且由于第一轮的原因,第二轮即使十位数字相同也是有序的;依次类推直至最高位排序完成。
代码如下:
void RxSort(int A[],int l,int h,int d,int k){
int size = h-l+1;
int *counts=new int[k];
int *temp=new int[size];
int index,pval=1;
for(int i=0;i<d;i++){
for(int j=0;j<k;j++)
counts[j]=0;
for(int j=l;j<=h;j++){
index=(int)(A[j]/pval)%k;
counts[index]++;
}
for(int j=1;j<k;j++)counts[j]=counts[j]+counts[j-1];
for(int j=h;j>=l;j--){
index=(int)(A[j]/pval)%k;
temp[counts[index]-1]=A[j];
counts[index]--;
}
for(int j=0;j<size;j++)A[j+l]=temp[j];
pval=pval*k;
}
delete[] counts;
delete[] temp;
}
结语
关于 CSP 初赛的排序内容就给大家介绍到这了,大家还是得多刷真题,在刷题中进一步掌握各种排序,希望对大家接下来的 CSP 初赛有帮助。喜欢的朋友们记得点赞哦。