【算法】Java实现七种常用排序算法

分类


  • 插入排序
    • 直接插入排序
    • 希尔排序
  • 交换排序
    • 冒泡排序
    • 快速排序
  • 选择排序
    • 直接选择排序
    • 堆排序
  • 归并排序
    • 归并
    • 归并排序

插入排序


直接插入排序

将待排序数组看作是左右两部分,左边为无序区,右边为有序区。排序过程就是将右边无序区中的元素逐个插入到左边有序区中,最后整个数组为有序区。

package test;

import java.util.Arrays;

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.directInsert(array);
        System.out.println(Arrays.toString(array));
    }

    public static void directInsert(int[] array) {
        int length = array.length;
        int i; //当前要排序的元素,初始为第二个元素,默认第一个元素为有序区
        int j; //有序区中要比较的元素,比较大小后移动或插入
        int temp; //保存当前要排序的元素,从而空出一个位置用于移动有序区,再将该元素插入有序区的空位
        for (i = 1; i < length; i++) {
            temp = array[i];
            j = i - 1; //空位左边的第一个元素

            // 降序是找到比他大的元素,升序是找到比他小的元素
            while (j >= 0 && array[j] > temp) {
                array[j + 1] = array[j]; //如果该元素比他大,则将该元素后移,即升序
                j--;
            }
            array[j + 1] = temp; //j+1就是空位
        }
    }
}

希尔排序

将待排序数组划分为若干组,在每组内进行直接插入排序,以使整个序列基本有序,然后再对整个序列进行直接插入排序

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.shell(array);
        System.out.println(Arrays.toString(array));
    }

    public static void shell(int[] array) {
        int length = array.length;
        int i; //本组中要排序的元素
        int j; //本组中空位的前一个元素
        int temp; //保存本组要排序的元素,从而空出一个位置用于移动本组的元素,再将该元素插入本组的空位
        int step; //将数组分为step组,step为相同组的元素的间隔步长

        // 初始分组,最终分为一组
        step = length / 2;

        //step最终为1
        while (step != 0) {
            //对每组进行直接插入排序,i初始化为每组的第二个元素
            for (i = step; i < length; i++) {
                temp = array[i]; //留出空位用于移动有序区
                j = i - step; //j为本组中空位的前一个元素
                while (j >= 0 && array[j] > temp) {
                    array[j + step] = array[j]; //将大于temp的元素后移,即升序
                    j -= step; //向本组的有序区左边移动,j为空位前一个元素
                }
                array[j + step] = temp; //j+step为空位
            }

            //进行再次分组
            step /= 2;
        }
    }
}

交换排序


冒泡排序

从一端开始,逐个比较相邻的两个元素,发现倒序即交换

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.bubble(array);
        System.out.println(Arrays.toString(array));
    }

    public static void bubble(int[] array) {
        int length = array.length;
        int i; //泡的位置,即迭代次数,一共要冒length-1个泡,最后一个不用冒
        int j; //指向当前正在排序的元素,一直指到上一个泡的下面
        int temp; //用于交换位置时腾出空位

        //泡依次冒到右边,即每次都是从无序区选一个最大值冒泡
        for (i = (length - 1); i > 0; i--) {
            for (j = 0; j < i; j++) {
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
}

快速排序

首先选定一个元素作为中间元素,然后将数组中所有元素与该中间元素比较,将比中间元素小的放在数组前面,比中间元素大的放在数组后面,再以中间元素作为分界点,得到左右两部分数组,而中间元素位于正确位置上,不用参与后续排序。

然后再对左右两部分分别进行快速排序,即对得到的两个子数组再采用相同的方式来排序和划分,直到每个子数组仅有一个元素或为空数组为止,此时数组所有元素都有序。

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.quick(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    public static void quick(int[] array, int start, int end) {
        int i; //基准左边的指针,指向正在排序的元素,也指向空位
        int j; //基准右边的指针,指向正在排序的元素,也指向空位
        int temp; //用于保存基准,一般是第一个元素,最后将基准放在中间

        if (start < end) {
            i = start;
            j = end;
            temp = array[i];

            while (i < j) {
                //由于以第一位为基准,空位在左边,则先从右边找到小于基准的元素,放在左边
                while (i < j && array[j] > temp) {
                    j--;
                }
                if (i < j) {
                    array[i] = array[j]; //现在j是空位
                    i++;
                }

                //从左边找到大于基准的元素,然后放在右边的空位
                while (i < j && array[i] < temp) {
                    i++;
                }
                if (i < j) {
                    array[j] = array[i]; //现在i是空位
                    j--;
                }
            }

            //将基准放在空位
            array[i] = temp;

            //划分数组进行递归排序,基准不用进行排序
            quick(array, start, i - 1);
            quick(array, i + 1, end);
        }
    }
}

选择排序


直接选择排序

在每一趟排序中,在待排序数组中选出最小或最大的元素放在其最终的位置上

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.select(array);
        System.out.println(Arrays.toString(array));
    }

    public static void select(int[] array) {
        int length = array.length;
        int i; //将要放置正确元素的位置,一共有length-1个,最后一个是正确的
        int j; //指向正在排序的元素
        int min; //初始化最小值,用于和后面元素比较,找到正确值进行交换位置
        int temp; //交换位置时使用

        for (i = 0; i < length - 1; i++) {
            min = i;
            for (j = i + 1; j < length; j++) {
                if (array[min] > array[j]) {
                    min = j; //当前最小值
                }
            }

            //如果最小值不等于最初值,则将换位置
            if (min != i) {
                temp = array[i];
                array[i] = array[min];
                array[min] = temp;
            }
        }
    }
}

堆排序

堆排序的原理比之前的排序方法更复杂,这里就不多说了,已经有很多资料

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.heap(array);
        System.out.println(Arrays.toString(array));
    }

    public static void heap(int[] array) {
        int length = array.length;
        int temp;
        // 建立初始堆
        for (int i = (length - 1) / 2; i >= 0; i--) {
            sift(array, i, length - 1);
        }
        System.out.println(Arrays.toString(array));
        // 逐步将根结点与末尾元素交换,并调整剩余数组为堆,即每次将最大值放在右边
        for (int i = length - 1; i > 0; i--) {
            temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            sift(array, 0, i - 1);
            System.out.println(Arrays.toString(array));
        }
    }

    // 调整数组中以k为根的子树序列为堆,最大下标为m
    // 假定左右子树都是堆
    private static void sift(int[] array, int k, int m) {
        int i = k; // i表示当前根结点
        int j = 2 * i + 1; // j指向当前根结点的左孩子
        int temp;
        // 保证i不是叶子
        while (j <= m) {
            // 让j指向左右孩子的最大者
            if (j < m && array[j] < array[j + 1]) {
                j += 1;
            }
            // 如果父结点最大,则建堆结束
            if (array[i] >= array[j]) {
                break;
            } else {
                temp = array[i];
                array[i] = array[j]; // 大的孩子结点值上移
                array[j] = temp; // 父结点下沉
                i = j; // i表示新的根结点
                j = 2 * i + 1; // j变为当前根结点的左孩子
            }
        }
    }
}

归并排序


归并

将多个有序表合并成一个有序表

public class Sort {
    public static void main(String[] args) {
        int[] A = {0,1,2,3,4,5};
        int[] B = {2,4,6,8,10,11};
        array = Sort.merge(A, B);
        System.out.println(Arrays.toString(array));
    }

    public static int[] merge(int[] A, int[] B) {
        int aLength = A.length;
        int bLength = B.length;
        int[] C = new int[aLength + bLength];
        int a = 0, b = 0, c = 0;
        // 先按最短长度合并
        while (a < aLength && b < bLength) {
            if (A[a] > B[b]) {
                C[c++] = B[b++];
            } else {
                C[c++] = A[a++];
            }
        }
        // 填入剩余元素
        while (a < aLength) {
            C[c++] = A[a++];
        }
        while (b < bLength) {
            C[c++] = B[b++];
        }
        return C;
    }
}

归并排序

将整个表看成n个有序子表,然后两两归并

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.mergeSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] array, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            mergeSort(array, low, mid);
            mergeSort(array, mid + 1, high);
            merge(array, low, mid, high);
        }
    }

    public static void merge(int[] array, int low, int mid, int high) {
        int[] temp = new int[high - low + 1]; // 子数组的辅助空间
        int i = low; // 左指针
        int j = mid + 1; // 右指针
        int k = 0; // 归并数组指针
        // 先按最小长度归并
        while (i <= mid && j <= high) {
            if (array[i] < array[j]) {
                temp[k++] = array[i++];
            } else {
                temp[k++] = array[j++];
            }
        }
        // 填入剩余元素
        while (i <= mid) {
            temp[k++] = array[i++];
        }
        while (j <= high) {
            temp[k++] = array[j++];
        }
        // 修改原数组
        for (int m = 0; m < temp.length; m++) {
            array[low + m] = temp[m];
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值