C++实现各常用排序算法

内排序

  提供插入排序、冒泡排序、选择排序、Shell排序、归并排序、快速排序、堆排序、分配排序、基数排序的实现代码(附注释)和图解.


           插入排序

//顾名思义,每处理一组新的数据,
//都需要吧这个数据加到之前已经是有序的部分中

//时间复杂度是O(n^2)
template<typename E>
void inssort(E A[],int n){
	for(int i=1;i<n;i++){
		for(int j=i;j>0;j--)	//i之前都是有序的
			if(A[j-1]>A[j])		//仅仅需要一个一个与之前的进行比较
				swap(A[j-1],A[j]);
	}
}

           冒泡排序

//自下往上,从j处一个一个同上面的元素进行比较,
//满足则交换

//时间复杂度是O(n^2)

template<typename E>
void bubsort(E A[],int n){
	for(int i=0;i<n-1;i++)
		for(int j=n-1;j>i;j--)
			if(A[j]<A[j-1])			//逐个与之前的一个进行比较
				swap(A[j],A[j-1]);

           选择排序

//从数组中选择最小的,然后放到数组的第一个位置
//然后选取次小的放到第二个位置,循环至有序

//时间复杂度是O(n^2)

template<typename E>
void selsort(E A[],int n){
	for(int i=0;i<n-1;i++){
		int lowIndex=i;		//记为本次循环最小的
		for(int j=n-1;i>i;j--)
			if(A[lowIndex]>A[j])
				lowIndex=j;
		swap(A[lowIndex],A[i]);
	}
}

           Shell排序

//Shell试图将待排序序列变成基本有序的,
//再利用插入排序完成
//处理n个长度的数组时,依次比较相邻为n/2、n/4、……、1个长度的子序列

//时间复杂度是O(n^1.5)

//仅仅对一个截至下标为n,相隔(长度)为incr的子序列进行排序
template<typename E>
void inssort2(E A[],int n,int incr){
	//incr是分割后子序列的增量
	for(int i=incr;i<n;i+=incr)
		for(int j=i;j>=incr;j-=incr)
			if(A[j]<A[j-incr])
				swap(A[j],A[j-incr]);
}

template<typename E>
void shellsort(E A[],int n){
	for(int i=n/2;i>=2;i/=2)	//i是子序列长度
		for(int j=0;j<i;j++)
			inssort2(&A[j],n-j;i)inssort2(A,n,1);
}

           归并排序

//运用分治法,将待排序的列表分成片段
//再处理个片段,最后通过某种方式将片段重组

//时间复杂度是O(nlogn)

template<typename E>
void MergeSortHelp(E A[],E reg[],int left,int right){
	//temp用来存放有序的序列
	if(left==right)	return;
	int mid=(right+left)/2;

	//分别做有进行迭代
	mergesort(A,reg,left,mid);
	mergesort(A,reg,mid+1;right);

	int k=left;

	//将两个序列从头往后进行比较,
	//将两个序列中较小的加到有序数组reg中

	while(start1<=end1 && start2<=end2)
		reg[k++]=arr[start1]<arr[start2] ?
					arr[start1++] : arr[start2];
	//若序列2到达了结尾但是序列1仍有数据未加入有序reg中
	//由于只有一个,直接加入
	while(start1<=end1)
		reg[k++]=arr[start1++];

	//若序列1到达了结尾但是序列2仍有数据未加入有序reg中
	//由于只有一个,直接加入
	while( start2<=end2)
		reg[k++]=arr[start2++];

	//对原数组进行覆盖
	for(k=left;k<=right;k++)
		arr[k]=reg[k];

	delete[] reg;
}

void mergesort(E A[],const int n){
	E reg[n];
	MergeSortHelp(A,reg,0,n-1);
}

           快速排序

//选定一个轴值,由这个轴值将数组分成两部分
//左侧元素都比轴值小,右侧均大于或等于轴值
//重复操作至排序完成

//时间复杂度O(nlog2n)

template<typename E>
void  QuickSortOnce(int A[],int first,int end){
	int i=first,j=end;
	
	while(i<j){		//找轴值--尽量确保之在中间位置
		
		while(i<j && [i]<=A[j]) j--;	//在满足条件的情况下先对j进行往前移动
		if(i<j)	//i<j满足则说明A[i]>A[j]
			swap(arr[i],arr[j]);
				//否则满足A[i]<=A[j],则i=j,,不执行i++操作直接结束,找到轴值
		while(i<j && A[i]<=A[j]) i++;	//在满足条件的情况下再对i进行往后移动
		if(i<j)
			swap(arr[i],arr[j]);
	}

	//找到轴值(此时i==j,返回哪个都行)
	return i;	
}

template<typename E>
void  QuickSortHelp(int A[],int first,int end){
	int p=QuickSortOnce(A,first,end);

	QuickSortOnce(A,first,p);
	QuickSortHelp(A,p+1,end);
}

template<typename E>
void  QuickSort(int A[],int n){
	//长为n的数组A进行排序
	QuickSortHelp(A,0,n-1);
}

           堆排序

buildHeap()及removefirst()方法请参考我的另一篇博客

//利用最大堆实现从小到大排序
//通过逐渐移除最大堆的第一个元素并放到数组后面实现

//时间复杂度是O(n+klogn):建堆O(n)、移动堆顶元素是O(logn)
//k表示找到数组中第k大的元素

template<typename E>
void HeapSort(E A[],const int n){
	heap<E> H(A,n,n);
	H.buildHeap();				//以A为数据源建立堆H
	for(int i=n-1;i>=0;i--)
		A[i]=H.removefirst();	//该方法实现意思是移除堆顶的元素
}

           分配排序

//通过一次遍历将总数据分别放到不同“盒子”中--通过关键码
//在对每个“”盒子中数据按照各自的进行排序
//即--通过记录关键码,直接取,直接放

//时间复杂度是O(n)--在满的情况下

//通过数组+链表实现

template<typename E>
void AlloSort(E A[],const int n){
	E reg[n];
	int t=0;

	List<E> B[10];	//MaxKeyNum是能容纳关键码数量-- 0~9
	E item;
	for(int i=0;i<n;i++)
		B[A[i]%10].push_back(A[i]);
	for(int i=0;i<10;i++)
		for(B[i].begin();B[i].getValue(item);B[i].next()){
			reg[t++]=item;
		}
	for(int i=0;i<n;i++)
		A[i]=reg[i];
}

//只适用于满的盒子

           基数排序

//对分配排序的扩展,同样用到了关键码
//但是是将某个空的没有用的位置留给其他基数使用

//时间复杂度是 O(nk+rk)--对n和数据,r个基数,k轮分配工作

template<typename E>
void RadixSort(E A[],int n,int k,int r,
				int cnt[]){
	//cnt数组用于存放关键码
	//n是A数组的长度
	//k是要排序的数的位数--个位是1,千位是4……
	//r表示进制数,一般对10进制排序r就取10(从0~9)

	int j;

	for(int i=0,rtoi=1;i<k;i++,rtoi*=r)	//rtoi表示1~10~100~……
		//初始化
		for(j=0;j<r;j++)	cnt[j]=0;	

		//统计各关键码(数字)出现的次数并放入cnt数组中
		for(j=0;j<n;j++)	cnt[(A[j]/rtoi)%r]++;

		//计算各关键码(数字)在数组中的下标并将结果放入cnt数组
		for(j=1;j<r;j++)	cnt[j]=cnt[j-1]+cnt[j];

		//依次从中取出并放入B数组形成有序的
		for(j=n-1;j>=0;j--)
			B[--cnt[(A[j]/rtoi)%r]]=A[j];

		for(j=0;j<n;j++)
			A[i]=B[j];
}

猜你喜欢

转载自blog.csdn.net/hacker_Dem_br/article/details/85215979