码迷,mamicode.com
首页 > 编程语言 > 详细

八大排序算法

时间:2016-08-25 21:40:25      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:

排序算法 

 排序算法 ,在编程中算一个最基础的问题之一 。
排序算法有很多的方法   ,比如:
1.冒泡排序 ;
2.插入排序;
3.希尔排序
4.选择排序;
5.堆排序;
6.快速排序;
7.归并排序;
8.基数排序;

这个便是算 法界 中广为流传的 八大算法   。不知道的可以记一下 。

下面就来详细讲讲这些算法的优缺点:
技术分享

这幅图,是我从网上找的串,但这不重要 ,它很好的向我们展示了 八大算法的 时间复杂度 、空间复杂度
以及稳定性 

下面来详细讲讲这些算法


一、冒泡排序

  基本思想:通过无序区中相邻元素间的比较和位置的交换,使最小的元素如气泡一般逐渐往上“漂浮”直至“水面”——就是数组尾部 ,在这里形成一个有序区。

关键点:设计交换判断条件,提前结束以排好序的序列循环。 
时间复杂度:  
最好情况下:
正序有序,则只需要比较n次。故,为O(n)  
最坏情况下:  逆序有序,则需要比较(n-1)+(n-2)+……+1,故,为O(n*n)
图形表达:
技术分享
代码实现:
void  Bubble_Sort(int arr[],int len)//arr为数组名,len为数组长度
{
	int i =0 ;
	int j = 0;
	for( i=0;i<len-1;i++)
    {
       for(j=0;j<(len-1-i);j++)//设置无序与有序序列的分割条件    (len-1-i)
	   {
	      if(arr[j]>arr[j+1])//前者小于后者
		   {
			   int temp=arr[j];//两数交换
		       arr[j]=arr[j+1];
		       arr[j+1]=temp;
		   } 
	   }	  
   }
}


二、插入排序


基本思想:将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据。每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。

算法的操作:
插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

代码实现:
void Insert_Sort(int arr[],int sz)//sz为数组的长度
{
	int i =0 ,j=0;
	int temp = 0;
	for(i =1 ;i< sz;i++)
	{
		temp =arr[i];//记录下  要插入到序列中的数
		j = i -1;
		while(j>=0&& temp<arr[j])//要插入的序列
		{
			arr[j+1]= arr[j];  //将序列中的数字向后移上一位 直到插入的数大于序列中的数
			j--;
		}
		arr[j+1] = temp;//将要插入的数插到序列中
	}	
}


三、希尔排序


基本思想希尔排序也是一种插入排序方法,实际上是一种分组插入方法。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。 
例如:将 n 个记录分成 d 个子序列: 
       { R[0],   R[d],     R[2d],…,     R[kd] } 
       { R[1],   R[1+d], R[1+2d],…,R[1+kd] } 
         … 
       { R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }
 
                          技术分享

算法 关键 :增量的选择以及排序最终以1为增量进行排序结束。


 时间复杂度。  
     最好情况
:由于希尔排序的好坏和步长d的选择有很多关系,因此,目前还没有得出最好的步长如何选择(现在有些比较好的选择了,但不确定是否是最好的)。所以,不知道最好的情况下的算法时间复杂度。  
     最坏情况下:O(n*logn),最坏的情况下和平均情况下差不多。  
     平均情况下:O(n*logn)

void Shell_Sort(int arr[],int len)
{
	int d = 0 ;
	int i = 0;
	int j = 0;
	int temp = 0;
	d= len/2;
	while(d >  0)
	{
		for(i = d;i< len ;i++)//各组内的插入排序
		{
			temp =arr[i];
			j =i-d;
			while(j >= 0 && arr[j] > temp )
			{
			arr[j+d] = arr[j];
			j -=d;
			}
			arr[j+d] =temp;
		}
		d=d/2;//递减增量
	}
}

 

四、选择排序


基本思路:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
关键点:记住有序数列与无序数列的间隔 

思路图:
技术分享

代码实现
void Select_Sort(int arr[],int len)//len为数组长度
{

	int i = 0;
	int j = 0;
	int temp= 0;
	for(i =0 ;i< len-1;i++)//判断需要几次排序
	{
		int min =i;//min为最小元素的下标
		for(j =i;j< len;j++)//将无序区的最小的数下标的找出来给min
		{
			if(arr[j] <arr[min])
			{
				min= j;
			}
		}
		temp= arr[i];//将下标为min的数放到有序区
		arr[i]= arr[min];
		arr[min] = temp;
	}
}


五、堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引元素。堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

关键点:建堆 ,交换 ,堆调整 

堆排序的基本思想是:
利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最大(或者最小)的记录。也就是说,以最小堆为例,根节点为最小元素,较大的节点偏向于分布在堆底附近。
技术分享



代码实现

这个代码是转载别人的
技术分享

六、快速排序

基本思路:它是由冒泡排序改进而来的。在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分 。
数组所有元素大小 比该记录小的放到前一部分比它大的放到右边
并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。
         技术分享

最核心的思想是  左右 分割。
算法复杂度  
     最好的情况下:因为每次都将序列分为两个部分(一般二分都复杂度都和logn 相关),故为 O(n*logn)  
     最坏的情况下:基本有序时,退化为冒泡排序,几乎要比较n*n次,故为O(n*n)

举个例子吧

2 2 4 9 3 6 7 1 5 

首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。

2 2 4 9 3 6 7 1 5 首先比较2和5,5比2大,j左移

2 2 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置

2 1 4 9 3 6 7 1 5 比较2和4,4大于2,因此将4移动到后面

2 1 4 9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变

经过第一轮的快速排序,元素变为下面的样子

[1] 2 [4 9 3 6 7 5]

之后,在把2左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果。

代码实现
void   Quick_Sort(int arr[],int start,int end)//对数组中的下标为i - j的元素 进行快速排序
{
	int  temp = arr[start];//temp  表示  记录位
	int i = start;
	int j = end;
	if(start < end)//从两端交替向中间扫描
	{
		while(i < j)
		{
			while(i<j && arr[j] >=temp)
			{
				j--;
			}
			if(i< j)
			{
				arr[i]=arr[j];
				i++;
			}
			while(i<j && arr[i]<temp)
			{
				i++;
			}
			if(i<j)
			{
				arr[j]=arr[i];
				j--;
			}

		}
		arr[i] = temp;
		Quick_Sort(arr,start,i-1);//对左半部分进行递归调用
		Quick_Sort(arr,i+1,end);//对右半部分进行递归调用
	}
}


七、归并排序

基本思路:
把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列

                                        技术分享


如设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11,;

归并排序具体工作原理如下(假设序列共有n个元素):

将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素

将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素

重复步骤2,直到所有元素排序完毕 


八、基数排序

 基本思想
它是一种非比较排序。它是根据位的高低进行排序的,也就是先按个位排序,然后依据十位排序……以此类推。

设有一个初始序列为: R {50, 123, 543, 187, 49, 30, 0, 2, 11, 100}。

我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以0~9来表示的。

所以我们不妨把0~9视为10个桶。

我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是0,将这个数存入编号为0的桶中。

技术分享


分类后,我们在从各个桶中,将这些数按照从编号0到编号9的顺序依次将所有数取出来。

这时,得到的序列就是个位数上呈递增趋势的序列。

按照个位数排序: {50, 30, 0, 100, 11, 2, 123, 543, 187, 49}。

接下来,可以对十位数、百位数也按照这种方法进行排序,最后就能得到排序完成的序列。





















八大排序算法

标签:

原文地址:http://blog.csdn.net/wx_east/article/details/52202970

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!