插入,希尔,快速排序

来源:互联网 发布:知乎 女孩子聊天 编辑:程序博客网 时间:2024/05/21 06:51
预备知识:基于比较的排序本质就是将序列中所有的逆序消除.一个排序好的序列是没有逆序的.    定理:N个互异数的数组的平均逆序数是N(N-1)/4.通过交换相邻元素进行排序的任何算法平均时间复杂度为N^2.(因为每次交换只减少一个逆序,而初始的平均逆序数是N(N-1)/4==>时间复杂度为N^2)1)插入排序 ,冒泡排序,选择排序==>交换相邻元素的方法//下面只贴出插入排序程序//两种实现一样.第一种容易理解,但是花去了更多的时间.第二种是对第一种的优化.void InsertionSort(ElementType A[], int N){int j, P;ElementType Tmp;for(P = 1; P < N; P ++ ){for( j = P; j > 0; j -- ){if( A[ j - 1 ] > A[ j ] ){Tmp = A[ j ];A[ j ] = A[ j - 1 ];A[ j - 1 ] = Tmp;}}}}void InsertionSort(ElementType A[], int N){int j,P;ElementType Tmp;for( P = 1; P < N; P ++ ){Tmp = A[ P ];for( j = P; j > 0 && A[ j - 1 ] > Tmp; j -- )A[ j ] = A[ j - 1 ];A[ j ] = Tmp;}}2)希尔排序原理:通过比较相距一定间隔的元素来工作;隔趟比较所用的距离随着算法的进行而减少,直到只比较相邻元素的最后一趟排序为止.由于这个原因,希尔排序也叫缩小增量排序.Shell建议的序列是:H = [N/2];实践中最好的序列之一是{1,5,19,109 .....}也就是 4^i - 3*2^i + 1.通过将这些值放到数组中可以很容易实现该算法.//增量为H=N/2void Shellsort(ElementType A[], int N ){int i, j, Increment;ElementType Tmp;for( Increment = N / 2; Increment > 0; Increment /= 2 ){for( i = Increment; i < N; i ++ ){for( j = i; j >= Increment; j -= Increment ){if( A[ j ] < A[ j - Increment ] ){Tmp = A[ j ];A[ j ] = A[ j - Increment ];A[ j - Increment ] = Tmp;}else break;}}}}3)快速排序原理:随机的(一般用三数中值分割法)选取枢纽元,集合中其余元素分成两个更小的集合.大于枢纽元的放到一个集合,小于枢纽元的放到另一个集合.然后递归地将两个子集合排序.对于很小的数组(N<=20)快速排序不如插入排序好.因为快速排序是递归的,所以这种情况免不了要发生.通常解决的方法是对于小的数组不递归地使用快速排序,而是用插入排序.void Swap( ElementType *Left, ElementType *Right ){ElementType Tmp = *Left;*Left = *Right;*Right = Tmp;}//三数中值分割法获取枢纽//例如:1 3 6 4 2,它的左边元素是1,右边是2,中间元素是6.所以中值自然是2.//ElementType Median3( ElementType A[] ,int Left, int Right ){int Center = (Left + Right ) / 2;if(A[ Left ] > A[ Center ])Swap(&A[Left],&A[Center]);if(A[Left] > A[Right])Swap(&A[Left],&A[Right]);if(A[Center] > A[Right])Swap(&A[Center],&A[Right]);//1 3 2 4 6Swap(&A[Center],&A[Right - 1]);//将枢纽元存放到A[Right - 1]的位置,方便快速排序的元素的分割. 1 3 4 2 6return A[Right - 1];//返回枢纽元 2}#define Cutoff (20)void Qsort( ElementType A[], int Left, int Right ){int i,j;ElementType Pivot;if( Left + Cutoff <= Right )//限定使用快速递归排序的元素个数不小于Cutoff,否则使用插入排序.{Pivot = Median3(A,Left,Right);i = Left; j = Right - 1;for(;;)//分割实现:将所有小于枢纽元的元素移动到数组左边,所有大元素移动到数组的右边.{//分割停止时,i指向一个大元素,j指向一个小元素.while(A[++i] < Pivot){}//i遇到>=Pivot的元素时,跳出循环,准备交换while(A[--j] > Pivot){}//j遇到<=Pivot的元素时,跳出循环,准备交换if( i < j)Swap(&A[i],&A[j]);elsebreak;}Swap(&A[i],&A[Right - 1]);//分割的最后一步是将枢纽元与i所指向的元素交换.Qsort(A,Left,i - 1);//对分割好的子集合进行快速递归排序Qsort(A,i + 1, Right );}else  //使用插入排序InsertionSort(A + Left, Right - Left + 1);}

原创粉丝点击