当前位置:文档之家› 各大常用排序方法

各大常用排序方法

//1. 希尔排序, 时间复杂度:O(nlogn)~ O(n^2)// 另称:缩小增量排序(Diminishing Increment Sort)void ShellSort(int v[],int n){int gap, i, j, temp;for(gap=n/2; gap>0; gap /= 2) /* 设置排序的步长,步长gap每次减半,直到减到1 */{for(i=gap; i<n; i++) /* 定位到每一个元素 */{for(j=i-gap; (j>=0) && (v[j]>v[j+gap]); j -= gap ) /* 比较相距gap远的两个元素的大小,根据排序方向决定如何调换 */{temp = v[j];v[j] = v[j+gap];v[j+gap] = temp;}}}}//2. 二分插入,void HalfInsertSort(int a[], int len){int i, j, temp;int low, high, mid;for (i=1; i<len; i++){temp = a[i];/* 保存但前元素 */low = 0;high = i-1;while (low <= high) /* 在a[low...high]中折半查找有序插入的位置 */{mid = (low + high) / 2; /* 找到中间元素 */if (a[mid] > temp) /* 如果中间元素比但前元素大,当前元素要插入到中间元素的左侧 */{high = mid-1;}else /* 如果中间元素比当前元素小,但前元素要插入到中间元素的右侧 */{low = mid+1;}} /* 找到当前元素的位置,在low和high之间 */for (j=i-1; j>high; j--)/* 元素后移 */{a[j+1] = a[j];}a[high+1] = temp; /* 插入 */}}//3. 插入排序//3.1 直接插入排序, 时间复杂度:O(n^2)void StraightInsertionSort(int input[],int len){int i, j, temp;for (i=1; i<len; i++){temp = input[i]; /* 操作当前元素,先保存在其它变量中 */for (j=i-1; j>=0 && input[j]>temp; j--) /* 从当前元素的上一个元素开始查找合适的位置 */{input[j+1] = input[j]; /* 一边找一边移动元素 */input[j] = temp;}}}//3.2 带哨兵的直接排序, 时间复杂度:O(n^2)/** 带哨兵的直接插入排序,数组的第一个元素不用于存储有效数据* 将input[0]作为哨兵,可以避免判定input[j]中,数组是否越界* 因为在j--的过程中,当j减小到0时,变成了input[0]与input[0]* 自身进行比较,很明显这个时候说明位置i之前的数字都比input[i]小* 位置i上的数字不需要移动,直接进入下一轮的插入比较。

*/void InsertionSortWithPiquet(int input[],int len){int i, j;for (i=2; i<len; i++) /* 保证数组input第一元素的存储数据无效,从第二个数据开始与它前面的元素比较 */{input[0] = input[i];for (j=i-1; input[j]>input[0]; j--){input[j+1] = input[j];input[j] = input[0]; /* input[j]一直都是排序的元素中最大的那一个 */ }}}//3.3 折半插入排序, 时间复杂度:O(n^2)void BinaryInsertionSort(int input[], int len){int i, j, low, mid, high;for(i=2; i<len; i++){input[0] = input[i]; //将input[i]暂存到input[0]low = 1;high = i-1;while(low < high){ //在input[]中折半查找有序插入的位置mid = (low + high)/2; //折半if(input[i] < input[mid]){ //插入点在低半区high = mid-1;}else{ //插入点在高半区low = mid+1;}}for(j=i-1; j>=high+1; j--){input[j+1] = input[j]; //记录后移}input[high+1] = input[0]; //插入}}//与直接插入排序相比: 减少了关键字间的比较次数//3.4 2-路插入排序//3.5 表插入排序//4. 冒泡排序法, 时间复杂度:O(n^2)void BubbleSort(int a[],int n){int i,j,k;for(j=0;j<n;j++) /* 气泡法要排序n次*/{for(i=0;i<n-j;i++) /* 值比较大的元素沉下去后,只把剩下的元素中的最大值再沉下去就可以啦 */{if(a[i]>a[i+1]) /* 把值比较大的元素沉到底 */{k=a[i];a[i]=a[i+1];a[i+1]=k;}}}}//5. 归并排序//6. 选择排序//6.1 简单选择排序, 时间复杂度:O(n^2)/*算法原理:首先以一个元素为基准,从一个方向开始扫描,* 比如从左至右扫描,以A[0]为基准。

接下来从A[0]...A[9]* 中找出最小的元素,将其与A[0]交换。

然后将基准位置右* 移一位,重复上面的动作,比如,以A[1]为基准,找出* A[1]~A[9]中最小的,将其与A[1]交换。

一直进行到基准位* 置移到数组最后一个元素时排序结束(此时基准左边所有元素* 均递增有序,而基准为最后一个元素,故完成排序)。

*/void SimpleSelectSort(int A[],int len){int i, j, temp;for(i=0; i<len; i++){for(j=i+1; j<=len; j++) /* 从j往前的数据都是排好的,所以从j开始往下找剩下的元素中最小的 */{if(A[i] > A[j]) /* 把剩下元素中最小的那个放到A[i]中 */{temp = A[i];A[i] = A[j];A[j] = temp;}}}}//6.2 树形选择排序,时间复杂度:O(nlogn)//6.3 堆排序,时间复杂度:O(nlogn)/*************************************************************** 堆的定义 n 个元素的序列 {k1,k2,...,kn}当且仅当满足下列关系时,* 称为堆:* ki<=k2i ki<=k2i+1 (i=1,2,...,n/2)* 或* ki>=k2i ki>=k2i+1 (i=1,2,...,n/2)* 堆排序思路:* 建立在树形选择排序基础上;* 将待排序列建成堆(初始堆生成)后,序列的第一个元素(堆顶元素)就一定是序列中的最大元素; * 将其与序列的最后一个元素交换,将序列长度减一;* 再将序列建成堆(堆调整)后,堆顶元素仍是序列中的最大元素,再次将其与序列最后一个元素交换并缩短序列长度;* 反复此过程,直至序列长度为一,所得序列即为排序后结果。

**************************************************************/void HeapAdjust(int data[], int s, int m){int j, rc;rc = data[s];for(j=2*s; j<=m; j*=2){if( j<m && data[j]<data[j+1] ){ //锁定值较大的那个孩子节点的位置j++;}if(rc > data[j]){ //如果父节点已经比值较大的那个孩子节点大,则结束此次循环break;}data[s] = data[j]; //否则将值较大的那个孩子节点赋值给父节点s = j; //锁定值较大的那个孩子节点的位置}data[s] = rc; //将原来父节点的值赋给原来值较大的那个孩子节点}void HeapSort(int data[],int len){int i, temp;for(i=len/2; i>0; i--) //从最后一个非终端节点(n/2)开始循环"筛选",最后建成一个最大堆{HeapAdjust(data, i, len);}for(i=len; i>0; i--){temp = data[1]; //把根节点的值(堆中最大的)放到后面data[1] = data[i];data[i] = temp;HeapAdjust(data, 1, i-1); //在剩下的节点中重新开始恢复最大堆}}//7. 快速排序//7.1 递归形式的快速排序,时间复杂度:O(nlogn)/* 快速排序(quick sort)。

在这种方法中,* n 个元素被分成三段(组):左段left,* 右段right和中段middle。

中段* 仅包含一个元素。

左段中各元素都小于等* 于中段元素,右段中各元素都大于等于中* 段元素。

因此left和right中的元* 素可以独立排序,并且不必对left和* right的排序结果进行合并。

* 使用快速排序方法对a[0:n-1]排序* 从a[0:n-1]中选择一个元素作为middle,* 该元素为支点把余下的元素分割为两段left* 和right,使得left中的元素都小于* 等于支点,而right 中的元素都大于等于支点* 递归地使用快速排序方法对left 进行排序* 递归地使用快速排序方法对right 进行排序* 所得结果为left+middle+right*/void QuickSort(int data[], int low, int high){int mid;if(low < high) {mid = Partition(data, low, high);QuickSort(data, low, mid-1); /* 递归调用 */QuickSort(data, mid+1, high);}}/* 要注意看清楚下面的数据之间是如何替换的,* 首先选一个中间值,就是第一个元素data[low],* 然后从该元素的最右侧开始找到比它小的元素,把* 该元素复制到它中间值原来的位置(data[low]=data[high]),* 然后从该元素的最左侧开始找到比它大的元素,把* 该元素复制到上边刚刚找到的那个元素的位置(data[high]=data[low]),* 最后将这个刚空出来的位置装入中间值(data[low]=data[0]),* 这样一来比mid大的都会跑到mid的右侧,小于mid的会在左侧,* 最后一行,返回的low是中间元素的位置,左右分别递归就可以排好序了。

相关主题