package com.algorithm; import java.util.Random; /** * 八种常见排序算法:插入、冒泡、选择、希尔、归并、快排、堆排序、基数排序 * @author Wennian * */ public class Sort { public static void main(String[] args) { // TODO Auto-generated method stub // 构建初始化乱序数组,采用随机数的方式,生成整数(正数、0、负数) int N = 100; int[] arr = new int[N]; for(int i=0;i<N;i++){ // 随机生成0-N-1的数,其中1/10的数为负数 arr[i] = new Random().nextInt(N) - N/10; } Sort sort = new Sort(); //sort.BubbleSort(arr); //sort.InserSort(arr); //sort.SelectSort(arr); //sort.SheelSort(arr); //sort.QuickSort(arr); //sort.mergeSort(arr); sort.heapSort(arr); for(int i=0;i<N;i++){ System.out.print(arr[i]+" "); if(i%10 == 0 && i>0){ System.out.println(); } } } /** * 冒泡排序:一组数,每次把最大的数往后沉 * 时间复杂度:o(n^2) 空间复杂度:o(1) * 稳定 */ void BubbleSort(int[] arr){ int len = arr.length; int end = len-1; // 初始时,结束位置为数组末尾 int start = 0; // 每次从第一个元素开始往后遍历 // 一共需要len趟才能排序完成 for(int i=0;i<len;i++){ start = 0; while(start < end){ if(arr[start]>arr[start+1]){ arr[start] ^= arr[start+1]; arr[start+1] ^= arr[start]; arr[start] ^= arr[start+1]; } start++; } end--; //每趟排序之后,待排数组长度减1 } } /** * 插入排序:认为前面的数组已经有序,每次向原来的数组中插入一个数 * 时间复杂度o(n^2) 空间复杂度o(1) * 稳定 * @param arr */ void InserSort(int[] arr){ int len = arr.length; int end = 0; // 已经排序好的数组 int start = end+1; // 下一个要插入的元素 while(start<=len-1){ for(int i = end;i>=0;i--){ if(arr[i+1]<arr[i]){ arr[i+1] ^= arr[i]; arr[i] ^= arr[i+1]; arr[i+1] ^= arr[i]; }else{ break; } } end = start; start++; } } /** * 选择排序:有序区和无序区,有序区的元素小于无序区,每次选择无需去的最小元素放在有序区后面 * 时间复杂度o(n^2) 空间复杂度o(1) * 稳定 */ void SelectSort(int[] arr){ int len = arr.length; int start = 0; // 无序区的第一个元素,认为他是最小值 while(start < len){ for(int i=start+1;i<len;i++){ if(arr[start]>arr[i]){ arr[start] ^= arr[i]; arr[i] ^= arr[start]; arr[start] ^= arr[i]; } } start++; } } /** * 希尔排序:缩小增量排序,每次缩小增量gap,间隔gap的数为一个子序列, * 依次缩小增量,直到gap=1,对每个子序列采用直接选择排序 * 时间复杂度o(nlogn)~o(n^2) 空间复杂度 o(1) * 不稳定 */ void SheelSort(int[] arr){ int len = arr.length; // gap选择为奇数,gap的选择直接影响排序的效率 // 若选择偶数,gap=4会重复gap=8的排序比较,时间浪费 for(int gap=len/2+1;gap>0;gap/=2){ //对子序列进行直接选择排序,一共有gap个子序列 for(int subarr=0;subarr<gap;subarr++){ int start = subarr; // 直接选择排序 while(start<len){ for(int i=start+gap;i<len;i+=gap){ if(arr[start]>arr[i]){ arr[start] ^= arr[i]; arr[i] ^= arr[start]; arr[start] ^= arr[i]; } } start +=gap; } } } } /** * 快序排序:每次找到一个分割值,满足:左边<=分割值<=右边,重复此过程直到有序 * 时间复杂度o(nlogn) 空间复杂度o(1) * 不稳定 * @param arr */ void QuickSort(int[] arr){ int len =arr.length; int left = 0 ; int right = len-1; quickSort(arr,left,right); } void quickSort(int[] arr ,int left,int right){ if(left < right){ int split = arr[left]; int index1 = left, index2 = right; while(index1<index2){ while(arr[index2]>=split && index1<index2){ index2--; } if(index1<index2) arr[index1++] = arr[index2]; while(arr[index1]<=split && index1<index2){ index1++; } if(index1<index2) arr[index2--] = arr[index1]; } arr[index1] = split; // 递归调用 quickSort(arr,left,index1); quickSort(arr,index1+1,right); } } /** * 归并排序:将数组分为子数组,认为每一个子数组已经有序,对两个有序数组进行归并 * 时间复杂度o(nlogn) 空间复杂度o(n) * 稳定 */ void mergeSort(int[] arr){ int len = arr.length; if(len<=0) return; divideArray(arr,0,len-1); } void divideArray(int[] arr,int left,int right){ if(left < right){ int mid = left + (right - left)/2; // 分解 divideArray(arr,left,mid); divideArray(arr,mid+1,right); // 合并 mergeArray(arr,left,mid,right); } } void mergeArray(int[] arr,int left,int mid,int right){ // 合并两个有序子数组arr[left..mid] arr[mid+1..right] int i=left,m=mid,j=mid+1,n=right; int[] tmp = new int[right-left+1]; int k=0; while(i<=m && j<=n){ if(arr[i]<=arr[j]) tmp[k++] = arr[i++]; else tmp[k++] = arr[j++]; } while(i<=m) tmp[k++] = arr[i++]; while(j<=n) tmp[k++] = arr[j++]; // copy tmp to arr for(int t=0;t<k;t++) arr[left+t] = tmp[t]; } /** * 堆排序:大根堆,每次取堆顶元素,将堆顶元素与最后一个值交换,然后调整堆依次 * 整个过程相当于一个不断建堆的过程 * 时间复杂度o(nlogn) 空间复杂度o(1) * 不稳定 */ void heapSort(int[] arr){ // 将初始数组看做已经建好的堆,调整堆 // parent:i child:2i+1 2i+2 // 从第一个非叶子节点往上调整 int len = arr.length; int last = len-1; while(last >= 0){ // 调整堆,将最大值放在堆顶,即第一个元素 for(int p=(last-1)/2;p>=0;p--){ int cur = p; // 只有第一次需要建立堆,其他时候只要从根节点开始调整堆即可 if(last != len-1){ cur = 0; p = 0; } while(cur <= (last-1)/2){ int child = 2*cur+1; if(child<last-1 && arr[child] < arr[child+1]) child += 1; if(arr[cur] < arr[child]){ arr[cur] ^= arr[child]; arr[child] ^= arr[cur]; arr[cur] ^= arr[child]; } cur = child; } } // 交换堆顶元素和最后一个元素 if(arr[0] != arr[last]){ arr[last] ^= arr[0]; arr[0] ^= arr[last]; arr[last] ^= arr[0]; } last--; } } }