排序--java实现

java中含有很多排序算法,我在这里只列举出来了几种我们常见的排序算法。

在讲解排序算法之前,需要先声明几个词语:

  1、稳定性:是指有两个相同的值在排序后其先后顺序是否发生了变化,若没有发生变化则是稳定的排序

  2、时间复杂度与空间复杂度:这里对其不进行讲解,请大家自行查询其他博客,明白其计算方法。

一、插入排序

1、直接插入算法(InsertSort):这种排序算法是最简单但也是相比较为复杂的一种排序算法。

  思想:这个排序区间可以划分为待排序区间和已排序区间(本人习惯左边作为已排序区间,右边作为待排序区间),每次选择待排序区间的第一个元素作为待插入元素,有序插入到已排序区间中,最开始未排序区间设置为1,因为默认包含有一个元素的区间是有序的。

  插入过程:

    (1)从已排序区间的最大值开始(若你左边是待排序区间,则是与已排序区间的最小值开始比较,下面亦是反着比较大小),将待插入元素依次与其比较大小

    (2)若待插入元素较小,则将被比较的元素后移一位,待插入元素与其前一位继续比较,重复该过程,直到被比较元素小于待插入元素,将该待插入元素插入此位置。

   实现代码如下:

 1 public static void insertSort(int[] array){
 2         int index = 1;
 3         while(index < array.length){
 4             int tmp = array[index];
 5             int i = index - 1;
 6             for(; i>=0; i--){
 7                 if(array[i] > tmp)
 8                     array[i+1] = array[i];
 9                 else
10                     break;
11             }
12             array[i + 1] = tmp;
13             index++;
14         }
15     }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n) O(n^2) O(n^2)    O(1) 稳定

2、希尔排序(ShellSort):

  思想:是对直接插入排序的一种优化。

  排序过程:根据所给的seq(分组数)来进行分组执行直接插入排序,

  代码实现如下:

 1 public static void shellSort(int[] arr){
 2         int step = arr.length/2;
 3         while(step >= 1){
 4             for(int i = step; i<arr.length; i++){
 5                 int index = i - step;
 6                 while(index >= 0){
 7                     if(arr[index] > arr[index+step]){
 8                         int tmp = arr[index];
 9                         arr[index] = arr[index+step];
10                         arr[index+step] = tmp;
11                         index-=step;
12                     }else
13                         break;
14                 }
15             }
16             step/=2;
17         }
18 
19     }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n) O(n^1.3) O(n^2) O(1) 不稳定

二、选择排序

  思想:同样也分为已排序区间和未排序区间,每次从未排序区间中选择一个最小的值,插入到已排序区间的最后。已排序区间长度的初始值设为0。

  代码实现如下:

 1 public static void selectSort(int[] arr){
 2         for(int i = 0; i < arr.length-1; i++){
 3             for(int j = i;j < arr.length;j++){
 4                 if(arr[j] < arr[i]){
 5                     int tmp = arr[i];
 6                     arr[i] = arr[j];
 7                     arr[j] = tmp;
 8                 }
 9             }
10         }
11     }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n^2) O(n^2) O(n^2) O(1) 不稳定

 

三、堆排序

  思想:对整个区间进行堆排序,升序建立大根堆,降序建立小根堆,每次将堆顶与堆的最后一个元素进行交换,删除堆的最后一个元素后进行堆调整。再重复上述过程,直到堆里只剩下一个元素。

  代码实现过程:

// 创建堆(堆排序)
    private void createHeap(int[] heap) {
        // 堆创建,自下向上进行向下调整
        int index = heap.length / 2 - 1;
        for(int i = index; i >= 0; i--){
            UpToDown(heap,heap.length, i);
        }
    }
// 向下调整
    public static void UpToDown(int[] heap, int size, int index){
        int child = index*2+1;
        while(child < size){
            if(child+1 < size && heap[child+1]>heap[child])
                child+=1;
            if(heap[child] > heap[index]){
                int tmp = heap[index];
                heap[index] = heap[child];
                heap[child] = tmp;
            }
            index = child;
            child = index*2+1;
        }
    }
// 删除堆顶
    public Integer poll(int[] heap){
        if(heap.length == 0)
            return null;
        int result = heap[0];
        heap[0] = heap[heap.length-1];
        UpToDown(heap,heap.length-1,0);
        return result;
    }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n*log(n)) O(n*log(n)) O(n*log(n)) O(1) 不稳定

四、冒泡排序

  思想:在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有 序

  代码实现过程:

 1 public static void BubbleSort(int[] arr){
 2         for(int i = 0; i < arr.length-1; i++){
 3             for(int j = 1; j < arr.length-i; j++){
 4                 if(arr[j-1]> arr[j]){
 5                     int tmp = arr[j-1];
 6                     arr[j-1] = arr[j];
 7                     arr[j] = tmp;
 8                 }
 9             }
10         }
11     }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n) O(n^2) O(n^2) O(1) 稳定

五、快速排序

  思想:

    (1) 从待排序区间选择一个数,作为基准值(pivot);

    (2) Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基 准值大的(可以包含相等的)放到基准值的右边;

    (3)采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序, 或者小区间的长度 == 0,代表没有数

  代码实现过程:

 1 public static void FastSort(int[] arr, int begin, int end){
 2         if(begin >= end)
 3             return;
 4         int left = begin;
 5         int right = end;
 6         while(left < right){
 7             while(left < right && arr[right] >= arr[begin])
 8                 right--;
 9             while(left < right && arr[left] <= arr[begin])
10                 left++;
11             int tmp = arr[left];
12             arr[left] = arr[right];
13             arr[right] = tmp;
14         }
15         int tmp = arr[left];
16         arr[left] = arr[begin];
17         arr[begin] = tmp;
18         FastSort(arr, begin, left-1);
19         FastSort(arr, left+1, end);
20     }
  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n*log(n)) O(n*log(n)) O(n^2) O(log(n)) 不稳定

  优化:

    (1)三数取中法:选取基准值时有可能会每次取到的都是待排序区间的最值,此时快速排序的效率比直接插入效率还低,因此为了避免这类情况发生,每次从待排序区间中选取三个数,取中间的值,这样至少可以保证这个值有一个大于它的值或者小于它的值。

    (2)当递归后的待排序区间的长度较小后,可以采用直接插入排序,降低递归的深度,在区间较小的时候直接插入排序效率相对较高。

    (3)当递归达到一定深度后,但其待排序区间长度仍然较长,可以考虑停止递归,而对此时的待排序区间采用堆排序。

六、归并排序

   思想:是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子 序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

   代码实现如下:

 1 private static void merge(int[] array, int low, int mid, int high) {
 2     int i = low;
 3     int j = mid;
 4     int length = high - low;
 5     int[] extra = new int[length];
 6     int k = 0;
 7     
 8     // 选择小的放入 extra
 9     while (i < mid && j < high) {
10         // 加入等于,保证稳定性
11         if (array[i] <= array[j]) {
12             extra[k++] = array[i++];
13        } else {
14             extra[k++] = array[j++];
15        }
16    }
17     
18     // 将属于元素放入 extra
19     while (i < mid) {
20    extra[k++] = array[i++];
21    }
22     
23     while (j < high) {
24    extra[k++] = array[j++];
25    }
26     
27     // 从 extra 搬移回 array
28     for (int t = 0; t < length; t++) {
29         // 需要搬移回原位置,从 low 开始
30         array[low + t] = extra[t];
31    }
32 }
33 
34 public static void mergeSort(int[] array) {
35     mergeSortInternal(array, 0, array.length);
36 }
37 // 待排序区间为 [low, high)
38 private static void mergeSortInternal(int[] array, int low, int high) {
39     if (low >= high - 1) {
40         return;
41    }
42     
43     int mid = (low + high) / 2;
44     mergeSortInternal(array, low, mid);
45     mergeSortInternal(array, mid, high);
46     
47     merge(array, low, mid, high);
48 }

 

 

  最好 平均 最坏 空间复杂度 稳定性
时间复杂度 O(n*log(n)) O(n*log(n)) O(n*log(n)) O(n) 不稳定

注:若有不对的地方,多谢各位大佬指正。

posted @ 2021-03-26 10:50  一帆小白  阅读(93)  评论(0编辑  收藏  举报