zoukankan      html  css  js  c++  java
  • 各种排序算法探讨与实现

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

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

    /*******************************************************************
    *各种排序算法示例程序---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<<"
    After 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;
    }
    
    
    


  • 相关阅读:
    复习列表
    20201009 day30 复习2:滑动窗口
    20201009 day30 复习1:扫描线
    20201007day29 模拟(九)
    20201006day28 模拟(八)
    20201005day27 模拟(七)
    20201004 day26 模拟(六)
    20201003day25 模拟(五)
    路由重分布(一)
    RIP路由协议(一)
  • 原文地址:https://www.cnblogs.com/f8master/p/3826083.html
Copyright © 2011-2022 走看看