排序总结

来源:互联网 发布:cimatrone11编程 编辑:程序博客网 时间:2024/04/29 20:45

 首先来说说排序的分类。

    1. 插入排序---直接插入排序、折半插入排序、希尔排序;

    2. 交换排序---冒泡排序、快速排序;

    3. 选择排序---直接选择排序、堆排序;

    3. 归并排序;

    4. 分配排序---桶排序、基数排序;

    5. 外部排序。

 

    内部排序和外部排序的概念:在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序;反之,若排序过程中要进行数据的内、外存交换,则称之为外部排序。

    需要注意的是:

    (1)内排序适用于记录个数不很多的小文件;
    (2)外排序则适用于记录个数太多,不能一次将其全部记录放入内存的大文件。

 

直接插入排序

     有一个比喻非常恰当:插入排序与打扑克时整理手上的牌非常类似。摸来的第1张牌无须整理,此后每次从桌上的牌(无序区)中摸最上面的1张并插入左手的牌(有序区)中正确的位置上。为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。

 

[cpp] view plaincopyprint?
  1. //插入排序   
  2. template <typename comparable>  
  3. void insertSort(comparable *array, int length)  
  4. {  
  5.     int i,j;  
  6.     comparable temp;  
  7.     for (i=1;i<length;i++)  
  8.     {  
  9.         temp=array[i];  
  10.         j=i-1;  
  11.   
  12.         while (j>=0&&array[j]>temp)  
  13.         {  
  14.             array[j+1]=array[j];  
  15.             j--;  
  16.         }  
  17.         array[j+1]=temp;  
  18.         //排序一轮打印一次   
  19.         for (int k=0;k<length;k++)  
  20.         {  
  21.             cout<<array[k]<<" ";  
  22.         }  
  23.         cout<<endl;  
  24.     }  
  25. }  

  

    时间复杂度O(n2)空间复杂度O(1),稳定性:插入排序是稳定的,因为具有同一值的元素必然插在具有同一值的前一个元素的后面,即相对次序不变。

    插入排序是一种简单的排序方法,他不仅适用于顺序存储结构(数组),而且适用于链接存储结构,不过在链接存储结构上进行直接插入排序时,不用移动元素的位置,而是修改相应的指针。

 

 

希尔(shell)排序

    希尔排序(Shell Sort)又称为“缩小增量排序”。是1959年由D.L.Shell提出来的。该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

 

[cpp] view plaincopyprint?
  1. //希尔插入排序   
  2. template <typename comparable>  
  3. void shellInsert(comparable *array,int length)  
  4. {  
  5.     int k,j,i;  
  6.     comparable t;  
  7.     k=length/2;  
  8.     while(k>0)  
  9.     {  
  10.         cout<<k<<endl;  
  11.         for(j=k;j<length;j++)  
  12.         {  
  13.             t=array[j];  
  14.             i=j-k;  
  15.             while((i>=0)&&(array[i]>t))  
  16.             {  
  17.                 array[i+k]=array[i];  
  18.                 i=i-k;  
  19.             }  
  20.             array[i+k]=t;  
  21.             //print   
  22.             for (int m=0;m<length;m++)  
  23.             {  
  24.                 cout<<array[m]<<" ";  
  25.             }  
  26.             cout<<endl;  
  27.         }  
  28.         k=k/2;  
  29.     }  
  30. }  

  

    时间复杂度O(n2)空间复杂度O(1),稳定性:希尔排序是不稳定的,大家可以写个例子,数组当中两个数相等,无法保证几轮排序之后两个数的相对位置不变,因此也无法保证稳定性。

    希尔排序在时间性能上优于直接插入排序。原因如下:

    (1) 当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
  (2) 当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
  (3) 在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
    因此,希尔排序在效率上较直接插人排序有较大的改进。

快速排序

 

   快速排序是一种交换排序,采用分治算法,其基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

   快速排序的基本思想如下:

设当前待排序的无序区为R[low..high],利用分治法可将快速排序的基本思想描述为:
①分解:
   
 在R[low..high]中任选一个记录作为基准(Pivot),以此基准将当前无序区划分为左、右两个较小的子区间R[low..pivotpos-1)和R[pivotpos+1..high],并使左边子区间中所有记录的关键字均小于等于基准记录(不妨记为pivot)的关键字pivot.key,右边的子区间中所有记录的关键字均大于等于pivot.key,而基准记录pivot则位于正确的位置(pivotpos)上,它无须参加后续的排序。
  注意:
     划分的关键是要求出基准记录所在的位置pivotpos。划分的结果可以简单地表示为(注意pivot=R[pivotpos]):
     R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
                  其中low≤pivotpos≤high。
②求解:
    
通过递归调用快速排序对左、右子区间R[low..pivotpos-1]和R[pivotpos+1..high]快速排序。
③组合:
   
 因为当"求解"步骤中的两个递归调用结束时,其左、右两个子区间已有序。对快速排序而言,"组合"步骤无须做什么,可看作是空操作。

[cpp] view plaincopyprint?
  1. //快速排序的划分算法   
  2. template <typename comparable>  
  3. int partition(comparable *array, int low, int high)  
  4. {  
  5.     int temp=array[low];  
  6.     int pivotkey = array[low];  
  7.     while(low < high)  
  8.     {  
  9.         while (low < high && array[high] >= pivotkey) --high;  
  10.         array[low] = array[high];  
  11.         while (low < high && array[low] <= pivotkey) ++low;  
  12.         array[high] = array[low];  
  13.     }  
  14.     array[low] = temp;  
  15.     //print   
  16.     for (int m=0;m<10;m++)  
  17.     {  
  18.         cout<<array[m]<<" ";  
  19.     }  
  20.     cout<<endl;  
  21.   
  22.     return low;  
  23. }  
  24.   
  25. //快速排序   
  26. template <typename comparable>  
  27. void quickSort(comparable *array,int low, int high)  
  28. {  
  29.     if (low < high)  
  30.     {  
  31.         comparable piovtloc = partition(array, low, high);  
  32.         quickSort(array, low, piovtloc-1);  
  33.         quickSort(array, piovtloc+1, high);  
  34.     }  
  35. }  

 

    最坏时间复杂度O(n2),最好时间复杂度O(logn),快速排序属于稳定排序。

选择排序

    选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。
    常用的选择排序方法有直接选择排序和堆排序。

直接选择排序

    第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
    这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

[cpp] view plaincopyprint?
  1. //直接选择排序   
  2. template <typename comparable>  
  3. void selectInsert(comparable *array,int length)  
  4. {  
  5.     int j,i,k;  
  6.     comparable temp;  
  7.     for (i=0;i<length;i++)  
  8.     {  
  9.         k=i;  
  10.         for (j=i+1;j<length;j++)  
  11.         {  
  12.             if (array[k]>array[j])  
  13.             {  
  14.                 k=j;  
  15.             }  
  16.         }  
  17.         if (i!=k)  
  18.         {  
  19.             temp = array[i];  
  20.             array[i] = array[k];  
  21.             array[k] = temp;  
  22.         }  
  23.         //print   
  24.         for (int m=0;m<length;m++)  
  25.         {  
  26.             cout<<array[m]<<" ";  
  27.         }  
  28.         cout<<endl;  
  29.     }  
  30. }  

直接选择排序的平均时间复杂度为O(n2),并且是不稳定的。

 

 

排序算法比较

(1)平方阶(O(n2))排序
     一般称为简单排序,例如直接插入、直接选择和冒泡排序;

(2)线性对数阶(O(nlgn))排序

     如快速、堆和归并排序;

(3)O(n1+£)阶排序

     £是介于0和1之间的常数,即0<£<1,如希尔排序;

(4)线性阶(O(n))排序

     如桶、箱和基数排序。

 

 

不同条件下,排序方法的选择

(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
     当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插入,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
     快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
     堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
     若要求排序稳定,则可选用归并排序。

 

 

 

 

原文:http://blog.csdn.net/dodolzg/article/details/6066520

0 0
原创粉丝点击