排序

排序

一、选择排序

选择排序有简单选择排序和堆排序(对选择排序的改进)

①简单选择排序

从未排序的序列中,选出最小的元素(先以该未排序序列的首个元素作为min)和该未排序序列的首个元素进行交换。
再在剩下的未排序的序列重复上述步骤直到该未排序序列的长度为1

//先写一个交换元素的函数
//因为我们用的是数组进行存储,则传入函数中的是一个指针便于访问
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void swap(ElementType*a,ElementType*b);
void SimpleSelectSort(ElementType A[],int N);
int main() {
	return 0;
}
void swap(ElementType*a,ElementType*b){
		ElementType t=*a;
		*a=*b;
		*b=t;
}
	
void SimpleSelectSort(ElementType A[],int N){
	int i,j,min;
	for(i=0;i<N-1;i++){//当i迭代到N-2时,未排序序列长度为1,此时循环就可以结束 
		min = i;//min每次迭代开始时指向未排序序列的第一个元素
		for(j=i;j<N;j++){ //在未排序序列中找到最小元素
			 if(A[j]<A[min]) min = j;
			 swap(A[min],A[i]);//找到未排序序列最小元素 与未排序序列的第一个元素进行交换 交换后将未排序序列的第一个元素纳入到已排序序列中	
		}
	}				
}
②堆排序

这里利用树堆来进行排序

二、插入排序

①简单插入排序

将待排序的一组序列分为已排好序的和未排序的两个部分,将未排序序列中的元素逐一插入到已排序的元素当中。一开始时以第一个元素为已排序序列,则经过N-1次插入后,排序结束
第k-1次排序:将它和第k-1个元素(已排序序列的最后一个)比较。若大于,则循环结束。若小于,则交换两个元素的位置,将该元素继续与k-2个元素进行比较。
直到该树比它前一个位置的元素大 或者 该数已经在第一个位置上

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main(){
	
	return 0;
}
void SimpleInsertSort(ElementType A[],int N){
	int p,i;
	ElementType tmp;//新建一个tmp来储存未排序序列的第一个元素 防止右移导致覆盖丢失
	for(p=1;p<N;p++){ //因为开始时默认A[0]为已排序元素,所以从i=1开始迭代 
		tmp = A[p];//储存未排序序列的第一个元素
		for(i=p;i>0&&A[i-1]>tmp;i--) A[i]=A[i-1]; //如果前比后大 执行右移操作  
		A[i]=tmp;	 		
	} 
}
②希尔排序

简单插入排序效率不高一个原因时因为每次只能交换相邻两个元素
希尔排序试图每次交换一定间隔的元素
原理:将待排序元素按一定间隔分为若干序列,分别进行插入排序。开始时设置的“间隔较大”,在每轮排序中将间隔逐渐减小直到间隔(增量)为1,此时进行的是最后的整个序列进行一次排序----简单插入排序
“间隔”定义为一组递减的增量序列(如sedgewick序列)。位置之差等于当前增量(步长)的元素归属于同一个子序列。排好后再选取下一个增量。
缺点:不是稳定的排序。可能导致数值相同的两个元素发生相对位置上的变化

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main(){
	
	return 0;
}
void ShellSort(ElementType A[],int N){
	//我们用Sedgewick序列作为递减增量序列
	//首先先确定Sedgewick中比N要小的第一个步长
	int Si,D,P,i;//Si表示步长下标,D表示步长 
	ElementType tmp;
	int Sedgewick[929,505,209,109,41,19,5,1,0];
	for (Si=0;Sedgewick[Si]>=N;Si++) ;//用这个循环找到了相对应的Si下标
	for (D=Sedgewick[Si];D>0;D++){//D>0表示最后一次进行的是步长为1的简单插入排序
		for(P=D;P<N;p++){ //注意现在的P代表的是每一个子序列的待排序列的第一个元素的下标 
			//每个子序列并不是单独进行排序 ,而是子序列都进行完第k次插入后,再进行下一次的插入 
			tmp=A[p];//tmp用来存储当前子序列的未排序序列的第一个元素,之后会存储下一个子序列的未排序序列的第一个元素
			for(i=P;i>=D&&A[i-D]>Tmp;i-=D){ //i>=D是判断是否已经右移了已排序序列的第一个元素 
				A[i]=A[i-D]; 
			}
			A[i]=tmp;
		}
	} 	 	 
}

三、交换排序

①冒泡排序

进行N-1次循环
在第k次循环中对从第1到第n-k个位置上的元素从前往后进行比较。若前一个元素大于后一个元素,则两者交换位置。
这样就把第k大的元素移动到第移到到第N-k个位置上,称为第k趟的冒泡。

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void swap(ElementType*a,ElementType*b); 
void BubbleSort(ElementType A[],int N);
int main(){
	return 0;
}
void BubbleSort(ElementType A[],int N){
	int P,i;//P表示剩下需要进行循环的次数 
	bool flag;
	for(P=N-1;P>=0;P--){ //一共进行N-1次循环(剩下第N次不用进行交换) 
		flag=false;//标记该次循环中是否交换,若无,则说明整个序列有序,直接终止循环
		for(i=1;i<=P;i++){ //一共进行P次冒泡(P次比较)  剩下需要进行循环的次数与循环中需要交换的次数相同 
			if(A[i]>A[i+1]) {
				swap(&A[i],&A[i+1])//只交换元素
				flag=ture 
			}
			if(flag==false) break; //如果在单次循环中无交换 则说明已经有序 直接退出循环 
		} 
		 
	}
}
void swap(ElementType*a,ElementType*b){
		ElementType t=*a;
		*a=*b;
		*b=t;
}
②快速排序

自己写很容易写错
快速排序算法是运用到递归来进行实现
具体步骤:
①选择一个主元(一般采用取中位数法), 并和倒数第二个元素进行交换
②设置两个下标指针Low和High,初值指向第一个元素和倒数第二个元素(主元的前一个元素)
③Low从左向右扫描,其位置左侧为已知遍历或交换过的比主元小的元素;High从右往左扫描,其位置右侧为已遍历或交换过的比主元大的元素。首先从Low指向的位置向右扫描,当遇到比主元大的元素则停止;然后从High指向的位置向左搜索,若遇到比主元小的元素则停止
④若Low和High没有错误,指向的元素交换位置
⑤重复3、4知道Low和High错位。此时将基准与A[Low]对调
⑥对划分好的两个子序列进行递归 当子序列一定小时则可以进行插入排序

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
ElementType Median3(ElementType A[],int Left,int Right); 
int main() {
	return 0;
}
ElementType Median3(ElementType A[],int Left,int Right){//return三个数的中位数 并排序 
	Center = (Left+Right)/2;
	if(A[Left]>A[Center]) swap(&A[Left],&A[Center]);
	if(A[Left]>A[Right]) swap(&A[Left],&A[Center]);
	if(A[Center]>A[Right]) swap(&A[Left],&A[Center]);
	swap(&A[Center],&A[Right-1]);//把基准放在Right-1的位置 
	return A[Right-1];
}

void QuickSort(ElementType A[],int Left,int Right){
	int Pivot,Cutoff,Low,High; //Pivot是基准,cutoff是用插入排序和快速排序的分界线 Low High是下标指针
	if(Cutoff<=Left-Right){ //如果进行排序的元素的数量超过了Cutoff 则进行快速排序 否则进行插入排序 
		Pivot = Median3(A[],Left,Right);
		Low = Left;
		High = Right -1;//注意进行排序的序列中 主元的右边还有一个比主元大的元素 即 A[Right] 
		while(1){ //当比较元素与Pivot相等的时候也停止 可以使Pivot最后调换到较为中间的位置,使两个子序列长度相近 
			while(A[++Low]>Pivot);//为什么是从第二个元素开始比较?因为第一个元素是A[Left]一定比Pivot小 
			while(A[--High]<Pivot);//从倒数第三个元素进行比较 因为倒数第二个元素是Pivot 倒数第一个是A[Right]比Pivot小
			if(Low<High) swap(&A[Low],&A[High]);
			else break;//此时Low比High大,循环终止 进行Pivot的调换 
		}
		swap(&A[Low],&A[Right-1]);//将基准与A[Low]进行对调
		Qsort(A,Left,Low-1);//基准此时在A[Low],左子序列范围是Left-Low-1
		Qsort(A,Low+1,Right);
	} 
	else InsertSort(A+Left,Right-Left+1);//Right-Left+1=N
}
//统一接口
void QuickSort(ElementType A[],int N){
	Qsort(A,0,N-1);//该接口可以自定义 
} 

四、归并排序

将两个已排序的子序列合并程一个有序序列的过程
一开始时N个长度为1的子序列 通过不断X2进行合并直到合并为一个大小为N的序列
则将一个大小为N的序列 对左右递归排序
①首先申请额外的空间用于

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值