• 排序算法合集 2015-06-30 08:43 155人阅读 评论(0) 收藏


    排序算法复习大致结束了,主要有以下几种:冒泡排序、选择排序、简单插入排序、希尔排序、归并排序、快速排序、堆排序。

    #include <iostream>
    
    #define MAXSIZE 1000
    
    using namespace std;
    
    class SqList{
    public:	
    	SqList():length(0){}
    	SqList(int length1,int value=0):length(length1)
    	{
    		for(int i=0;i<length;++i)
    		{
    			data[i]=value;
    		}
    	}
    	
    	bool insertTail(int value)
    	{
    		if(length>=MAXSIZE)
    		{
    			return false;
    		}
    		data[length]=value;
    		length++;
    		return true;
    	}
    	
    	friend ostream& operator<<(ostream& output, SqList list);
    
    	
    public:
    	int data[MAXSIZE];
    	int length;
    };
    
    void swap(int& a,int &b)
    {
    	int tmp=a;
    	a=b;
    	b=tmp;
    }
    
    ostream& operator<<(ostream& output, SqList list)
    {
    	for (int i = 0; i<list.length; ++i)
    	{
    		output <<list.data[i] << "   ";
    		if ((i + 1) % 18 == 0)
    			output << endl;
    	}
    	output << endl;
    	return output;
    }
    
    /**
     *冒泡排序即相邻的两者相互比较,根据需求把较大的或较小的前移或后移
     *记住,两两相邻的比较是冒泡排序的特点之一
     */
    void BubbleSort1(SqList* list)
    {//每次遍历时把较大者后移
    	int length=list->length;
    	while(length>0)
    	{
    		for(int i=0;i<length-1;++i)
    		{
    			if(list->data[i] > list->data[i+1])
    				swap(list->data[i],list->data[i+1]);
    		}
    		length--;
    	}
    }
    
    void BubbleSort2(SqList* list)
    {//每次遍历时,把较小的前移
    	for(int i=0;i<list->length;i++)
    	{
    		for(int j=list->length-2;j>=i;j--)
    		{
    			if(list->data[j] > list->data[j+1])
    				swap(list->data[j],list->data[j+1]);
    		}
    	}
    	
    }
    
    /**
     *选取排序即每次在未排序队列当中选取一个最小值,然后与第i个值进行交换,直至i为length为止;
     *当然,也可以选取最大值把到后面,根据需求而定
     */
    
    void selectSort(SqList* list)
    {
    	for (int i = 0; i < list->length; ++i)
    	{
    		int min = list->data[i];
    		int pos = i;
    		for (int j = i+1; j < list->length; ++j)
    		{
    			if (list->data[j] < min)
    			{
    				min = list->data[j];
    				pos = j;
    			}
    		}
    		if (pos != i)
    		{
    			swap(list->data[i], list->data[pos]);
    		}
    	}
    }
    
    /**
     *遍历链表,把每个元素插入到正确位置
     */
    void InsertSort1(SqList *list)
    {
    	for (int i = 1; i < list->length; ++i)
    	{
    		int j = i - 1;
    		for (; j >=0; j--)
    		{
    			if (list->data[i] > list->data[j])
    				break;
    		}
    		int tmp = list->data[i];
    		for (int k = i; k > j+1; --k)
    		{
    			list->data[k] = list->data[k - 1];
    		}
    		list->data[j + 1] = tmp;
    	}
    }
    
    void InsertSort2(SqList *list)
    {
    	for (int i = 1; i < list->length; ++i)
    	{
    		if (list->data[i] < list->data[i - 1])
    		{
    			int tmp = list->data[i];
    			int j = i-1;
    			for (; j >= 0 && list->data[j] > tmp; --j)
    			{//查找的同时,进行后移操作
    				list->data[j + 1] = list->data[j];
    			}
    			list->data[j + 1] = tmp;
    		}
    	}
    }
    
    /**
     *希尔排序是插入排序的一种改进,可以理解为把一个数组分成几个小的数组进行插入排序,再合并使原数组基本有序。
     *希尔排序一个很关键的步骤是增量的选取,合适的增量能够提高排序效率,但不合适的增量可能会导致程序崩溃或结果错误。
     *其次,希尔排序也不是一个稳定的排序算法,因为它是跳跃插入排序的。
     *希尔排序只是比前面几种O(n2)的效果稍好,并不会优于后面要提到的快速排序等算法。
     */
    void ShellSort(SqList* list)
    {
    	int increment = list->length;
    	do{
    		increment = increment / 3 + 1;
    		for (int i = increment + 1; i < list->length; ++i)
    		{
    			if (list->data[i] < list->data[i - increment])
    			{
    				int tmp = list->data[i];
    				int j = i - increment;
    				for (; j >= 0 && list->data[j] > tmp; j -= increment)
    				{
    					list->data[j + increment] = list->data[j];
    				}
    				list->data[j + increment] = tmp;
    			}
    		}
    	} while (increment > 1);
    }
    
    
    /**
     *归并排序原理上相对比较简单,即两个有序数组合并为一个有序数组
     *但实现起来相对比较复杂,要用到辅助空间
     */
    //合并过程
    void Merge(int TR1[], int TR2[], int low, int mid, int high)
    {//将TR2归并入TR1中
    	int pos1 = low;
    	int pos2 = mid + 1;
    	for (int i = low; i <= high; ++i)
    	{
    		if (pos1 <= mid && pos2 <= high)
    		{		
    			if (TR2[pos1]>TR2[pos2])
    			{
    				TR1[i] = TR2[pos2];
    				pos2++;
    			}
    			else
    			{
    				TR1[i] = TR2[pos1];
    				pos1++;
    			}
    	    }
    		else if (pos1<=mid)
    		{
    			TR1[i] = TR2[pos1++];
    		}
    		else
    		{
    			TR1[i] = TR2[pos2++];
    		}		
    	}
    }
    //排序过程
    void Msort(int SR[],int TR1[], int low, int high)
    {
    	int TR2[MAXSIZE + 1];
    	if (low < high)
    	{//先全部存放到TR2中,再由TR2归并到TR1
    		int mid = (low + high) / 2;
    		Msort(SR,TR2,low, mid);
    		Msort(SR,TR2,mid + 1, high);//先将两个子序列排序,然后再合并
    		Merge(TR1, TR2, low, mid, high);
    	}
    	else
    	{
    		TR1[low] = SR[low];
    	}
    }
    void MergeSort1(SqList* list)
    {
    	Msort(list->data,list->data,0,list->length-1);
    }
    
    void MergePass(int TR[], int SR[], int k, int length)
    {
    	int i = 0;
    	while (i <= length-2*k+1)
    	{//两两合并
    		Merge(TR, SR, i, i + k-1, i + 2 * k - 1);
    		i = i + 2 * k;
    	}
    
    	if (i <= length - k + 1)
    	{//说明后面还剩两个子数组,一个是完整的k个,另一个小于k
    		Merge(TR, SR, i, i + k - 1, length);
    	}
    	else
    	{//最后只剩一个子数组,
    		for (int j = i; j <= length; j++)
    		{
    			TR[j] = SR[j];
    		}
    	}
    }
    void MergeSort2(SqList* list)
    {
    	int* TR = new int[list->length];
    	int k = 1;
    	while (k < list->length)
    	{//两次转存,先从data转存到TR,再从TR转存到data; 
    		MergePass(TR, list->data, k, list->length - 1);
    		k = k * 2;
    		MergePass(list->data, TR, k, list->length - 1);
    		k = k * 2;
    	}
    }
    
    /**
     *快速排序将以枢轴为界,将原数组分为两个部分,枢轴以前,值都小于枢轴的值,枢轴以后的值都大于枢轴
     *采用递归的方法,对以枢轴为界的两个子序列进行快速排序,直至子序列长度为1
     *1、快速排序的关键是枢轴的选取,主要有三种方法:1)选取第一个或最后一个作为枢轴值;
     *2)采用随机数生成器,生成枢轴值的下标;3)取第一个、最后一个、中间三者的中间值作为枢轴值。
     *2、快速排序因为要递归,当需要排序的数组量比较小时,使用普通的排序算法效果可能更好,所以又出现了一种优化方法。
     *相较于归并排序和堆排序,快速排序是一种高效而且简单的排序方法。
     */
    int partion(SqList* list, int low, int high)
    {
    	int key = list->data[high];//枢轴值
    	int fast = low;
    	int slow = low;
    	while (fast < high)
    	{
    		if (list->data[fast] < key)
    		{
    			if (slow != fast)
    			{
    				swap(list->data[fast], list->data[slow]);				
    			}
    			fast++;
    			slow++;
    		}
    		else
    		{
    			fast++;
    		}
    	}
    	swap(list->data[slow], list->data[high]);
    	return slow;
    }
    void qsort1(SqList* list,int low,int high)
    {
    	if (low < high)
    	{
    		int index = partion(list,low,high);
    		qsort1(list, low, index - 1);//高低子表都采用递归的方法实现
    		qsort1(list, index + 1, high);
    	}
    }
    
    #define MAX_LENGTH_INSERT_SORT 7//定义插入排序可以接受的最大数组
    void qsort2(SqList* list, int low, int high)
    {
    	if ((high - low) > MAX_LENGTH_INSERT_SORT)
    	{
    		if (low < high)
    		{
    			int index = partion(list, low, high);
    			qsort2(list, low, index - 1);
    			qsort2(list, index + 1, high);
    		}
    	}
    	else
    		InsertSort2(list);//当然,此处不能直接使用,还需要对InsertSort2作一下修改,改成指定下标的形式
    }
    //只用一次递归,高子表采用迭代的方式,减小了递归的深度。
    void qsort3(SqList* list, int low, int high)
    {
    	if ((high - low) > MAX_LENGTH_INSERT_SORT)
    	{
    		if (low < high)
    		{
    			int index = partion(list, low, high);
    			qsort2(list, low, index - 1);
    			low = index + 1;//高子表不递归,采用迭代
    		}
    	}
    	else
    		InsertSort2(list);//当然,此处不能直接使用,还需要对InsertSort2作一下修改,改成指定下标的形式
    }
    void QuickSort(SqList* list)
    {
    	qsort1(list,0,list->length-1);
    }
    
    /**
     *堆排序也没有想像中那么复杂,建堆和堆维护都可以用一个函数完成;
     *
     */
    void HeapAdjust(SqList* list, int obj, int length)
    {
    	int tmp = list->data[obj - 1];
    	for (int j = 2*obj; j <= length; j *= 2)
    	{//一定要注意下标和编号的不统一,堆排序开始编号是1,而本程序的数据结构开始编号是0。
    		//也就是说编号j对应的下标是j-1
    		if (j < length && list->data[j-1] < list->data[j])
    			j++;
    		if (list->data[j-1] <= tmp)
    		{
    			break;
    		}
    		list->data[obj - 1] = list->data[j-1];
    		obj = j;
    	}
    	list->data[obj - 1] = tmp;
    }
    void HeapSort(SqList* list)
    {
    	//第一次循环,建立最大堆
    	for (int i = list->length / 2; i > 0; i--)
    	{//注意,传入的参数都是下标再加1
    		HeapAdjust(list, i, list->length);
    	}
    	//第二次循环,排序
    	for (int i = list->length; i > 0; i--)
    	{
    		swap(list->data[0],list->data[i - 1]);
    		HeapAdjust(list, 1, i-1);
    	}
    }
    
    int main()
    {
    	SqList list;
    	list.insertTail(5);
    	list.insertTail(7);
    	list.insertTail(9);
    	list.insertTail(8);
    	list.insertTail(4);
    	list.insertTail(3);
    	list.insertTail(1);
    	list.insertTail(10);
    	list.insertTail(16);
    	list.insertTail(78);
    	list.insertTail(0);
    	
    	cout<<"排序前:"<<endl;
    	cout<<list<<endl;
    	
    	/*BubbleSort2(&list);
    	cout<<"冒泡排序法:"<<endl;
    	cout<<list<<endl;*/
    
    	/*selectSort(&list);
    	cout << "选择排序法:" << endl;
    	cout << list << endl;*/
    	
    	/*InsertSort2(&list);
    	cout << "插入排序法:" << endl;
    	cout << list << endl;*/
    /*
    	ShellSort(&list);
    	cout << "希尔排序法:" << endl;
    	cout << list << endl;*/
    
    	//MergeSort1(&list);
    	//cout << "归并排序:" << endl;
    	//cout << list << endl;
    
    	/*QuickSort(&list);
    	cout << "快速排序:" << endl;
    	cout << list << endl;*/
    
    	HeapSort(&list);
    	cout << "堆排序:" << endl;
    	cout << list << endl;
    
    	
    	return 0;
    }
    


  • 相关阅读:
    网络流 讲解
    二分图判定 【模板】
    POJ——T3352 Road Construction
    shell脚本编写-自动部署及监控
    万能头文件
    1284 2 3 5 7的倍数(容斥原理)
    1289 大鱼吃小鱼(栈)
    1305 Pairwise Sum and Divide(数学 ,规律)
    博客达人
    Prim算法---最小生成树
  • 原文地址:https://www.cnblogs.com/zclzqbx/p/4687082.html
Copyright © 2020-2023  润新知