八大排序算法

来源:互联网 发布:淘宝现在改版了吗 编辑:程序博客网 时间:2024/06/01 21:22

排序算法 

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

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

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


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

下面来详细讲讲这些算法


一、冒泡排序

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

关键点:设计交换判断条件,提前结束以排好序的序列循环。 
时间复杂度:  
最好情况下:
正序有序,则只需要比较n次。故,为O(n)  
最坏情况下:  逆序有序,则需要比较(n-1)+(n-2)+……+1,故,为O(n*n)
图形表达:

代码实现:
[html] view plain copy
  1. void  Bubble_Sort(int arr[],int len)//arr为数组名,len为数组长度  
  2. {  
  3.     int i =0 ;  
  4.     int j = 0;  
  5.     for( i=0;i<len-1;i++)  
  6.     {  
  7.        for(j=0;j<(len-1-i);j++)//设置无序与有序序列的分割条件    (len-1-i)  
  8.        {  
  9.           if(arr[j]>arr[j+1])//前者小于后者  
  10.            {  
  11.                int temp=arr[j];//两数交换  
  12.                arr[j]=arr[j+1];  
  13.                arr[j+1]=temp;  
  14.            }   
  15.        }        
  16.    }  
  17. }  


二、插入排序


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

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

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

代码实现:
[html] view plain copy
  1. void Insert_Sort(int arr[],int sz)//sz为数组的长度  
  2. {  
  3.     int i =0 ,j=0;  
  4.     int temp = 0;  
  5.     for(i =1 ;i< sz;i++)  
  6.     {  
  7.         temp =arr[i];//记录下  要插入到序列中的数  
  8.         j = i -1;  
  9.         while(j>=0&& temp<arr[j])//要插入的序列  
  10.         {  
  11.             arr[j+1]= arr[j];  //将序列中的数字向后移上一位 直到插入的数大于序列中的数  
  12.             j--;  
  13.         }  
  14.         arr[j+1] = temp;//将要插入的数插到序列中  
  15.     }     
  16. }  


三、希尔排序


基本思想希尔排序也是一种插入排序方法,实际上是一种分组插入方法。先取定一个小于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)

[html] view plain copy
  1. void Shell_Sort(int arr[],int len)  
  2. {  
  3.     int d = 0 ;  
  4.     int i = 0;  
  5.     int j = 0;  
  6.     int temp = 0;  
  7.     dlen/2;  
  8.     while(d >  0)  
  9.     {  
  10.         for(i = d;i< len ;i++)//各组内的插入排序  
  11.         {  
  12.             temp =arr[i];  
  13.             j =i-d;  
  14.             while(j >= 0 && arr[j] > temp )  
  15.             {  
  16.             arr[j+d] = arr[j];  
  17.             j -=d;  
  18.             }  
  19.             arr[j+d] =temp;  
  20.         }  
  21.         d=d/2;//递减增量  
  22.     }  
  23. }  

 

四、选择排序


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

思路图:


代码实现
[html] view plain copy
  1. void Select_Sort(int arr[],int len)//len为数组长度  
  2. {  
  3.   
  4.     int i = 0;  
  5.     int j = 0;  
  6.     int temp0;  
  7.     for(i =0 ;i< len-1;i++)//判断需要几次排序  
  8.     {  
  9.         int min =i;//min为最小元素的下标  
  10.         for(j =i;j< len;j++)//将无序区的最小的数下标的找出来给min  
  11.         {  
  12.             if(arr[j] <arr[min])  
  13.             {  
  14.                 minj;  
  15.             }  
  16.         }  
  17.         temparr[i];//将下标为min的数放到有序区  
  18.         arr[i]= arr[min];  
  19.         arr[min] = temp;  
  20.     }  
  21. }  


五、堆排序

堆排序(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左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果。

代码实现
[html] view plain copy
  1. void   Quick_Sort(int arr[],int start,int end)//对数组中的下标为i - j的元素 进行快速排序  
  2. {  
  3.     int  temp = arr[start];//temp  表示  记录位  
  4.     int i = start;  
  5.     int j = end;  
  6.     if(start < end)//从两端交替向中间扫描  
  7.     {  
  8.         while(i < j)  
  9.         {  
  10.             while(i<j && arr[j] >=temp)  
  11.             {  
  12.                 j--;  
  13.             }  
  14.             if(i< j)  
  15.             {  
  16.                 arr[i]=arr[j];  
  17.                 i++;  
  18.             }  
  19.             while(i<j && arr[i]<temp)  
  20.             {  
  21.                 i++;  
  22.             }  
  23.             if(i<j)  
  24.             {  
  25.                 arr[j]=arr[i];  
  26.                 j--;  
  27.             }  
  28.   
  29.         }  
  30.         arr[i] = temp;  
  31.         Quick_Sort(arr,start,i-1);//对左半部分进行递归调用  
  32.         Quick_Sort(arr,i+1,end);//对右半部分进行递归调用  
  33.     }  
  34. }  


七、归并排序

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

                                        


如设有数列{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}。

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

0 0
原创粉丝点击