排序算法

一.插入排序

直接插入排序

 /**
     * 直接插入排序 稳定算法
     * 将待排序的数分为两类,一类为有序数列,一类为无序数列,每次从无序数列中去取一个数,
     * 从有序数列尾端开始比较,若当前数比有序数小,将有序数往后移一位,不断重复该操作
     * 直到找到第一个小于等于它的数,然后将带插入数插到该数后面.
     * 时间复杂度为o(n^2) 空间复杂度为o(1)
     *
     * @param datas
     * @param len
     */
    public static void insertSort(int[] datas, int len) {
        for (int i = 1; i < len; i++) {
            int temp = datas[i];
            //j为有序数组的最后一个下标
            int j = i - 1;
            while (j >= 0 && temp < datas[j]) {
                datas[j + 1] = datas[j];
                j--;
            }
            datas[j + 1] = temp;
        }
    }

二分插入排序

 /**
     * 二分插入排序 稳定算法
     * 在直接插入排序的基础上,在有序队列中查找使用二分查找
     * 时间复杂度为o(n^2) 空间复杂度o(n)
     *
     * @param datas
     * @param len
     */
    public static void binarySort(int[] datas, int len) {
        int left = 0, right, mid;
        for (int i = 1; i < len; i++) {
            left = 0;
            right = i - 1;
            int temp = datas[i];
            //二分搜索找出插入元素的位置
            while (left <= right) {
                mid = (left + right) >> 1;
                if (temp < datas[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            }
            //将有序数列该位置后面的值都右移一个位置
            for (int j = i - 1; j >= left; j--) {
                datas[j + 1] = datas[j];
            }
            datas[left] = temp;
        }
    }

shell排序

 /**
     * shell排序 不稳定排序
     * 依据:在直接插入排序中,在待排序基本有序的情况下.时间复杂度为o(n)
     * 将待排序的数分成d = len/2,以d间隔对每一组进行直接插入排序
     * 不断使d = d/2,直到组变为1组
     *
     * @param nums
     * @param len
     */
    public static void shellSort(int[] nums, int len) {
        int d = 1;
        while (d >= 1) {
            for (int i = d; i < len; i++) {
                int temp = nums[i];
                int j = 0;
                for (j = i - d; j >= 0 && temp < nums[j]; j -= d) {
                    nums[j + d] = nums[j];
                }
                nums[j + d] = temp;
            }
            d /= 2;
        }
    }


二.交换排序

交换排序

 /**
     * 交换排序
     * 时间复杂度o(n^2) 空间复杂度o(1)
     *
     * @param nums
     * @param len
     */
    public static void swapSort(int[] nums, int len) {
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                if (nums[i] > nums[j]) {
                    int temp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = temp;
                }
            }
        }
    }


冒泡排序

/**
     * 冒泡排序
     * n个数,总共比较n-1,每一次都是相邻两个数比较大小,大的数放到右边
     * 时间复杂度 o(n^2) 空间复杂度o(1)
     *
     * @param nums
     * @param len
     */
    public static void bubbleSort(int[] nums, int len) {
        for (int i = 0; i < len - 1; i++) {
            for (int j = 0; j < len - i - 1; j++) {
                if (nums[j] > nums[j + 1]) {
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
        }
    }

快速排序

 /**
     * 快速排序  不稳定排序
     * 始终将最左边一个最为排序码,每一趟排序结果是左边的数始终不大于排序码,右边的数始终不小于排序码
     * 然后分别对排序码左边和右边的数进行同样的操作
     * 时间复杂度 o(n*log n)
     *
     * @param nums
     * @param left
     * @param right
     */
    public static void quickSort(int[] nums, int left, int right) {
        int l = left, r = right;
        if (left > right) return;
        int key = nums[left];
        do {
            while (l < r && key < nums[r]) r--;
            if (l < r) nums[l++] = nums[r];
            while (l < r && key > nums[l]) l++;
            if (l < r) nums[r--] = nums[l];
        } while (l != r);
        nums[l] = key;
        quickSort(nums, left, r - 1);
        quickSort(nums, l + 1, right);
    }

归并排序

 /**
     * 归并排序 稳定排序
     * 递归分治思想
     * 时间复杂度 o(n*log n)
     *
     * @param nums
     * @param low
     * @param high
     * @param sort
     */
    public static void merge(int[] nums, int low, int high, int[] sort) {
        if (low >= high) return;
        int m = (low + high) >> 1;
        merge(nums, low, m, sort);
        merge(nums, m + 1, high, sort);
        mergeArray(nums, low, m, high, sort);
    }

    /**
     * 将两个有序的数组合并为一个有序的数组
     *
     * @param nums
     * @param low
     * @param m
     * @param high
     * @param sort
     */
    private static void mergeArray(int[] nums, int low, int m, int high, int[] sort) {
        int len = 0;
        int i = low, j = m + 1;
        while (i <= m && j <= high) {
            if (nums[i] < nums[j]) {
                sort[len++] = nums[i];
                i++;
            } else {
                sort[len++] = nums[j];
                j++;
            }
        }

        if (i <= m) {
            for (int k = i; k <= m; k++) sort[len++] = nums[k];
        } else {
            for (int k = j; k <= high; k++) sort[len++] = nums[k];
        }
        //将合并后的有序数赋值给原数组
        for (int k = 0; k < len; k++) {
            nums[low + k] = sort[k];
        }
    }

三.选择排序


直接选择排序

 /**
     * 选择排序 不稳定排序
     * 在未排序的数中选择一个最小的放在第一个位置,然后在未排序的数中选出一个最小的放在第二个位置,
     * 不断重复,直到未排序的只剩最后一个数
     * 时间复杂度o(n^2) 空间复杂度o(1)
     *
     * @param nums
     * @param len
     */
    public static void selectSort(int[] nums, int len) {
        for (int i = 0; i < len - 1; i++) {
            int min = i;
            for (int j = i + 1; j < len; j++) {
                if (nums[min] > nums[j]) {
                    min = j;
                }
            }
            if (i != min) {
                int temp = nums[i];
                nums[i] = nums[min];
                nums[min] = temp;
            }
        }
    }


堆排序

 /**
     * 堆排序 不稳定排序
     * 从小到大排序利用最大堆,即保证每一个根节点的值都比两个儿子节点的值大
     * 首先是建堆,利用完全二叉树的性质,左儿子节点的索引为父节点索引值的2两倍,
     * 右儿子节点索引值为父节点索引值2倍加1
     * 从完全二叉树最后一个非叶子节点的节点开始堆调整,然后是倒数第二个非叶子节点,
     * 直到根节点,则根节点就是所有值中最大的节点
     * 然后将根节点的值与完全二叉树最后一个节点得值进行交换,继续对前n-1个数进行建堆,
     * 因为除根节点外,其他非叶子节点都满足最大堆的性质,所以只需要根节点进行堆调整
     * 时间复杂度o(n*log n)
     *
     * @param nums
     * @param len
     */
    public static void heapSort(int[] nums, int len) {
        for (int i = len / 2; i > 0; i--) {
            //从len/2节点开始进行堆调整.直到调整根节点
            sift(nums, i, len);
        }
        for (int i = len; i > 1; i--) {
            //将根节点的值与数组最后一个节点的值交换
            int temp = nums[1];
            nums[1] = nums[i];
            nums[i] = temp;
            //待排序的减少最后一个元素,重新对第一个跟节点进行堆调整
            sift(nums, 1, i - 1);
        }
    }

    /**
     * 对子树进行堆调整,使得子树的根节点的值为最大,并且使得每一个有儿子的节点值都比儿子的值大
     * 从根节点开始从上往下调整
     *
     * @param nums
     * @param i
     * @param len
     */
    public static void sift(int[] nums, int i, int len) {
        //左儿子节点的索引
        int j = i * 2;
        //保存子树根节点的值
        int temp = nums[i];
        boolean isFinish = false;
        while (j <= len && !isFinish) {
            //在左右儿子节点存在时找到节点儿子值较大的节点
            if (j < len && nums[j] < nums[j + 1]) j++;
            //子树根节点的值比当前的节点i的儿子节点值最大值要大,则不用继续调整
            if (temp >= nums[j]) {
                isFinish = true;
            } else {
                //将大的节点值换到i节点
                nums[i] = nums[j];
                //继续往下进行调整
                i = j;
                j = 2 * j;
            }
        }
        nums[i] = temp;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值