初识基本排序

前言

对于排序,我们早已不陌生,在学习for循环里的冒泡排序正是如此

所谓排序就是将一串数据递减 或 递增的排放在一起

稳定性:一组数据经过排序,这些记录的相对次序保持不变

即r[i] = r[j],在经过排序前后位置保持不变 称作稳定 反之叫做不稳定

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序

在学习排序前要知道排序具体有哪些?

按照顺序一一讲起

直接插入排序

复制代码
public static void insetSort(int[] array) {
    for (int i = 1; i < array.length; i++) {
        int tmp = array[i];
        int j = i-1;
        for (; j >= 0 ; j--) {
            if(array[j] > tmp) {
                array[j+1] = array[j];
            }else {
                array[j+1] = tmp;
                break;
            }
        }
        array[j+1] = tmp;
    }
}

此外 在当 i = 1 时 j = 0 ,j--会数组越界找不到下标,所以下标 0 要单独添加 array [ j + 1] = tmp

时间复杂度:O(N^2) 最坏情况下:逆序的 5 4 3 2 1

时间复杂度:O(n) 最好情况下:本身就是有序的 1 2 3 4 5

如果数据越有序,直接插入排序越快

希尔排序

复制代码
public static void shellSort(int[] array) {
    int gap = array.length;
    while (gap > 1) {
        //gap /= 2;//
        gap = gap/3+1;//
        shell(array,gap);
    }
}

private static void shell(int[] array, int gap) {
    for (int i = gap; i < array.length; i++) {
        int tmp = array[i];
        int j = i-gap;
//这里写成J--;结果不发生改变因为在gap == 1 进行最后一次排序后无论前几次怎样排序在最后会进行统    一排序
        for (; j >= 0 ; j -= gap) {
            if(array[j] > tmp) {
                array[j+gap] = array[j];
            }else {
                array[j+gap] = tmp;
                break;
            }
        }
        array[j+gap] = tmp;
    }
}

注意 :希尔排序是直接排序的进阶版 利用gap加快排序 但是希尔排序是一种不稳定的排序

时间复杂度会在O(n^1.3 - n^1.5 )

直接选择排序

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:不稳定

时间复杂度和 数据 是否有序无关

堆排序

heapsort

复制代码
public  static  void HeapSort(int [] array) {
         createHeap(array);
         int end  = array.length - 1;
         while (end > 0){
             swap(array,0,end);
             siftDown (array,0,end);
             end--;
         }
}

  private static void createHeap(int[] array) {
      for (int parent = (array.length -1-1) / 2;   parent > 0 ; parent--) {
          siftDown(array,parent,array.length);
      }
  }

  private static void siftDown(int[] array, int parent, int length) {
      int child = 2 * parent - 1;
      while (child < length){
          if(child + 1 < length && array[child] <array [child +1]){
              child++;
          }
          if(array[child] > array [parent]){
              swap(array,parent,child);
              parent = child;
              child = 2 * parent + 1;
          }
          else {
              break;
          }
      }
  }

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:不稳定

冒泡排序

复制代码
public  static  void bubbleSort(int [] array){
    for (int i = 0; i < array.length - 1; i++) {
        boolean flg =false;
        for (int j = 0;j < array.length - 1 - i;j++ ){
            if(array[j] > array[j+1]) {
              int tmp = array[j];
              array[j] = array[j + 1];
              array[j + 1] = tmp;
            }
       }
      }
    }
}

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

优化代码 可提升效率

这是冒泡排序常见的优化方法

优化后时间复杂度可达到O(n)

复制代码
public  static  void bubbleSort(int [] array){
    for (int i = 0; i < array.length - 1; i++) {
        boolean flg =false;
        for (int j = 0;j < array.length - 1 - i;j++ ){
            if(array[j] > array[j+1]) {
                flg = true;
                swap(array, j, j + 1);
            }
        }
        if(!flg){
            break;
        }
    }
}

快速排序

复制代码
public static void quickSort(int[] array) {
    quick(array, 0, array.length - 1);
}

private static void quick(int[] array, int start, int end) {
    while (start >= end) {
        return;
    }
    if (end - start <= 10) {
        insertSortRange(array, start, end);
        return;
    }
    int minIndex = getMidNum(array, start, end);
    int pivot = paration2(array, start, end);
    quick(array, start, pivot - 1);
    quick(array, pivot + 1, end);

挖坑法(最常见)

复制代码
private static int paration(int[] array, int left, int right) {
    int par = array[left];
    while (left < right){
        while (left < right && array[left] <= par){
            left ++;
        }
        while (left < right && array[right] >= par){
            right --;
        }
        array[right] =array[left];
    }
    array[left] = par;
    return  left;
}

hoare法

复制代码
int tmp = array[left];
int tmpleft = left;
while (left < right) {
    while (left < right && array[left] <= tmp) {
        left++;
    }
    while (left < right && array[right] >= tmp) {
        right--;
    }
    swap(array, left, right);
}
swap(array,left,tmpleft);
return left;

前后指针

复制代码
private static int paration2(int[] array, int left, int right){
    int prev = left;
    int cur = left+1;
    while(cur <= right){
        //cur无越界  cur值小于prev
        while (cur <= right && array[cur] < array[prev]  ){
            swap(array,cur,prev);
        }
        cur++;
        prev++;
    }
    swap(array,prev,left);
    return  left;
}

可以优化 ---- >减少递归次数

直接插入法

复制代码
private static void insertSortRange(int[] array, int start, int end) {
    for (int i = start + 1; i < end; i++) {
        int tmp = array[i];
        int j = i - 1;
        for (; j > start; j--) {
            if (array[j] > tmp) {
                swap(array, array[j], array[j + 1]);
            } else {
                array[j + 1] = tmp;
                break;
            }
        }
        array[j + 1] = tmp;

    }
}

三数取中法

复制代码
private static int getMidNum(int[] array, int start, int end) {
    int mid = (array.length - 1) / 2;
    if (array[start] < array[end]) {
        if (array[end] < array[mid]) {
            return end;
        } else if (array[mid] < array[start]) {
            return start;
        } else {
            return mid;
        }
    } else {
        if (array[end] > array[mid]) {
            return end;
        } else if (array[mid] > array[start]) {
            return start;
        } else {
            return mid;
        }

    }
}

非递归方法

复制代码
private static int parationNor(int[] array, int left, int right) {
    Deque<Integer> stack = new ArrayDeque<>();
    int povit = paration(array, left, right);
    if (left < povit) {
        stack.push(left);
        stack.push(povit - 1);
    }
    if (right > povit) {
        stack.push(povit + 1);
        stack.push(right);
    }
    while (!stack.isEmpty()) {
        right = stack.pop();
        left = stack.pop();
        povit = paration(array, left, right);
        if (left + 1 < povit) {
            stack.push(left);
            stack.push(povit - 1);
        }
        if (right - 1 > povit) {
            stack.push(povit + 1);
            stack.push(right);
        }
    }
    return left;
}

因此方法选择的不同导致排序的内容皆有细微的差异,但整体的排序保持一致

时间复杂度: 最坏情况:当数据给定的是1 2 3 4 5 6 7.....有序的情况下 确实是O(n^2)

9 8 7 6 5 4 最好情况:O(N*logN)

空间复杂度: 最坏情况:O(N)

最好情况:O(logN)

稳定性: 不稳定性

归并排序

复制代码
public static void mergeSort(int[] array) {
    mergeSortTmp(array,0,array.length-1);
}

private static void mergeSortTmp(int[] array,int left,int right) {
    if(left >= right) {
        return;
    }
    int mid = (left + right) / 2;
    mergeSortTmp(array,left,mid);
    mergeSortTmp(array,mid+1,right);
    //走到这里 全部分解完毕
    // 合并
    merge(array,left,mid,right);
}


//类比合并两个数组
private static void merge(int[] array, int left, int mid, int right) {
    //创立新数组
    int [] tmp = new int[right - left+1];
    int k = 0;
    int s2 = mid + 1;
    int s1 = left;
    while(s1 <= mid && s2 <= right){
        if (array[s1] <=  array[s2]) {
            tmp[k++] = array[s1++];
        }else {
            tmp[k++] = array[s2++];
    }
}
    while(s1 <= mid ) {
            tmp[k++] = array[s1++];
    }
    while(  s2 <= right){
        tmp[k++] = array[s2++];
        }
    for(int i = 0; i < k ; i++) {
        array[i + left] =tmp[i];
    }
}

非递归实现:

将一串数组像成 一个个有序的个体 再到 两个有序 ---> 四个有序 ---> 整个数组有序

所以只要确认 left mid right的位置在调用merge函数即可

复制代码
private static void mergeSortTmpNor(int[] array){
    int gap  =1 ;
    while (gap <= array.length) {
        for (int i = 0; i < array.length; i = i+ gap *2) {
            int left = i;
            int mid = gap + left  - 1;
            int right = gap + mid;
            if(right >= array.length){
                right   =  array.length - 1;
            }
            if (mid >= array.length){
                mid = array.length - 1;
            }
            merge(array,left,mid,right);
        }
        gap *= 2;
    }
}

此外要注意right 和 mid是否越界

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定

以上就是一些基本排序的所要了解的知识

若有错误欢迎指正

相关推荐
岛雨QA1 小时前
多路查找树「Java数据结构与算法学习笔记11」
数据结构·算法
岛雨QA1 小时前
树结构实际应用「Java数据结构与算法学习笔记10」
数据结构·算法
岛雨QA2 小时前
树结构的基础部分「Java数据结构与算法学习笔记9」
数据结构·算法
会编程的土豆2 小时前
2.25 做题
数据结构·c++·算法
Gogo11212 小时前
架构的宿命:深入对比 NestJS (Node.js) 与 Java 的垃圾回收机制
java·node.js
微风起皱2 小时前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
Frostnova丶2 小时前
LeetCode 1356. 根据数字二进制下1的数目排序
数据结构·算法·leetcode
xuxie992 小时前
NEXT 1 进程2
java·开发语言·jvm
岛雨QA2 小时前
哈希表「Java数据结构与算法学习笔记8」
数据结构·算法