常见排序算法代码及时间复杂度整理(java)-已测试


public class Sort {
    public Sort() {
        System.out.println("sort constructor");
    }

    public static void main(String[] args) {
        //
        int[] a = {1000, 11, 10, 55, 1, 78, 100, 111, 56, 45, 79, 90, 345};
        //System.out.println(8/3);
        System.out.println("排序之前");
        output(a);
        //insertSort(a);
        //shellSort(a);
        //selectSort(a);
        //heapSort(a);
        //bubbleSort(a);
        //quickSort(a, 0, a.length - 1);
        //mergeSort(a, 0, a.length - 1, new int[a.length]);
        radisSort(a,10);
        System.out.println("排序之后");
        output(a);
    }

    /**
     * 直接插入排序
     *
     * 1. 从第一个元素开始,该元素可以认为已经被排序
     * 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
     * 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
     * 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
     * 5. 将新元素插入到该位置后
     * 6. 重复步骤2~5
     *
     * @param array 待排序数组
     */
    public static void insertSort(int[] array) {
        int i = 1;
        while (i < array.length) {
            int temp = array[i];
            int j;
            for (j = i - 1; j >= 0; j--) {
                if (array[j] > temp) {
                    array[j + 1] = array[j];
                } else {
                    break;
                }
            }
            array[j + 1] = temp;
            i++;
        }
    }

    /**
     * 希尔排序(Wiki官方版)
     *
     * 1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;(注意此算法的gap取值)
     * 2. 按增量序列个数k,对序列进行k 趟排序;
     * 3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。
     *
     * @param array 待排序数组
     */
    public static void shellSort(int[] array) {
        int gap = 1, i, j, len = array.length;
        int temp;
        while (gap < len / 3) {
            // <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...
            gap = gap * 3 + 1;
        }
        for (; gap > 0; gap /= 3) {
            //直接插入排序
            for (i = gap; i < len; i++) {
                temp = array[i];
                //从后向前依次进行比较,若值大于temp,则向后移位
                for (j = i - gap; j >= 0 && array[j] > temp; j -= gap) {
                    array[j + gap] = array[j];
                }
                //找到小于等于temp的位置,插入temp,此处j+gap的原因是for中j-=gap
                array[j + gap] = temp;
            }
        }
    }

    /**
     * 选择排序
     *
     * 1. 从待排序序列中,找到关键字最小的元素;
     * 2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
     * 3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复①、②步,直到排序结束。
     *
     * @param array 待排序数组
     */
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIdx = i;
            for (int j = i + 1; j < array.length; j++) {
                //此处需要注意,array[minIdx]不要写成array[j]
                if (array[j] < array[minIdx]) {
                    minIdx = j;
                }
            }

            if (minIdx != i) {
                int temp = array[minIdx];
                array[minIdx] = array[i];
                array[i] = temp;
            }
        }
    }

    /**
     * 堆排序
     *
     * 1. 先将初始序列K[1..n]建成一个大顶堆, 那么此时第一个元素K1最大, 此堆为初始的无序区.
     * 2. 再将关键字最大的记录K1 (即堆顶, 第一个元素)和无序区的最后一个记录 Kn 交换, 由此得到新的无序区K[1..n−1]和有序区K[n], 且满足K[1..n−1].keys⩽K[n].key
     * 3. 交换K1 和 Kn 后, 堆顶可能违反堆性质, 因此需将K[1..n−1]调整为堆. 然后重复步骤②, 直到无序区只有一个元素时停止.
     *
     * @param arr 待排序数组
     */
    public static void heapSort(int[] arr) {
        //1.构建大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr, i, arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for (int j = arr.length - 1; j > 0; j--) {
            //将堆顶元素与末尾元素进行交换
            swap(arr, 0, j);
            //重新对堆进行调整
            adjustHeap(arr, 0, j);
        }
    }

    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     *
     * @param arr
     * @param i
     * @param length
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        //先取出当前元素i
        int temp = arr[i];
        //从i结点的左子结点开始,也就是2i+1处开始
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            //如果左子结点小于右子结点,k指向右子结点
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;
            }
            //如果子节点大于父节点,将子节点值赋给父节点
            if (arr[k] > temp) {
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        //将temp值放到最终的位置
        arr[i] = temp;
    }

    /**
     * 冒泡排序
     * 第一次次将最大的数冒泡到最后,第二次将第二大的数冒泡到倒数第二个位置,以此类推
     *
     * @param array
     */
    public static void bubbleSort(int[] array) {
        //外层控制冒泡次数
        for (int i = 0; i < array.length - 1; i++) {
            //-i是控制循环完成的数据不再进行比较
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                }
            }
        }
    }

    /**
     * 快速排序
     * 选定一个基准值(一般是第一个元素),两个指针,一个前指针一个后指针
     * 后指针从后向前遍历,遇到第一个小于基准值的位置停下
     * 前指针从前向后遍历,遇到第一个大于基准值的位置停下
     * 交换两个指针上的元素,直到j=i
     *
     * @param array
     * @param left
     * @param right
     */
    public static void quickSort(int[] array, int left, int right) {
        if (left > right) {
            return;
        }
        int temp = array[left];
        int j = right;
        int i = left;
        while (i < j) {
            //顺序很重要,要先从右边开始找

            //当i停下来时,a[i]的值大于基准数或走到了尽头。
            //当i没有走到尽头,也就是说i找到了一个大于基准的数,
            //接着j开始向左走,企图寻找一个小于基准的数,但是存在i < j这个条件的限制,j有可能没找到小于基准的数时就被迫停下来了,此时i==j的位置与基准数交换位置,结果就会出现错误。

            //当然,我们想从左开始并且正确也是可以的
            //需要改基准值为数组最右边:
            while (array[j] >= temp && i < j) {
                j--;
            }
            while (array[i] <= temp && i < j) {
                i++;
            }

            if (i < j) {
                swap(array, i, j);
            }
        }

        //最终将基准数归位
        array[left] = array[i];
        array[i] = temp;
        quickSort(array, left, i - 1);
        quickSort(array, i + 1, right);
    }

    /**
     * 归并排序
     * 将数组分成很小的单元,每个单元排序后,再将这两个单元合成一个有序的序列
     * 递归完成
     *
     * @param array
     * @param left
     * @param right
     * @param temp
     */
    public static void mergeSort(int[] array, int left, int right, int[] temp) {
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(array, left, mid, temp);
            mergeSort(array, mid + 1, right, temp);
            merge(array, left, right, mid, temp);
        }
    }

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

        while (i <= mid) {
            temp[t++] = array[i++];
        }
        while (j <= right) {
            temp[t++] = array[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while (left <= right) {
            array[left++] = temp[t++];
        }
    }

    /**
     * 基数排序
     * 将整数按位数切割成不同的数字,然后按每个位数分别比较
     *
     * @param array
     * @param radix 基数:十进制为10radix = 10;
     */
    public static void radisSort(int[] array, int radix) {
        int[][] bucket = new int[radix][array.length];
        int maxDigit = getMaxDigit(array);
        int divisor = 1;
        int currentDigit = 1;
        while (currentDigit <= maxDigit) {
            // 用来计数:数组counter[i]用来表示该位是i的数的个数
            //因为每个位置上可能有多个数据,因此使用一个数组记录位置上的元素数
            int[] counter = new int[radix];
            // 将array中元素分布填充到bucket中,并进行计数
            for (int i = 0; i < array.length; i++) {
                int which = (array[i] / divisor) % radix;
                bucket[which][counter[which]] = array[i];
                counter[which]++;
            }
            int index = 0;
            // 根据bucket中收集到的array中的元素,根据统计计数,在array中重新排列
            for (int i = 0; i < radix; i++) {
                if (counter[i] != 0) {
                    for (int j = 0; j < counter[i]; j++) {
                        array[index] = bucket[i][j];
                        index++;
                    }
                }
                counter[i] = 0;
            }
            divisor *= radix;
            currentDigit++;
        }

    }

    public static int getMaxDigit(int[] array) {
        int maxNum = getMaxNum(array);

        int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999,
            99999999, 999999999, Integer.MAX_VALUE};
        for (int i = 0; ; i++) {
            if (maxNum <= sizeTable[i]) {
                return i + 1;
            }
        }
    }

    public static int getMaxNum(int[] array) {
        int maxNum = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > maxNum) {
                maxNum = array[i];
            }
        }
        return maxNum;
    }

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

    //输出打印
    public static void output(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + (i == arr.length - 1 ? "" : ","));
        }
        System.out.print("\n");
    }

}

猜你喜欢

转载自blog.csdn.net/u013984781/article/details/100777086