zoukankan      html  css  js  c++  java
  • 排序算法进阶

    常用排序算法

    一、排序算法的稳定性

    1、稳定排序

    排序前两个相等的数在序列中的前后位置和排序后他们两个的前后位置相同

    比如:冒泡,插入,基数,归并等

    2、非稳定排序

    排序前两个数的相对位置在排序后会发生改变

    比如:选择,快速,希尔,堆等

    二、算法性能评价

    1、执行时间及所需的辅助空间

    2、算法本身的复杂程度

    三、几种排序算法

    1、插入排序

    也叫直接插入排序,对于少量元素的排序,这是一个有效的算法

    基本思想:将一个记录插入到已经排序的有序表中,从而产生一个新的,记录数加1的有序表

    void insert_sort(T* parr, int len)
    {
    	int tempval;
    	int j;
    	for (int i = 1; i < len; i++)//i表示待排序序列第一个数的下标
    	{
    		for (j = i - 1; j >= 0; j--)//j表示已序序列的最后一个数的下标
    		{
    			if (parr[j + 1] < parr[j])
    			{
    				tempval = parr[j + 1];
    				parr[j + 1] = parr[j];
    				parr[j] = tempval;
    			}
    			else
    				break;//优化
    		}
    	}
    }
    

    目前的最优解--降低时空复杂度

    #include<iostream>
    #include<ctime>
    #include<cstdlib>
    using namespace std;
    template<typename T>
    void insert_sort(T* parr, int len)
    {
    	int tempval;
    	int j;
    	for (int i = 1; i < len; i++)//i表示待排序序列第一个数的下标
    	{
    		tempval = parr[i];//将待排序数用中间变量保存起来
    		j = i - 1;//j表示已序序列的最后一个数的下标
    		while (j >= 0 && tempval < parr[j])//待排序数要小于已序序列的最后一个数,才执行
    		{
    			parr[j+1] = parr[j];
    			j--;
    		}//目的:将大于待排序数的数依次从后往前赋值,直到这个待排序数小于已序序列中的某个数为止	
    		parr[j + 1] = tempval;//赋值结束后,将这个待排序数赋值给最后一个被比较的数
    	}
    	
    }
    template<typename T>
    void print(T* parr, int len)//输出  
    {
    	for (int i = 0; i < len; i++)
    	{
    		cout << parr[i] << " ";
    	}
    	cout << endl;
    }
    
    int main()
    {
    	int arr[10] = { 0 };
    	srand((unsigned int)time(NULL));
    	for (int i = 0; i < 10; i++)
    	{
    		arr[i] = rand() % 100;
    	}
    	print(arr, 10);
    	insert_sort(arr, 10);
    	print(arr, 10);
    	
    	getchar();
    	getchar();
    	return 0;
    }
    
    
    

    2、希尔排序

    希尔排序是插入排序的一种又称"缩小增量排序",非稳定排序算法

    基本思想:把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量的逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件被分成一组,算法便终止

    void shell_sort(int* parr, int len)
    {
    	int tempval;//中间变量
    	int j;
    	int jump = len >> 1;//每次插入的步数,开始为排序数列的一半
    	while (jump != 0)//只要步数不为0,就一直执行
    	{
    		for (int i = jump; i < len; i++)//确定循环次数,i可以表示待排序数列的第一个数的下标
    		{
    			tempval = parr[i];//把待排序数用中间变量保存好
    			j = i - jump;//待排序数和它所要比较的数
    			while (j >= 0 && tempval < parr[j])//顺序排序,大的数往后面排
    			{
    				parr[j + jump] = parr[j];//将比较的数进行交换
    				j -= jump;//当jump=1时,这个条件就有用了,可以让待排序数从前往后依次比较
    			}
    			parr[j + jump] = tempval;//如果待排序数比要比较的数大,就将自己给自己赋值,保持不变就行。但是待排序数比要比较的数小,那么就将这个待排序数赋值给,待排序数最后一个比较的数
    		}
    		jump >>= 1;
    
    	}
    }
    

    3、快速排序

    基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成 有序序列

    #include<iostream>
    #include<ctime>
    #include<cstdlib>
    using namespace std;
    void quick_sort(int* parr, int low, int hight)//传一个低位,一个高位下标,相当于数组下标0,和最后一个下标
    {
    	int tempval;
    	int t = parr[low];//确定标杆的值,就是数组里的第一个元素
    	int f, b;//f希望指的数比标杆要小,b希望指的数比标杆大
    	f = low + 1;//从标杆的左边第一个数开始找
    	b = hight;//右边的边界,数组的最右边的数
    	if (low >= hight)//递归的终止条件,表示只有一个元素不需要定位
    		return;
    	while (f <= b)//待搜索位置已经搜索完成
    	{
    		while (f <= b && parr[f] <= t)//f<=b表示待搜索的区间还没有搜索完,且f所指的值比标杆小
    		{
    			f++;//向后面移动一位,再进行比较
    		}
    		while (f <= b && parr[b] >= t)//f<=b表示待搜索区间还没有搜索完,且b所指的值比标杆大
    		{
    			b--;//向前移动再进行比较
    		}
    		//到这里,有可能区间还没有搜索完,f指向一个大于标杆的数,b指向一个小于标杆的数
    		if (f < b)//证明区间没有搜索完
    		{
    			tempval = parr[f];
    			parr[f] = parr[b];
    			parr[b] = tempval;//将两个拿来比较的数,进行交换
    			f++;
    			b--;
    		}
    	}
    	parr[low] = parr[b];
    	parr[b] = t;//将标杆所指的数和b所指的数进行交换
    	quick_sort(parr, low, b - 1);//排好第一个数据
    	quick_sort(parr, b + 1, hight);//递归,排好最后一个数据
        //这两个递归语句是第一个是:减小hight的值,直到hight=low,退出语句,执行下一句,增加low的值,直到low=hight,退出函数 
    
    
    }
    
    void print(int* parr, int len)
    {
    	for (int i = 0; i < len; i++)
    	{
    		cout << parr[i] << " ";
    	}
    	cout << endl;
    }
    
    int main()
    {
    	int arr[10] = { 0 };
    	srand((unsigned int)time(NULL));
    	for (int i = 0; i < 10; i++)
    	{
    		arr[i] = rand() % 100;
    	}
    	print(arr, 10);
    	quick_sort(arr, 0,10);
    	print(arr, 10);
    
    	getchar();
    	getchar();
    	return 0;
    }
    
    
    

    4、计算一个排序算法所用时间

    使用timeGetTime()函数,包含头文件

    #include<windows.h>
    #pragma comment(lib,"winmm.lib)
    

    具体用法

    #include<iostream>
    #include<ctime>
    #include<cstdlib>
    #include<windows.h>
    #pragma comment(lib,"winmm.lib")
    using namespace std;
    void sort(int* parr, int len)//选择排序
    {
    	int j = 0;
    	int temp = 0;
    	for (int i = 0; i < len - 1; i++)
    	{
    		for (j = i; j < len - 1; j++)//前面不变
    		{
    			if (parr[i] > parr[j + 1])
    			{
    				temp = parr[i];
    				parr[i] = parr[j + 1];
    				parr[j + 1] = temp;
    			}
    		}
    	}
    }
    #define MAX_LEN 10000
    int main()
    {
    	int arr[MAX_LEN] = { 0 };
    	srand((unsigned int)time(NULL));
    	for (int i = 0; i < MAX_LEN; i++)
    	{
    		arr[i] = rand() % 100;
    	}
    	float beginTime = timeGetTime() / 1000.0f;
    	sort(arr, MAX_LEN);
    	float endTime = timeGetTime() / 1000.0f;
    	printf("%f
    ", endTime - beginTime);
    	getchar();
    	getchar();
    	return 0;
    }
    
    
    

    四、排序算法的选择

    所用时间:

    快速排序<希尔排序<插入排序<选择排序<冒泡排序

    快速排序所占的内存较大,比希尔排序空间复杂度大,所以一般选择希尔排序

    但是在实际中一般根据需要来选择排序算法

  • 相关阅读:
    [转]为iPhone4S和iOS5增加全局英汉词典教程
    Notes on MSBuild
    Using jQuery To Manipulate and Filter Data
    使用MSBuild进行自动化构建
    使用ADO.NET的计算列
    来自Twitter的前端工具包——Bootstrap
    Jquery Templetes简介
    C#导入导出Excel
    Mysql在sql中截取时间类型字段的年月日和时间
    使用NPOI导出Excel,并在Excel指定单元格插入图片
  • 原文地址:https://www.cnblogs.com/Kissfly123/p/14495243.html
Copyright © 2011-2022 走看看