七种排序算法

排序方法一般有:
冒泡排序 选择排序 插入排序 快排(快速排序) 希尔排序 归并排序 堆排序
冒泡,插入,归并是稳定的
选择,快排,希尔,堆,不稳定

简单排序推荐冒泡,复杂排序推荐快排


稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的


冒泡排序:

通过嵌套循环,遍历数列所有元素,一次比较两个,判断是否交换大小,最大值沉底或最小值浮顶之后开启下一轮遍历,直至排序完成。

for(int i= 0;i<c.length-1;i++){
  for(int j=0;j<c.length-1-i;j++){
      if(c[j]>c[j+1]){
          int temp = c[j+1];
          c[j+1] = c[j];
          c[j] = temp;
      }
  }
 }

选择排序

在未排序的列中找到最大(小)值,放到最前端或者最后端,再从剩余未排序的列中找到最大(小)值。
只需要交换下标,内部循环完之后,交换最小值和 i值

for(int i= 0;i <c.length-1;i++) {
     int min = i;
     for(int j=i+1;j<c.length;j++){
         if(c[min]>c[j] ) {
             min = j;
         }
     }
     if(i !=min){
         int temp = c[i];
         c[i]= c[min];
         c[min]=temp;
     }
 }

插入排序

将已排序的当做有序序列,下一个未排序的从后往前遍历,插入前面有序序列的合适位置 。temp=i=j,然后j-i位与temp比较。

for(int i=0;i<c.length;i++)
{
    int temp = c[i];     //把第i给位置的值给temp  (拿出来的操作)
    int j;
    for( j= i;j>0&&c[j-1]>temp;j--)  //只能j>0写前面,不然判断会越界
    {
        c[j]=c[j-1];
    }
    c[j]= temp;
}

快排(快速排序)

快排是冒泡的升级版,最好的内排序(在内存中进行的排序过程)

先走左边,左边走通了,再走右边

static void QuickSort(int[] arr,int min,int max ){
    if(min>=max){
        return;
    }
    int left = min;
    int right = max;
    int key = arr[min];

    while(left<right){
        while(left<right && arr[right]>=key ){
            right--;
        }
        arr[left] = arr[right];  //找到小的值,占了key的位置

        while(left<right && arr[left]<=key){
            left++;
        }
        arr[right]=arr[left];   //找到大的值,占了上一个循环找的小于key值得位置

        arr[left] = key;  //key的值,占了上一个循环找到的大的字
        //这两个while 就实现了一次查找,  小  key  大 的排序
    }
    //外圈while 继续查找, 直到右边没有比key大的,左边没有比key小的。 即(left = right)

    QuickSort(arr,min,left-1);  //左迭代,排序key左边的。 
    QuickSort(arr,right+1,max);   //右迭代,排序key右边的。

希尔排序

gap分组:按arr.length /2 分为多组,再组内使用插入排序,

private static void shellSort(int[] arr) {
    //step:步长
    for (int step = arr.length / 2; step > 0; step /= 2) {
        //对一个步长区间进行比较 [step,arr.length)
        for (int i = step; i < arr.length; i++) {
            int value = arr[i];
            int j;

            //对步长区间中具体的元素进行比较
            for (j = i - step; j >= 0 && arr[j] > value; j -= step) {
                //j为左区间的取值,j+step为右区间与左区间的对应值。
                arr[j + step] = arr[j];
            }
            //此时step为一个负数,[j + step]为左区间上的初始交换值
            arr[j + step] = value;
        }
    }
}

归并排序

这个好复杂,还需要与数组等长的辅助空间,


public class Main {

    public static void main(String[] args) {
        int[] arr = {11, 44, 23, 67, 88, 65, 34, 48, 9, 12};
        int[] tmp = new int[arr.length];    //新建一个临时数组存放
        mergeSort(arr, 0, arr.length - 1, tmp);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }

    public static void merge(int[] arr, int low, int mid, int high, int[] tmp) {
        int i = 0;
        int j = low, k = mid + 1;  //左边序列和右边序列起始索引
        while (j <= mid && k <= high) {
            if (arr[j] <= arr[k]) {
                tmp[i++] = arr[j++];
            } else {
                tmp[i++] = arr[k++];
            }
        }
//若左边序列还有剩余,则将其全部拷贝进tmp[]中
        while (j <= mid) {
            tmp[i++] = arr[j++];
        }

        while (k <= high) {
            tmp[i++] = arr[k++];
        }

        for (int t = 0; t < i; t++) {
            arr[low + t] = tmp[t];
        }
    }

    public static void mergeSort(int[] arr, int low, int high, int[] tmp) {
        if (low < high) {
            int mid = (low + high) / 2;
            mergeSort(arr, low, mid, tmp); //对左边序列进行归并排序
            mergeSort(arr, mid + 1, high, tmp);  //对右边序列进行归并排序
            merge(arr, low, mid, high, tmp);    //合并两个有序序列
        }
    }
}


堆排序

靠二叉树来实现的,构建大堆顶,将堆顶与堆尾元素交换,

private static void heapSort(int[] arr) {
        //创建堆
        for (int i = (arr.length - 1) / 2; i >= 0; i--) {
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr, i, arr.length);
        }

        //调整堆结构+交换堆顶元素与末尾元素
        for (int i = arr.length - 1; i > 0; i--) {
            //将堆顶元素与末尾元素进行交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;

            //重新对堆进行调整
            adjustHeap(arr, 0, i);
        }
    }

    /**
     * 调整堆
     * @param arr 待排序列
     * @param parent 父节点
     * @param length 待排序列尾元素索引
     */
    private static void adjustHeap(int[] arr, int parent, int length) {
        //将temp作为父节点
        int temp = arr[parent];
        //左孩子
        int lChild = 2 * parent + 1;

        while (lChild < length) {
            //右孩子
            int rChild = lChild + 1;
            // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
            if (rChild < length && arr[lChild] < arr[rChild]) {
                lChild++;
            }

            // 如果父结点的值已经大于孩子结点的值,则直接结束
            if (temp >= arr[lChild]) {
                break;
            }

            // 把孩子结点的值赋给父结点
            arr[parent] = arr[lChild];

            //选取孩子结点的左孩子结点,继续向下筛选
            parent = lChild;
            lChild = 2 * lChild + 1;
        }
        arr[parent] = temp;
    }
}

posted @ 2021-09-27 19:58  Drac  阅读(291)  评论(0)    收藏  举报