【挑战程序设计竞赛】高等排序

归并排序

题目

利用归并排序法将包含n个整数的数列S按升序排序。另外,请报告merge中总共执行了多少次比较运算。

思路

归并排序:

  • 以整个数组为对象执行mergeSort
  • mergeSort如下所示:
    1、将给定的包含n个元素的局部数组“分割”成两个局部数组,每个数组包含n/2个元素。
    2、对两个局部数组分别执行mergeSort排序。
    3、通过merge将两个已排序完毕的局部数组“整合”成一个数组。
    在这里插入图片描述
    当局部数组只剩一个元素时,mergeSort不作任何处理直接结束。如果不是,则计算局部数组的中央位置mid,将left到mid(不包含mid)视作后半部分,再分别套用mergeSort。
    一般来说,n个数据大致会分为Log2(n)层。每层执行merge的总复杂度为O(n)。因此整体复杂度为O(nlogn)。

代码

/*归并*/
void merge(int A[],int n,int left,int mid,int right){
	int n1=mid-left;
	int n2=right-mid;
	for(int i=0;i<n1;i++) L[i]=A[left+i];
	for(int i=0;i<n2;i++) R[i]=A[right+i];
	L[n1]=R[n2]=SENTINEL;//末尾标记
	int i=0,j=0;
	for(int k=left;k<right;k++){
		cnt++;
		if(L[i]<=R[i]){
			A[k]=L[i++];
		}else{
			A[k]=R[j++];
		}
	} 
} 
/*归并排序*/ 
void mergeSort(int A[],int n,int left,int right){
	if(left+1<right){
		int mid=(right+left)/2;
		mergeSort(A,n,left,mid);
		mergeSort(A,n,mid,right);
		merge(A,n,left,mid,right);
	}
}

分割排序

题目

输入有n个元素的数列A,得出分割后的数列,把用作分割基准的元素用“[ ]”标出。

思路

数组A的分割对象范围为p到r,设置分割的基准是A[r]为x。然后移动A中的元素,将小于等于x的元素移到p到i的范围,大于x的元素移到i+1到j的范围内(不包含j)。i的初始化为p-1,j初始化为p。
A[j]大于x时不必移动元素,直接让j向前移动一个位置,将A[j]归入“大于x的组”。
如果A[j]小于等于x,则先让i向前移动一个位置,然后交换A[j]进而A[i]。这样一来就进入了“小于等于x的组”。而随着j向前移动一个位置,原本位于A[i]的元素又会回到“大于x的组”中。
在这里插入图片描述

代码

#include <stdio.h>
#define MAX 100000

int A[MAX],n;

int partition(int p,int r){
	int x,i,j,t;
	x=A[r];
	i=p-1;
	j=p;
	for(j=p;j<r;j++){
		if(A[j]<=x){//如果A[j]小于x,则将i向前一位,A[j] A[i]交换。 
			i++;
			t=A[i];A[i]=A[j];A[j]=t;
		}
	}
	t=A[i+1];A[i+1]=A[r];A[r]=t;//最后将分割基准值交换即可
	return i+1; 
} 
int main(){
	int i,q;
	
	scanf("%d",&n);
	for(i=0;i<n;i++) scanf("%d",&A[i]);
	
	q=partition(0,n-1);
	
	for(i=0;i<n;i++){
		if(i) printf(" ");
		if(i==q) printf("[");
		printf("%d",A[i]);
		if(i==q) printf("]");
	}
	printf("\n");
	
	return 0;
}

快速排序

题目

给n张卡片排序。每张卡片由1个花色(S、H、C、D)和1个数字组成。请用快速排序,将这些卡片按升序排列。
限制:输入中花色和数字完全相同的卡片不超过2张。

思路

快速排序:

  • 以整个数组为对象执行quickSort。
  • quickSort流程如下:
    1、通过分割将对象局部数组分割为前后两个局部数组。
    2、对前半部分的局部数组执行quickSort。
    3、对后半部分的局部数组执行quickSort。
    快速排序与归并排序一样基于分支法,但其执行partition进行分割时就已经在原数组中完成了排序,因此不需要归并排序中那种手动的合并处理。

代码

#include <stdio.h>
#define MAX 100000
#define SENTINEL 200000000

struct Card{
	char suit;
	int value;
}; 

struct Card L[MAX/2+2],R[MAX/2+2];
/*归并排序*/ 
void merge(struct Card A[],int n,int left,int mid,int right){
	int i=0,j=0,k;
	int n1=mid-left;
	int n2=right-mid;
	for(i=0;i<n1;i++) L[i]=A[left+i];
	for(i=0;i<n2;i++) R[i]=A[mid+1];
	R[n2]=L[n1]=SENTINEL;
	for(k=left;k<right;k++){
		if(L[i].value<=R[j].value){
			A[k]=L[i]++;
		}else{
			A[k]=R[j++];
		}
	} 
}
void mergeSort(struct Card A[],int n,int left,int right){
	if(left<=right){
		int mid=(left+right)/2;
		mergeSort(A,n,left,mid);
		mergeSort(A,n,mid,right);
		merge(A,n,left,mid,right);
	}
}
/*快速排序*/
int partition(struct Card A[],int n,int p,int r){
	int i,j;
	struct Card t,x;
	x=A[r];
	i=p-1;
	j=p;
	for(j=p;j<r;j++){
		if(A[j].value<=x.value){
			i++;
			t=A[i];A[i]=A[j];A[j]=t;
		}
	}
	t=A[i+1];A[t+1]=A[r];A[r]=t;
	return i+1;
}
void quickSort(struct Card A[],int n,int p,int r){
	int q;
	if(p<r){
		q=partition(A,n,p,r);
		quickSort(A,n,p,q-1);
		quickSort(A,n,q+1,r);
	}
}

int main(){
	int n,i,v;
	struct Card A[MAX],B[MAX];
	char S[10];
	int stable=1;
	
	scanf("%d",&n);
	
	for(i=0;i<n;i++){
		scanf("%s %d",S[i],&v);
		A[i].suit=B[i].suit=S[i];
		A[i].value=B[i].value=v;
	}
	
	mergeSort(A,n,0,n);
	quickSort(B,n,0,n-1);
	
	for(i=0;i<n;i++){
		//比较归并排序与快速排序的结果
		if(A[i].suit != B[i].suit) stable=0; 
	}
	
	if(stable==1) printf("Stable\n");
	else printf("Not Stable\n");
	for(i=0;i<n;i++){
		printf("%c %d\n",B[i].suit,B[i].value);
	} 
	
	return 0;
}

计数排序

又叫桶排序或者箱排序。

题目

输入数列A,通过计数排序算法将A按升序排列输出。

思路

对输入数组A的各元素Aj进行排序时,先将小于等于Aj的元素数记录在计数数组C中,然后根据C中的数值计算Aj在输出数组B中的位置。
计数数组C[x]的值表示数组A中有多少个小于等于x的元素。
在这里插入图片描述

代码

#include <stdio.h>
#include <stdlib.h>
#define MAX 2000001
#define VMAX 10000

int main(){
	unsigned short *A,*B;
	
	int C[VMAX+1];
	int n,i,j;
	scanf("%d",&n);
	
	A=malloc(sizeof(short) * n+1);
	B=malloc(sizeof(short) * n+1);
	
	for(i=0;i<=VMAX;i++) C[i]=0;
	
	for(i=0;i<n;i++){
		scanf("%hu",&A[i+1]);
		C[A[i+1]]++;
	}
	
	for(i=1;i<=VMAX;i++) C[i]=C[i]+C[i-1];
	
	for(j=1;j<=n;j++){
		B[C[A[j]]]=A[j];
		C[A[j]]--;
	}
	
	for(i=1;i<=n;i++){
		if(i>1) printf(" ");
		printf("%d",B[i]);
	}
	printf("\n");
	
	return 0;
} 

利用标准库排序

Sort函数

STL为用户提供了给元素排序的函数sort。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
	int n;
	vector<int> v;
	
	cin>>n;
	for(int i=0;i<n;i++){
		int x;
		cin>>x;
		v.push_back(x);
	}
	
	sort(v.begin(),v.end());
	
	for(int i=0;i<v.size();i++){
		cout<<v[i]<<" ";
	}
	cout<<endl;
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值