各种排序算法探讨与实现

可紊 提交于 2020-03-26 04:16:20

本文对各个排序算法进行了一点复习整理,并通过一段代码对几种排序算法进行了实现。这包括:冒泡排序,插入排序,选择排序,希尔排序,堆排序,归并排序,快速排序,基数排序,计数排序等。相关简要讨论在程序中有一定说明。

各种算法实现见以下示例代码:

/*******************************************************************
*各种排序算法示例程序---By F8Master
*/
#include<stdlib.h>
#include<iostream>
#include<vector>
#include<iomanip>
using namespace std;

template <class Comparable>
void bubbleSort(vector<Comparable> &a);

template<typename Comparable>
void insertSort(vector<Comparable> &a);

template<typename Comparable>
void selectSort(vector<Comparable> &a);

template<typename Comparable>
void shellSort(vector<Comparable> &a);

template<typename Comparable>
void heapSort(vector<Comparable> &a);

template<typename Comparable>
void mergeSort(vector<Comparable> &a);

template<typename Comparable>
void quickSort(vector<Comparable> &a);

template<typename Comparable>
void countSort(vector<Comparable> &a);

template<typename Comparable>
void radixSort(vector<Comparable> &a);

void main()
{
	vector<int> v;
	while(true)
	{
		cout<<"Choose sort Algorithm(0 for end) :"<<endl;
		int num=0;
		cout<<setw(2)<<++num<<setw(20)<<"BubbleSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"InsertSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"SelectSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"ShellSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"HeapSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"MergeSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"QuickSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"CountSort"<<endl;
		cout<<setw(2)<<++num<<setw(20)<<"RadixSort"<<endl;
	

		int selnum;
		cin>>selnum;
		if(selnum==0)
			break;

		v.clear();
		for(int i=0;i<128;i++)
			v.push_back(rand()%1000);
		cout<<"Before sort:"<<endl;
		for(int i =0;i<v.size();i++)
			cout<<setw(5)<<v[i];
		cout<<endl;

		switch(selnum)
		{
		case 1: bubbleSort(v);
		case 2: insertSort(v);
		case 3:selectSort(v);
		case 4:shellSort(v);
		case 5: heapSort(v);
		case 6: mergeSort(v);
		case 7: quickSort(v);
		case 8: countSort(v);
		case 9: radixSort(v);
		default:break;
		}
		cout<<"\nAfter sort:"<<endl;
		for(int i =0;i<v.size();i++)
			cout<<setw(5)<<v[i];
		cout<<endl;
	}
	system("pause");
}
/*****************************************************************/
/* 冒泡排序基本思想是:两两比较相邻记录的关键字,如果反序则交换 
*时间复杂度最好的情况为O(n),最坏的情况是O(n^2);是一种稳定的排序算法
*/
template <class Comparable>
void bubbleSort(vector<Comparable> &a)//冒泡
{
	for(int i = 1;i<a.size();i++)
	{
		for(int j = 0;j<a.size()-i;j++)
		{
			if(a[j]>a[j+1])
				swap(a[j],a[j+1]);
		}
	}
}
/**************************************************************************/

/**************************************************************************/
/*插入排序基本思想: 将一个记录插入到前面已经排好序的序列中, 从而得到一个新的,记录数增1的序列
* 时间复杂度也为O(n^2), 若列表基本有序,则插入排序比冒泡、选择更有效率 */
template<typename Comparable>
void insertSort(vector<Comparable> &a)//插入
{
	insertSort(a,0,a.size()-1);
}
template<typename Comparable>
void insertSort(vector<Comparable> &a, int left, int right)//插入实现,将在快排中用到
{
	for(int i = left+1;i<right-left+1;i++)
	{
		int tmp = a[i];
		int j;
		for(j=i-1;j>=i &&tmp<a[j];j--)
			a[j+1]=a[j];
		a[j+1]=tmp;
	}
}
/**************************************************************************/

/**************************************************************************/
/* 选择排序基本思想:就是通过n-i次比较,从n-i+1个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换。
* 时间复杂度也为O(n^2),但选择排序的性能要略优于冒泡排序 */
template<typename Comparable>
void selectSort(vector<Comparable> &a)//选择
{
	for(int i=0;i<a.size();i++)
	{
		
		int pos = i;
		int min = a[i];
		for(int j = i+1;j<a.size();j++)
		{
			if(a[j]<min)
			{
				min = a[j];
				pos = j;
			}
		}
		swap(a[i],a[pos]);
	}
}
/**************************************************************************/
/*希尔排序基本思想:间隔一定增量的元素进行排序,一次见效增量值直到1
*效率估计O(nlog2^n)~O(n^1.5),取决于增量值的最初大小。建议使用质数作为增量值,本程序并未如此实现
/**************************************************************************/

template<typename Comparable>
void shellSort(vector<Comparable> &a)//希尔
{
	for(int gap = a.size()/2;gap>0;gap/=2)
	{
		for(int i=gap;i<a.size();i++)
		{
			int tmp = a[i];
			int j=i;
			for( ; j>=gap&&tmp<a[j-gap];j-=gap)
				a[j]=a[j-gap];
			a[j]=tmp;
		}
	}

}
/**************************************************************************/

/**************************************************************************/
/*通过构造最大堆,并依次交换最大元素与末尾元素实现排序
*时间复杂度为 O(nlogn)
*/
template<typename Comparable>
void heapSort(vector<Comparable> &a)//堆排序
{
	for(int i=a.size()/2;i>=0;i--)//构造最大堆
		percDown(a,i,a.size());
	for(int j = a.size()-1;j>0;j--)
	{
		swap(a[0],a[j]);
		percDown(a,0,j);
	}
}

int leftChild(int i)
{
	return i*2+1;
}

template<typename Comparable>
void percDown(vector<Comparable> &a,int i,int n)
{
	int child;
	int tmp;//存较小的值
	for(tmp = a[i];leftChild(i)<n;i=child)
	{
		child = leftChild(i);
		if(child!=n-1 && a[child]<a[child+1])
			child++;
		if(tmp<a[child])
			a[i]=a[child];
		else
			break;
	}
	a[i]=tmp;
}
/********************************************************************************/

/********************************************************************************/
/*通过递归实现,将已经有序的两个序列合并为一个序列,该方法对空间的要求较高
* 时间复杂度为O(nlogn),空间复杂度为O(n+logn)
*/
template<typename Comparable>
void mergeSort(vector<Comparable> &a)//归并排序
{
	vector<Comparable> tmpArray(a.size());//临时存储数组
	mergeSort(a,tmpArray,0,a.size()-1);
}

template<typename Comparable>
void mergeSort(vector<Comparable> &a, vector<Comparable> &tmpArray, int left, int right)//归并排序递归调用部分
{
	if(left<right)
	{
		int center = (left + right)/2;
		mergeSort(a,tmpArray,left,center);
		mergeSort(a,tmpArray,center+1,right);
		merge(a,tmpArray,left,center+1,right);
	}
}

template<typename Comparable>
void merge(vector<Comparable> &a, vector<Comparable> &tmpArray, int leftPos, int rightPos, int rightEnd)//归并排序合并部分
{
	int leftEnd = rightPos-1;
	int tmpPos = leftPos;
	int numElements= rightEnd - leftPos +1;
	while(leftPos<=leftEnd && rightPos<=rightEnd)
	{
		if(a[leftPos]<a[rightPos])
			tmpArray[tmpPos++]=a[leftPos++];
		else
			tmpArray[tmpPos++]=a[rightPos++];
	}
	while(leftPos<=leftEnd)
		tmpArray[tmpPos++]=a[leftPos++];
	while(rightPos<=rightEnd)
		tmpArray[tmpPos++]=a[rightPos++];
	for(int i=0;i<numElements;i++,rightEnd--)
		a[rightEnd]=tmpArray[rightEnd];

}
/********************************************************************************/

/********************************************************************************/
/*快速排序基本思想:通过递归实现,选定一个枢纽元素,对待排序序列进行分割,
分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。 
平均时间复杂度O(nlogn)
*/
template<typename Comparable>
void quickSort(vector<Comparable> &a)//快速排序
{
	quickSort(a,0,a.size()-1);
}
template<typename Comparable>
void quickSort(vector<Comparable> &a,int left, int right)//快速排序实现
{
	if(left+10<=right)
	{
		Comparable pivot = median3(a,left,right);//确定枢纽元
		int i =left,j=right-1;
		for( ; ; )
		{
			while(a[++i]<pivot){}//找到左边首个不小于pivot的值
			while(a[--j]>pivot){}//找到右边首个不大于pivot的值
			if(i<j)
				swap(a[i],a[j]);
			else
				break;
		}
		swap(a[i],a[right-1]);
		quickSort(a,left,i-1);
		quickSort(a,i+1,right);
	}
	else
		insertSort(a,left,right);
}

template<typename Comparable>
const Comparable &median3(vector<Comparable> &a,int left,int right)
{
	int center = (left+right)/2;
	if(a[left]>a[center])
		swap(a[left],a[center]);
	if(a[left]>a[right])
		swap(a[left],a[right]);
	if(a[center]>a[right])
		swap(a[center],a[right]);//交换后大小顺序为左<中<右
	swap(a[center],a[right-1]);//枢纽元放在a[right-1]位置
	return a[right-1];
}

/********************************************************************************/

/********************************************************************************/
/*计数排序基本思想:通过一个额外的count数据记录出每个元素的个数,并计算出应该出现的位置,从而实现排序
*该方法不基于比较
*/
template<typename Comparable>
void countSort(vector<Comparable> &a)//计数排序
{
	Comparable min,max;
	findMinMax(a,a.size(),&min,&max);
	int numElements = max-min+1; //跨度范围
	vector<Comparable> count(numElements,int(0));
	for(int i = 0;i<a.size();i++)//计数
	{
		count[a[i]-min]++;
	}
	for(int i=0,j=0;i<numElements;i++)//重写原数组
	{
		while(count[i]>0)
		{
			a[j++]=i+min;
			--count[i];
		}
	}

}
template<typename Comparable>
void findMinMax(vector<Comparable> &a,int size,Comparable *min,Comparable *max)
{
	if(size==0)
		return;
	else if(size==1)
	{
		*min = *max = a[0];
		return;
	}
	else
	{
		*min = a[0]<a[1]?a[0]:a[1];
		*max = a[0]>a[1]?a[0]:a[1];
		Comparable tmpMin;
		Comparable tmpMax;
		int i,j;
		for(i = 2,j = 3 ; i<size&&j<size ;i+=2,j+=2)
		{
			tmpMin = a[i]<a[j]?a[i]:a[j];
			tmpMax = a[i]>a[j]?a[i]:a[j];
			if(tmpMin<*min)
				*min = tmpMin;
			if(tmpMax>*max)
				*max = tmpMax;
		}
		if(size%2!=0)
		{
			if(a[size -1] > *max)
				*max = a[size - 1];
			else if(a[size -1] < *min)
				*min = a[size -1];
		}
	}	
}
/********************************************************************************/

/********************************************************************************/
/*基数排序基本思想:对于int型而言,可以解释为一次一句百位、十位、个位进行分组,组内递归调用进行排序
*/
template<typename Comparable>
void radixSort(vector<Comparable> &a)//基数排序
{
	radixSort(a,0,a.size()-1,3);
}
template<typename Comparable>
void radixSort(vector<Comparable> &a,int left,int right,int d)
{
	int i,j,radix=10,p1,p2;
	vector<Comparable> count(radix,int(0));//计数数组
	vector<Comparable> auxArray(right-left+1);//辅助数组
	if(d<=0)//递归截止条件
		return;
	
	for(i=left;i<=right;i++)
		count[getDigit(a[i],d)]++;
	for(j=1;j<radix;j++)
		count[j]+=count[j-1];

	for(i=left;i<=right;i++)
	{
		j=getDigit(a[i],d);
		auxArray[count[j]-1]=a[i];
		count[j]--;
	}
	for(i=left,j=0;i<=right;i++,j++)//辅助数组元素写入原数组
	{
		a[i]=auxArray[j];
	}
	for(j=0;j<radix;j++)
	{
		p1=count[j]+left;
		if(j==radix-1)
			p2=right;
		else
			p2=count[j+1]-1+left;
		if(p1<p2)
			radixSort(a,p1,p2,d-1);
	}
	
}
int getDigit(int a,int d)//返回指定位的值,个位为d=1,以此类推
{
	int tmp=1;
	for(int i=0;i<d-1;i++)
		tmp*=10;
	return (a / tmp)%10;
}




易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!