1.冒泡排序

每次将最小的元素下沉到当前数组的后面,遍历时遇到大的就交换

  1. public class BubbleSort {
  2. public int[] bubbleSort(int[] A, int n) {
  3. // write code here
  4. if (n <=1) {
  5. return A;
  6. }
  7. //冒泡
  8. for (int i= n-1; i> 0; i--) {
  9. for (int j =0 ; j <i;j++ ) {
  10. if (A[j] > A[i]) {
  11. int temp = A[j];
  12. A[j] = A[i];
  13. A[i] = temp;
  14. }
  15. }
  16. }
  17. return A;
  18. }
  19. }

image.gif

2.选择排序

从头到尾,依次选择最小的元素放在前面,遍历时需要记录当前未排序元素的最小元素的下标

  1. public class SelectionSort {
  2. public int[] selectionSort(int[] A, int n) {
  3. //选择排序
  4. int index = 0 ;
  5. for (int i=0; i< n-1; i++) {
  6. for (int j = i+1; j<n; j++ ) {
  7. if (A[index]> A[j]) {
  8. index = j;
  9. }
  10. }
  11. int temp = A[i];
  12. A[i] = A[index];
  13. A[index] = temp;
  14. index = i+1;
  15. }
  16. return A;
  17. }
  18. }

image.gif

3.插入排序

从头到尾遍历每个元素,遍历的元素依次与其前面的元素进行比较,并把比它大的元素依次向后移动

  1. public class InsertionSort {
  2. public int[] insertionSort(int[] A, int n) {
  3. // write code here
  4. //插入排序
  5. for(int i=1,j;i<n;i++){
  6. int temp=A[i];
  7. for(j=i;j>0&&temp<A[j-1];j--){
  8. A[j]=A[j-1];
  9. }
  10. A[j]=temp;
  11. }
  12. return A;
  13. }
  14. }

image.gif

4.归并排序

这里需要分两步,一个是递归的(不断的去拆待排序的元素,直到子待排序的数组只有一个元素停止递归),一个是合并(将相邻两个的有序数组合并为一个更大的有序数组,需要用到一个额外的数组空间)

  1. public class MergeSort {
  2. public int[] mergeSort(int[] A, int n) {
  3. if(A == null || n <2) {
  4. return A;
  5. }
  6. process(A, 0, n-1);
  7. return A;
  8. }
  9. private void process(int[] a, int left, int right) {
  10. if (left == right) {
  11. return ;
  12. }
  13. int mid = (left+right) /2;
  14. process(a, left, mid);
  15. process(a, mid+1, right);
  16. merge(a, left, mid, right);
  17. }
  18. private void merge(int[] arr, int left, int mid, int right) {
  19. int[] help = new int[right - left +1];
  20. int l = left;
  21. int r = mid + 1;
  22. int index = 0;
  23. while (l <= mid && r <= right) {
  24. if (arr[l] <= arr[r]) {
  25. help[index++] = arr[l++];
  26. } else {
  27. help[index++] = arr[r++];
  28. }
  29. }
  30. while (l <=mid) {
  31. help[index++] = arr[l++];
  32. }
  33. while (r <= right) {
  34. help[index++] = arr[r++];
  35. }
  36. for (int i=0; i<help.length ; i++) {
  37. arr[left+i] = help[i];
  38. }
  39. }
  40. }

image.gif

5.快速排序

快速排序的思想就是先随机一个索引random,并将该位置的元素和最后一个元素进行交换,然后用一个下标pi来记录比该元素小的数,从左到右依次遍历,如果遇到比最后一个元素小的,就将pi++并与 pi++所指示的元素进行交换。最后在将最后一个元素换回来(此时pi所对应的的元素值就是最初random出的那个数),然后再对左边和右边分别进行递归

  1. public class QuickSort {
  2. public int[] quickSort(int[] A, int n) {
  3. if (A== null || n <2) {
  4. return A;
  5. }
  6. process(A, 0, n-1);
  7. return A;
  8. }
  9. private void process(int[] arr, int left, int right) {
  10. if (left < right) {
  11. int random = left + (int) (Math.random() * (right - left + 1));
  12. swap(arr, random, right);
  13. int mid = partition(arr, left, right);
  14. process(arr, left, mid - 1);
  15. process(arr, mid + 1, right);
  16. }
  17. }
  18. private int partition(int[] arr, int left, int right) {
  19. int pi = left-1;
  20. int index = left;
  21. while (index <= right) {
  22. if (arr[index] <= arr[right]) {
  23. swap(arr, ++pi, index);
  24. }
  25. index++;
  26. }
  27. return pi;
  28. }
  29. private void swap(int[] arr, int indexA, int indexB) {
  30. int temp = arr[indexA];
  31. arr[indexA] = arr[indexB];
  32. arr[indexB] = temp;
  33. }
  34. }

image.gif

6.堆排序

堆排序的思想就是每次用未排序的元素构建完全二叉树的大根堆,然后将堆顶元素和最后一个元素进行交换,再次对剩下的元素构建大根堆,然后再交换,最后得到排序的结构。核心点就是大根堆的构建和交换

  1. public class HeapSort {
  2. public int[] heapSort(int[] A, int n) {
  3. //构建大根堆
  4. for(int i=(n-1)/2;i>=0;i--){
  5. //依次对每个元素进行下沉
  6. sink(A,i,n-1);
  7. }
  8. int k=n-1;
  9. while(k>0){
  10. //置换出堆顶元素
  11. swap(A,0,k--);
  12. //将新换到堆顶的元素进行下沉
  13. sink(A,0,k);
  14. }
  15. return A;
  16. }
  17. public void sink(int [] arr, int i,int n){
  18. while(2*i+1<=n){
  19. int j=2*i+1;
  20. if(j<n&&arr[j+1]>arr[j]) j++;
  21. if(arr[i]>arr[j]) break;
  22. swap(arr,i,j);
  23. i=j;
  24. }
  25. }
  26. public void swap(int[] arr,int i,int j){
  27. int temp=arr[i];
  28. arr[i]=arr[j];
  29. arr[j]=temp;
  30. }
  31. }

image.gif

7.希尔排序

希尔排序其实是插入排序的变种,希尔排序的步长逐渐递减

  1. public class ShellSort {
  2. public int[] shellSort(int[] A, int n) {
  3. int k=1;
  4. while(3*k<n) k=3*k+1;
  5. while(k>=1){
  6. for(int i=k;i<A.length;i++){
  7. for(int j=i;j>=k;j-=k){
  8. if(A[j]<A[j-k]){
  9. int temp= A[j];
  10. A[j]=A[j-k];
  11. A[j-k]=temp;
  12. }
  13. }
  14. }
  15. k=k/3;
  16. }
  17. return A;
  18. }
  19. }

image.gif

8.计数排序和基数排序

这两种排序算法有其应用的局限性,都是基于分桶的思想
(1)计数排序
适合一段范围内的数据排序,比如有n个数进行排序,先求出最小值,再求出最大值,然后依据最小值和最大值分桶,相同的值在一个桶,最后将桶中的元素依次遍历出来即可

  1. public class CountingSort {
  2. public int[] countingSort(int[] A, int n) {
  3. if(A == null || n <2) {
  4. return A;
  5. }
  6. int min = A[0];
  7. int max = A[0];
  8. for (int i =1 ;i < n; i++) {
  9. if (min > A[i]) {
  10. min = A[i];
  11. }
  12. if (max < A[i]) {
  13. max = A[i];
  14. }
  15. }
  16. int[] countArr = new int[max-min+1];
  17. for (int i=0; i< A.length; i++ ) {
  18. countArr[A[i]-min]++;
  19. }
  20. int index =0 ;
  21. for (int i=0 ; i<countArr.length; i++) {
  22. while (countArr[i]-- >0) {
  23. A[index++] = min+i;
  24. }
  25. }
  26. return A;
  27. }
  28. }

image.gif
(2)基数排序
适合对固定位数的数据进行排序,先对最低位进行排序,然后依次到最高位分别进行排序,如下给2000内的数据排序

  1. public class RadixSort {
  2. public int[] radixSort(int[] A, int n) {
  3. int[][] buckets = new int[10][n];
  4. int base =1;
  5. for (int i=0;i<4; i++) {
  6. int[] count = new int[10];
  7. for (int j=0;j<n;j++) {
  8. int model = A[j]/base%10;
  9. //这里用Count来记录buckets下标为model行的元素的列下表(每个count记录了为当前model的元素个数)
  10. buckets[model][count[model]++] = A[j];
  11. }
  12. int index=0;
  13. for(int j=0;j<10;j++){
  14. for(int k=0;k<count[j];k++){
  15. A[index++]=buckets[j][k];
  16. }
  17. }
  18. base*=10;
  19. }
  20. return A;
  21. }
  22. }

image.gif