排序算法可以说是算法的入门以及算法学习阶段的基石,排序算法显得那么的基础又是非常重要的一种算法。排序算法常常作为一些高阶算法的数据处理中间过程,在实际的问题处理中被应用的最为广泛,因此算法选讲阶段就从八大排序算法开始。在本节内容中既可以看到一般性的比如插入排序,冒泡排序等基础算法又可以看到比如基数排序,位图排序,快速排序等等比较难理解的算法,算法之门从排序算法说起。
1.插入排序
插入排序算法的原理很简单,默认A中有一部分数据已经排好序了,后续只要从没有排好序的序列里面每拿出一个数字就在排好序的序列中从右向左依次寻找合适的位置进行放置就可以了插入排序伪代码 :A.length-1代表数列A的长度,时间复杂度 O(n^2) 使用场景:当所需要排序的数值规模比较小时使用该方法比较好
for j=1 to A.lengrh-1
key = a[j]
insert a[j] into the sorted sequence A[0,j-1]
i= j-1
while i>=0 and a[i] > key
a[i+1] = a[i]
i = i-1
a[i+1] = key
template <typename T> T INSERTION_SORT(T * A ,int& length) { if(NULL == A || length <=0) { printf("输入错误 "); return -1; } int i_tmp = 0; int j_tmp = 0; T key = 0;
for(j_tmp=1;j_tmp<length;j_tmp++) { key = A[j_tmp]; i_tmp = j_tmp-1; while((i_tmp >=0) && (A[i_tmp] > key)) { A[i_tmp+1] = A[i_tmp]; i_tmp -= 1; } A[i_tmp+1] = key; } return 0; }
2.分治排序
分治排序的策略就是分而治之,总体上是一种递归的思想,分治排序的时间复杂度为o(nlogn)。分治排序算法将原问题的规模逐步的通过分解缩小为若干个和原问题类似的子问题,当子问题的规模小到一定程度(可以直接求解时)递归的分解过程就结束了。将子问题的解组合之后就能得到原问题的解,这就是分治算法的核心思想。一般来说分治排序要经过下面的三个步骤:
2.1.分解:将原问题分解成规模比较小的子问题。
2.2.求解:对于每个子问题进行求解。
2.3.组合:将所有子问题的解组合为原问题的解。
下面是两种基于递归的分治策略,第一种利用哨兵位来代替数组判空的操作,但是正如下面所说,当集合数据元素量级很大时选择哨兵元素会变得很困难,因此又给出了一种不用哨兵元素的排序策略。
1 /**********************************分治排序****************************************/ 2 //分治排序是一个属于递归类型的算法,分治的思想在每一个模式里面都需要经过一下三个步骤 3 //分解:将原问题分解成若干个类似的规模较小的子问题 4 //解决:递归的解决每一个子问题,如果子问题规模足够小就直接求解。 5 //合并:合并子问题的解构成原问题的解 6 //分治排序中需要将规模较小的两个已经排序的数据集合并因此需要一种合并的算法MERGE,这 7 //里使用一种特殊的方式将两个结果集尾部元素增加一个位置设置为结束符防止多次对于数据集 8 //为空的判断A代表原数据集A[p,q]和A[q+1,r]代表两个已经排好序的数据集。 9 template <typename T> 10 void MERGE(T * A,int p,int q,int r) 11 { 12 int len1 = q-p+1; 13 int len2 = r-q; 14 15 T *L = (T *)malloc(sizeof(T)*(len1+1)); 16 T *R = (T *)malloc(sizeof(T)*(len2+1));; 17 int i = 0; 18 int j = 0; 19 int k = 0; 20 21 for(i=0;i<len1;i++) 22 { 23 L[i] = A[p+i-1]; 24 } 25 for(j=0;j<len2;j++) 26 { 27 R[j] = A[q+j]; 28 } 29 L[len1] = MAX_NUM; 30 R[len2] = MAX_NUM; 31 i=0; 32 j=0; 33 34 for(k=p-1;k<r;k++) 35 { 36 if(L[i] <= R[j]) 37 { 38 A[k] = L[i]; 39 i++; 40 } 41 else 42 { 43 A[k] = R[j]; 44 j++; 45 } 46 } 47 free(L); 48 free(R); 49 L = NULL; 50 R = NULL; 51 } 52 53 //根据算法导论去掉哨兵位置重写分治算法,这是很有必要的当数据集的量级非常巨大的时候很显然寻找好的哨兵位置是非常困难的 54 template <typename T> 55 void RE_MERGE(T * A,int p,int q,int r) 56 { 57 int len1 = q-p+1; 58 int len2 = r-q; 59 60 T *L = (T *)malloc(sizeof(T)*(len1)); 61 T *R = (T *)malloc(sizeof(T)*(len2));; 62 int i = 0; 63 int j = 0; 64 int k = 0; 65 66 for(i=0;i<len1;i++) 67 { 68 L[i] = A[p+i-1]; 69 } 70 for(j=0;j<len2;j++) 71 { 72 R[j] = A[q+j]; 73 } 74 i=0; 75 j=0; 76 77 for(k=p-1;k<r;k++) 78 { 79 if((len1 == i) || (len2 == j)) 80 { 81 82 break; 83 } 84 if(L[i] <= R[j]) 85 { 86 A[k] = L[i]; 87 i++; 88 } 89 else 90 { 91 A[k] = R[j]; 92 j++; 93 } 94 } 95 while(i < len1) 96 { 97 A[k] = L[i]; 98 i++; 99 k++; 100 } 101 102 while(j < len2) 103 { 104 A[k] = R[j]; 105 j++; 106 k++; 107 } 108 free(L); 109 free(R); 110 L = NULL; 111 R = NULL; 112 } 113 114 template <typename T> 115 int MERGE_SORT(T * A , int p,int r) 116 { 117 if(NULL == A || r<= 0 ) 118 { 119 return -1; 120 } 121 if(p < r) 122 { 123 int q = (p + r)/2; 124 MERGE_SORT(A,p,q); 125 MERGE_SORT(A,q+1,r); 126 RE_MERGE(A,p,q,r); 127 } 128 return 0; 129 }
3.冒泡排序
冒泡排序的思想很简单,就是每次比较相邻两个元素的数据值将小的元素放置到数组的头部,将较大的元素放置到数组尾部。因为这个过程小的元素一直从数据集里面上升到数据集头部很想气泡冒出水面因此称为冒泡排序。对于数量级为n的元素集合,冒泡排序需要进行n-1次排列每一次都需要执行n此判断所以时间复杂度为0(n*n),需要有一个临时空间做数据交换区因此空间复杂度为O(1)。
#include "stdafx.h" #include <stdio.h> #include <malloc.h> #include <math.h> template <typename T> void swap(T & x , T & y) { T temp = x; x = y; y = temp; } template <typename T> int POP_SORT(T * A , int & len) { if(NULL == A || len <= 0) { return -1; } int i = 0; int j = 0; for(i=0;i<len-1;i++) { for(j=i+1;j<len;j++) { if(A[i] > A[j]) { swap<T>(A[i],A[j]); } } } return 0; } int _tmain(int argc, _TCHAR* argv[]) { int A[10] = {5,2,4,6,1,3,9,8,10,7}; int num[2] = {0}; int i_tmp = 0; int result = 0; int Alen = sizeof(A) /sizeof(A[0]); printf("排序前的数组为:"); for(i_tmp=0;i_tmp<Alen;i_tmp++) { printf("%d ",A[i_tmp]); } printf(" "); /*************************************************/ printf("冒泡排序后的数组为:"); result = POP_SORT<int>(A,Alen); if(0 == result) { for(i_tmp=0;i_tmp<Alen;i_tmp++) { printf("%d ",A[i_tmp]); } } else { printf("f冒泡执行失败-排序过程发生错误 "); } printf(" "); /*************************************************/ return 0; }
上面所讲的那些排序都是基于比较的排序算法,元素之间必须经历相互比较的过程才能完成排序,下面的算法不再进行元素之间的比较只是通过元素之间的运算就能达到排序目的。
未完待续......