Java实现常用的几种排序

目录

一、插入排序

1:直接插入排序

2:折半插入排序

3:希尔排序

二、交换排序

1:冒泡排序

2:快速排序 

三、归并排序

四、堆排序


一、插入排序

1:直接插入排序

         思想:在有序序列中插入元素,有移动法交换法两种实现

         时间复杂度:O(n2)

         稳定性:稳定


    /**
     * 移动法:先找到插入位置,然后向后移动元素
     */
    public static void sort1(int arr[]) {
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] >= arr[i - 1]) continue;
            int j = i;
            int temp = arr[i];
            //找到插入位置
            while (j > 0 && temp < arr[j - 1]) j--;
            //向后移动
            for (int k = i; k > j; k--) arr[k] = arr[k - 1];
            //插入到指定位置
            arr[j] = temp;
        }
    }

    /**
     * 交换法:当前元素和之前元素比较,如果比前面元素小则交换
     */
    public static void sort2(int arr[]) {
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] >= arr[i - 1]) continue;
            int j = i;
            while (j > 0 && arr[j] < arr[j-1]){
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
                j--;
            }
        }
    }

2:折半插入排序

        思想:是对直接插入排序的改进,在寻找插入点时,直接插入排序是和前面有序元素一个一个比较,折半插入排序是使用折半的思路寻找插入点

/**
     * 折半查找插入位置
     *
     * @return
     */
    private static int zbFind(int arr[], int low, int high, int x) {
        int mid = 0;
        //如果有序序列中存在元素x,找到直接返回下标
        while (low <= high) {
            mid = (low + high) / 2;
            if (arr[mid] == x) return mid;
            if (x > arr[mid]) low = mid + 1;
            else high = mid - 1;
        }
        //循环结束如果没有结束,则序列中没有x,此时区间长度为2,mid取小值,比mid值小则返回mid,否则返回mid+1
        if (x < arr[mid]) return mid;
        else return mid + 1;
    }
    
    //找到插入位置后和直接插入排序的思想一致
    private static void sort(int arr[]) {
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] >= arr[i - 1]) continue;
            int temp = arr[i];
            //找到插入位置
            int j = zbFind(arr, 0, i-1, arr[i]);
            //向后移动
            for (int k = i; k > j; k--) arr[k] = arr[k - 1];
            //插入到指定位置
            arr[j] = temp;
        }
    }

       折半排序减少了查找插入位置的次数,移动次数和直接插入排序一样,所以时间复杂度也是O(n2),稳定的排序算法

3:希尔排序

         思想:对序列进行分组,分组之后使用直接插入排序


    private static void sort(int arr[]) {
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                if (arr[i] >= arr[i - gap]) continue;
                int j = i;
                int temp = arr[i];
                //找到插入位置
                while (j - gap >= 0 && temp < arr[j - gap]) j -= gap;
                //向后移动
                for (int k = i - gap; k >= j; k -= gap) {
                    arr[k + gap] = arr[k];
                }
                arr[j] = temp;
            }
        }
    }

       时间复杂度:O(n^(1.3—2))

       稳定性:不稳定

二、交换排序

1:冒泡排序

       思想:相邻两个元素进行比较(j,j + 1),如果arr[j] > arr[j+1]则交换两元素,每次循环从下标0开始,一趟后最大的排到最后,第二趟后次大的排到倒数第二位....

private static void sort(int arr[]) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

      时间复杂度:O(n2)

      稳定性:稳定 

2:快速排序 

       思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分所有数据小,然后再按此方法对这两部分数据分别进行快速排序

private static void sort(int arr[], int low, int high) {
        //递归出口
        if (low >= high) return;
        int i = low;
        int j = high;
        //取区间第一个元素为基点
        int key = arr[low];
        while (i < j) {
            //从后往前找一个比基点小的元素
            while (i < j && arr[j] >= key) j--;
            //从前往后找一个比基点大的元素
            while (i < j && arr[i] <= key) i++;
            //交换
            if (i < j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        arr[low] = arr[i];
        arr[i] = key;

        sort(arr, low, i - 1);
        sort(arr, i + 1, high);

    }

       时间复杂度:O(nlogn)

       稳定性:不稳定

三、归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

第一步:递归拆分子序列

第二步:合并有序序列(期间需要一个临时数组保存数据)

private static void sort(int arr[], int temp[], int left, int right) {
        if (left >= right) return;
        int mid = (left + right) / 2;
        sort(arr, temp, left, mid);
        sort(arr, temp, mid + 1, right);
        merge(arr, temp, left, mid, right);
    }

    private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
        int i = left;
        int j = mid + 1;
        int t = 0;
        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) temp[t++] = arr[i++];
            else temp[t++] = arr[j++];
        }

        while (i <= mid) temp[t++] = arr[i++];

        while (j <= right) temp[t++] = arr[j++];

        t = 0;
        while (left <= right) arr[left++] = temp[t++];

    }

        时间复杂度:O(nlogn)

        稳定性:稳定

四、堆排序

堆本质是一个完全二叉树,分为最大堆(根不小于孩子)和最小堆(根不大于孩子) 

第一步:初始化堆

第二步:将根(第一个元素)和最后一个元素交换,重新调整堆


    /**
     * 推排序
     * @param array
     */
    public static void sort(int[] array) {
        //初始化堆
        for (int i = array.length / 2 - 1; i >= 0; i--) {
            adjustHeap(array, i, array.length);
        }


        // 开始排序
        for (int j = array.length - 1, i = 0; j > 0; j--) {
            // 元素交换
            swap(array, 0, j);
            i++;

            int start = (array.length - i) / 2 - 1;  //最后一个非叶子节点的下标
            int length = array.length - i;           //需要调整序列的长度

            //从最后一个非叶子节点开始调整
            for (int k = start; k >= 0; k--) {
                adjustHeap(array, k, length);
            }

        }


    }

    /**
     * 堆内调整
     * @param array
     * @param i
     * @param length
     */
    public static void adjustHeap(int[] array, int i, int length) {
        int temp = array[i];

        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
            // 得到最大的节点的下标
            if (k + 1 < length && array[k] < array[k + 1]) {
                k++;
            }

            // 如果发现子节点更大,则进行值的交换
            if (array[k] > temp) {
                swap(array, i, k);

                //调整后更新下标,继续判断是否满足堆的条件
                i = k;
            } else {
                break;
            }
        }
    }


    /**
     * 交换数组元素
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

       时间复杂度:O(nlogn)

       稳定性:不稳定

猜你喜欢

转载自blog.csdn.net/qq_34018603/article/details/86919138