本文共 7434 字,大约阅读时间需要 24 分钟。
import java.util.*; public class HeapSort { public int[] heapSort(int[] A, int n) { //Floyd 构堆法 for(int i=n/2-1;i>=0;i--) moveDown(A,i,n-1); for(int i=n-1;i>0;i--){ swap(A,i,0); //堆顶最大的元素交换到最后,倒数第二,倒数第三。。。。。。 moveDown(A,0,i-1); //新堆顶元素沿树下移 } return A; } //主要思想:如果左、右孩子存在,找出其中较大的当成大孩子,将大孩子与父亲交换 public void moveDown(int[] data,int first,int last){ int largest = 2*first+1; //左孩子当大孩子 while(largest<=last){ //左孩子存在则执行循环 if(largest
package snippet;public class MegerSort { public static void mmegerSort(int[] data){ int n=data.length; megerSort(data,0,n-1); } private static void megerSort(int[] data, int first, int last) { if(last-first<2) return; //递归出口,data至少有两个元素 int mid=(last+first)/2; megerSort(data, 0, mid); //data的左半部分归并排序 megerSort(data,mid+1,last); //data的右半部分归并排序 meger(data,first,mid,last); //合并排序过后的左右两部分 } //合并函数,合并的过程中排序 private static void meger(int[] data, int first, int mid, int last) { int[] tmp=new int[last-first+1]; //临时数组,来合并数组 int i=0, m=first, n=mid+1; //通过循环把左右数组中较大元素放入临时数组 while(m<=mid && n<=last){ //左右两数组都有元素 if(data[n]
public class quickSort { public static void quickSort(int[] arr){ if(arr == null){ return; } quickSort(arr, 0, arr.length - 1); } public static void quickSort(int[] arr, int low, int high){ if(arr == null || low >= high){ return; } int index = partitionIt(arr, low, high); quickSort(arr, low, index - 1); quickSort(arr, index + 1, high); } private static int partitionIt(int[] array, int first, int last) { //为什么j加一个1,而i没有加1,是因为下面的循环判断是从--j和++i开始的。 //而基准元素选的array[left]即第一个元素,所以左游标从第二个元素开始比较。 int low = first; int high = last + 1; int temp = array[first];// pivot 为选取的基准元素 while (true) { while (low < last && array[++low] < temp) { } while (high > first && array[--high] > temp) { } if (low >= high) { //左右游标相遇时停止 break; } else { swap(array, low, high); //左右游标未相遇时交换各自所指元素 } } swap(array, first, high);//基准元素和游标相遇时所指元素交换为最后一次交换 return high; //一趟排序完成,返回基准元素位置(注意这里基准元素已经交换位置了) } public static void swap(int[] arr, int a, int b){ int tmp = arr[a]; arr[a] = arr[b]; arr[b] = tmp; } public static void main(String[] args) { int[] arr = { 9, 8, 7, 3, 5, 4, 10, 2, 4 ,5, 20, 21, 0, -1, 40, 23, 25, 39, 35}; quickSort(arr); for(int i : arr) { System.out.println(i); } }}
import java.util.*; public class RadixSort { public int[] radixSort(int[] A, int n) { //1.建十个桶,每个桶高度为n int[][] bound=new int[10][n]; //2.分别按个位、十位、百位、千位将数放入桶再倒出 int m=1; //位数 int a=1; //这个a是为了依次将个位,十位,百位,千位的数作为余数 int[] count=new int[n]; //每个桶内的元素的个数 while(m<=4){ //装桶 for(int p=0;p0) //如果该桶内有元素 for(int p=0;p
适用场景:数据分布氛围小,例如身高、年龄,但是对于均匀分布的整数,不适合
计数排序非常基础,他的主要目的是对整数排序并且会比普通的排序算法性能更好。例如,输入{1, 3, 5, 2, 1, 4}给计数排序,会输出{1, 1, 2, 3, 4, 5}。这个算法由以下步骤组成:
import java.util.*; public class CountingSort { public int[] countingSort(int[] A, int n) { //找最大最小值,建桶 int min = A[0]; int max = A[0]; for(int a : A){ min = Math.min(a,min); max = Math.max(a,max); } int bucketLength = max-min+1; //桶长度 int[] bucket = new int[bucketLength]; //放内容 for(int a : A){ bucket[a-min]++; //某数有几个,相应位置为几,0个则为0 } //倒出内容 int index = 0; for(int i = 0; i < bucketLength; i++){ //主要是为了遍历bucket[i] for(int j = 0; j < bucket[i]; j++){ //0个的不放,有几个的数放几次 A[index++] = i+min; } } return A; } }
import java.util.*; public class SelectionSort { public int[] selectionSort(int[] A, int n) { //依次从A[i]及其之后的数中比较出最小的放在i的位置上 for(int i=0;iA[j]){ mindex=j; } } int tmp=A[mindex]; A[mindex]=A[i]; A[i]=tmp; } return A; }}
import java.util.*; public class BubbleSort { public int[] bubbleSort(int[] A, int n) { if(A==null) return null; for(int i=0;iA[j+1]){ int tmp=A[j]; A[j]=A[j+1]; A[j+1]=tmp; } } } return A; }}
import java.util.*;public class InsertionSort { public int[] insertionSort(int[] A, int n) { int i,j,tmp; //这里很关键 for(i=1;i0&&tmp 0 && tmp
import java.util.*; public class ShellSort { public int[] shellSort(int[] A, int n) { int i,j,k,h,hcnt,tmp; int[] increments=new int[20]; //计算增量,并将其放入增量数组 for(h=1,i=0;h=0;i--){ //第一个i-- 巧妙 h=increments[i]; //h个数组依次 for(hcnt=h;hcnt<2*h;hcnt++){ //每个子数组进行插入排序 for(j=hcnt;j =0 && tmp
M是选择桶的数量, 快速排序根据枢轴的不同空间复杂度不同
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uLIY9VEB-1580433071814)(https://ws4.sinaimg.cn/large/006tNbRwly1fuwjvav55jj30pk0jsdon.jpg)]***时间复杂度记忆- ***
冒泡、选择、直接 排序需要两个for循环,每次只关注一个元素,平均时间复杂度为O(n2)(一遍找元素O(n),一遍找位置O(n)) 快速、归并、希尔、堆基于二分思想,log以2为底,平均时间复杂度为O(nlogn)(一遍找元素O(n),一遍找位置O(logn)) *稳定性记忆-“快希选堆”(快牺牲稳定性)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3LN4Dzr-1580433071816)(https://ws2.sinaimg.cn/large/006tNbRwly1fuwklsdwrcj317u0k0tc2.jpg)]
在构建堆的过程中,因为我们是完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,对于每个非终端结点来说,其实最多进行两次比较和互换操作,因此整个构建堆的时间复杂度为O(n)。
在正式排序时,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的某个结点到根结点的距离为.log2i.+1),并且需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)。
假如用T(n)表示使用归并排序对n个元素构成的数组进行排序而使用的时间,用mergeTime来表示将两个子分组合并起来而花费的时间。那么
T(n) = T(n/2)+T(n/2) + mergetime
而megeTime就是归并两个子数组所耗费的时间,以最大时间来算,最多需要n-1次来比较两个子数组的元素,然后n次移动到临时数组中。那么mergetime就是2n -1 。
因此 T(n) = T(n/2)+ T(n/2) +2n -1 。
在最差的情况下,要把n个元素的数组划分,需要n次比较和n次移动。假设用T(n) 来表示使用快速排序算法来排序n个元素的数组所耗费的时间。那么
T(n) = T(n/2)+ T(n/2) +2n
如此看来,有人可能就想到了,从数学公式上看,归并排序还比快排要少个1呢,是不是要快些?其实,不是这样的,请注意到那几个字"最差的情况下",就是在我每次选择的基准,取决于输入的基准,都是最不理想的基准,恰好要移动最多次才能达到目的。但是这种情况的出现的概率是1/(2^n),非常非常小,而且,这是最普通的快速排序方法,先人提出了很多改进优化的方案,其中一种被很常用的就是采用随机函数来选择基准来避免最坏的情况的发生。