基本排序算法

选择排序:

简单选择排序是指,对一个序列A中元素A[1]~A[n],令i从1到n枚举,进行n趟操作,每趟从待排序部分[i,n]中选择最小的元素,令其与待排序部分的第一个元素A[i]进行交换,这样元素A[i]就会与当前有序区间[1,i-1]形成新的有序区间[1,i]。于是在n趟操作后,所有元素就会是有序的。
该算法总共需要进行n趟操作,每趟操作选出待排序部分[i,n]中最小的元素,令其与A[i]交换。因此总时间复杂度为O(n^2),实现代码如下:

void selectSort(){
	for(int i=1;i<=n;i++){		//进行n趟排序
		int k=i;
		for(int j=i;j<=n;j++){		//选出[i,n]中最小的元素,下标为K
			if(A[j]<A[k])
				k=j;
		}
		int temp=A[i];
		A[i]=A[k];
		A[k]=temp;
	}
}

插入排序:

直接插入排序是指,对序列A的n个元素A[i]~A[n],令i从2到n枚举,进行n-1趟操作。假设某一趟时,序列A的前i-1个元素A[1]-A[n]已经有序,而范围[i,n]还未有序,那么该趟从范围[1,i-1]中寻找某个位置j,使得将A[i]插入位置j后(此时A[j]-A[i-1]会后移一位),范围[1,i]有序。

void insertSort(){
	for(int i=2;i<=n;i++){				//进行n-1趟排序 
		int temp=A[i],j=i;				//temp临时存放A[i],j从i开始往前枚举 
		while(j>1&&temp<A[j-1]){		//只要temp小于前一个元素A[j-1] 
			A[j]=A[j-1];				//把A[j-1]后移至A[j] 
			j--;
		}
		A[j]=temp;					//插入位置为j 
	}
}

归并排序

归并排序是一种基于归并思想的排序方法,下面主要介绍2-路归并。2-路归并排序的原理是,将序列两两分组,将序列归并为[n/2]个组,组内单独排序;然后将这些组再两两归并,生成[n/4]个组,组内再单独排序;以此类推,直到只剩下一个组为止。归并排序的时间复杂度为O(nlogn)。
1.递归实现代码

const int maxn=1010; 
//将数组A的[L1,R1]与[L2,R2]区间合并为有序区间(此处L2即为R1+1) 
void merge(int A[],int L1,int R1,int L2,int R2){
	int i=L1,j=L2;		//i指向A[L1],j指向A[L2] 
	int temp[maxn],index=0;		//temp临时存放合并后的数组,index为其下标 
	while(i<=R1&&j<=R2){
		if(A[i]<=A[j])				//如果A[i]<=A[j] 
			temp[index++]=A[i++];	//将A[i]加入序列temp 
		else						//如果A[i]>A[j] 
			temp[index++]=A[j++];	//将A[j]加入序列temp 
	}
	while(i<=R1)
		temp[index++]=A[i++];	//将[L1,R1]的剩余元素加入序列temp 
	while(j<=R2)
		temp[index++]=A[j++];	//将[L2,R2]的剩余元素加入序列temp 
	for(i=0;i<index;i++)
		A[L1+i]=temp[i];		//将合并后的序列赋值返回数组A 
}
void mergeSort(int A[],int left,int right){
	if(left<right){					//只要left小于right 
		int mid=(left+right)/2;		//取[left,right]的中点 
		mergeSort(A,left,mid);		//递归,将左子区间[left,mid]归并排序 
		mergeSort(A,mid+1,right);	//递归,将右子区间[mid+1,right]归并排序 
		merge(A,left,mid,mid+1,right);	//将左子区间和右子区间合并 
	}
}

2.非递归实现

const int maxn=1010; 
//将数组A的[L1,R1]与[L2,R2]区间合并为有序区间(此处L2即为R1+1) 
void merge(int A[],int L1,int R1,int L2,int R2){
	int i=L1,j=L2;		//i指向A[L1],j指向A[L2] 
	int temp[maxn],index=0;		//temp临时存放合并后的数组,index为其下标 
	while(i<=R1&&j<=R2){
		if(A[i]<=A[j])				//如果A[i]<=A[j] 
			temp[index++]=A[i++];	//将A[i]加入序列temp 
		else						//如果A[i]>A[j] 
			temp[index++]=A[j++];	//将A[j]加入序列temp 
	}
	while(i<=R1)
		temp[index++]=A[i++];	//将[L1,R1]的剩余元素加入序列temp 
	while(j<=R2)
		temp[index++]=A[j++];	//将[L2,R2]的剩余元素加入序列temp 
	for(i=0;i<index;i++)
		A[L1+i]=temp[i];		//将合并后的序列赋值返回数组A 
}
void mergeSort(int A[]){
	//setp为组内元素个数,setp/2为左子区间元素个数,注意等号可以不取
	for(int step=2;step/2<=n;step*=2){
		//每setp个元素一组,组内前setp/2和后setp/2个元素进行合并
		for(int i=1;i<=n;i+=step){		//对每一组 
			int mid=i+step/2-1;			//左子区间元素个数为setp/2
			if(mid+1<=n){			//右子区间存在元素则合并 
				//左子区间为[i,mid],右子区间为[mid+1,min(i+setp-1,n)] 
				merge(A,i,mid,mid+1,min(i+step-1,n));
			} 
		} 
	} 
}

快速排序(c++中sort()函数)

快速排序是排序算法中平均时间复杂度为O(nlogn)的一种算法,其实现需要先解决寻找主元的问题。(即使得A[1]的左侧所有元素都不超过A[1],右侧所有元素都大于A[1])。此问题可通过two pointers思想解决:

  1. 先将A[1]存至某个临时变量temp,并令两个下标left,right分别指向序列首尾(如令left=1,right=n)。
  2. 只要right指向的元素A[right]大于temp,就将right不断左移,当某个时候A[left]<=temp时,将元素A[right]挪到left指向的元素A[left]处。
  3. 只要left指向的元素A[left]不超过temp,就将left不断左移,当某个时候A[left]>temp时,将元素A[left]挪到right指向的元素A[right]处。
  4. 重复2,3步骤,直到left与right相遇,把temp放到相遇的地方。
    代码实现如下:
int Partition(int A[],int left,int right){
	int temp=A[left];		//将A[left]存放至临时变量temp 
	while(left<right){		//只要left与right不相遇 
		while(left<right&&A[right]>temp)	//反复左移right 
			right--;
		A[left]=A[right];		//将A[right]挪到A[left] 
		while(left<right&&A[right]<=temp)	//反复右移left 
			left++;
		A[right]=A[left];		//将A[left]挪到A[right] 
	}
	A[left]=temp;		//把temp放到left与right相遇的地方 
	return left;		//返回相遇的下标 
}

在主元基础上利用递归法对左右区间不断进行找主元的递归,最终完成排序。
快速排序代码实现:

//快速排序,left与right初值为序列首尾下标 
void quickSort(int A[],int left,int right){
	if(left<right){		//当前区间的长度超过1
		//将[left,right]按A[left]一分为二 
		int pos=Partition(A,left,right);
		quickSort(A,left,pos-1);	//对左子区间递归进行快速排序 
		quickSort(A,pos+1,right);	//对右子区间递归进行快速排序
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值