八大排序算法----java实现

一.冒泡排序

算法原理:

给定一个数组,从小到大排序

  1. 数组头部开始比较相邻的两个元素,如果头部的元素比后面的大,就交换两个元素的位置。
  2. 往后对每个相邻的元素都做这样的比较、交换操作,这样到数尾部时,第 1 个元素会成为最小的元素。
  3. 重新从头部开始第 1、2 步的操作,除了在这之前头部已经排好的元素。
  4. 继续对越来越少的数据进行比较、交换操作,直到没有可比较的数据为止,排序完成。
代码实现:
package BubbleSort;

/**
 * 冒泡排序
 */

public class BubbleSort {

    public static int[] bullueSort(int[] array) {
        if (array.length == 0) {
            return array;
        }
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array.length - 1; j++) {
                if (array[j + 1] < array[j]) {
                    int temp = array[j + 1];
                    array[j + 1] = array[j];
                    array[j] = temp;
                }

            }

        }
        return array;

    }

    public static void main(String[] args) {
        int [] arr = {0,41,5,5,866,47};
        int [] sorted = bullueSort(arr);
        for (int i:sorted
             ) {
            System.out.print(i+" ");
        }

    }
}

二.选择排序

算法原理:
  1. 在未排序的数组中找到最大(小)元素,存放到排序序列的起始位置
  2. 在剩余的序列中继续寻找最大(小)元素存放到已排序的序列末尾
  3. 重复上述步骤,直到所有的元素都排序完成,即可得到从大(小 )到小(大)的序列
代码实现:
package SelectionSort;

/**
 * 选择排序
 */

public class selectionSort {
    public static int[] selectionSort(int[]array){
        if(array.length == 0){
            return array;
        }
        for(int i=0;i<array.length;i++){
            int minIndex = i;
            for(int j=i;j<array.length;j++){
                if(array[j]<array[minIndex]){//寻找最小的数
                    minIndex = j;//保存最小值的角标
                }
                /**
                 * 交换最小值与无序序列的第一位
                 */

                int temp =array[minIndex];
                array[minIndex] = array[i];
                array[i] = temp;
            }
        }

        return array;
    }


    public static void main(String[] args) {
        int [] arr = {0,41,45,5,45,47};
        int [] sorted = selectionSort(arr);
        System.out.println("选择排序如下:");
        for (int i:sorted
        ) {
            System.out.print(i+" ");
        }
    }
}

三.插入排序

算法原理:
  1. 从第一个元素开始,该元素被认为是已排序元素
  2. 取出下一个元素,在已排序的元素序列中从后向前进行扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一个位置
  4. 重复步骤三,直到找到已排序元素小于或等于新元素的位置
  5. 将新元素插入到找到的元素后边
  6. 重复上述2-5步骤
代码实现:
package InsertionSort;
/**
 * 插入排序

 */
public class InsertionSort {

    public static int[] insertionSort(int[] array){
        if(array.length == 0){
            return array;
        }
        int current;
        for (int i =0;i<array.length-1;i++){
            current =array[i+1];
            int preIndex =i;
            while (preIndex>=0&&current<array[preIndex]){//保证preIndex>0,确保数组不会越界
                array[preIndex+1] =array[preIndex];
                preIndex--; //向前寻找小于等于当前元素的值
            }
            array[preIndex+1]= current;
        }
        return array;
    }


    public static void main(String[] args) {
        int [] arr = {0,41,45,5,45,47};
        int [] sorted = insertionSort(arr);
        System.out.println("插入排序如下:");
        for (int i:sorted
        ) {
            System.out.print(i+" ");
        }
    }
}

四.希尔排序

算法原理:

算法背景:希尔排序是Donald Shell 于1959年提出的一种排序算法。希尔排序也是一种插入排序,所以想要掌握希尔排序,首先要了解插入排序,请会上文排序算法三。希尔排序是简单插入排序经过改进后的一个更加高效的版本,也称为缩小增量排序。其是时间效率是突破O(N**2)的第一批算法之一。
·
希尔排序把数据序列按照一定的增量进行分组,对每组使用直接插入排序算法;随着增量逐渐减少,每组包含的关键词原来越少,当增量减到1️⃣的时候,整个序列就会被分成一组,进行插入排序,算法便终止了

  1. 选择典型的希尔增量将原来的序列划分为若干个增量序列(关于选择怎样的增量进行划分涉及到算法的性能,所以其选择和证明是一个较为复杂的数学难题),在此我们选择{n/=2…1}增量序列
  2. 按照增量序列的个数k,对序列进行k次插入排序
  3. 每次排序,根据对应的增量,将待排序的序列分割成若干个长度为m的子序列,并直接使用插入排序进行排序,仅当增量为1️⃣时,将整个序列看成一个序列进行处理。
算法过程演示:

八大排序算法----java实现_第1张图片

代码实现:
package ShellSort;

/**
 * 希尔排序
 */
public class ShellSort {
    public static int[] shellSort(int[]array){
        if(array.length==0){
//            System.out.println("数组为空");
            return array;
        }
        int len = array.length;
        int temp,gap = len/2;
        while (gap>0){
            for (int i = gap; i <len ; i++) {
                temp = array[i];
                int preIndex =i-gap;
                while (preIndex>=0&&array[preIndex]>temp){//分组交换,(插入排序)
                    array[preIndex+gap]=array[preIndex];
                    preIndex -= gap;

                }
                array[preIndex+gap] = temp;
            }
            gap/=2;//缩小步长,继续跳入第一层while 循环
        }



        return array;
    }
    public static void main(String[] args) {
        int [] arr = {465,56,4,4,5,334,7,7,165};
        int [] sorted = shellSort(arr);
        System.out.println("希尔排序如下:");
        for (int i:sorted
        ) {
            System.out.print(i+" ");
        }
    }
}

五.归并排序

算法原理:

算法背景:和选择排序一样,归并排序的性能不受输入数据的影响,但是其时间性能的表现比选择排序好的多,始终为O(nlog n)但是其代价是需要额外的内存空间
·
归并排序是采用分治法的一个非常典型的应用,归并排序是一种稳定的排序算法,将已经有序的序列进行合并,得到完全有序的序列。
·
因为较难理解 ,此处整一个讲得很好的B站视频链接:归并排序

  1. 把长度为n的输入序列分为两个长度为n/2的子序列
  2. 对这两个子序列进行分别的归并排序
  3. 将两个排序好的子序列合并成一个最终的排序序列(其实是把递归的过程交给了计算机)
代码实现:
package MergeSort;

import java.util.Arrays;

/**
 * 归并排序
 */
public class MergeSort {

    public static int[] mergeSort(int[]array){

        if(array.length<2){
            return array;
        }
        int mid = array.length/2;
        int []left = Arrays.copyOfRange(array,0,mid);
        int []right = Arrays.copyOfRange(array,mid,array.length);
        return merge(mergeSort(left),mergeSort(right));



    }
    /**
     *
     * 归并排序--将 两段排序好的数组合成一个排序数组
     *
     */
    public static int[]merge(int[]left,int[]right){
        int[] result = new int[left.length+right.length];//新建一个可以容纳左右数组的新数组
        //两个自列的归并过程
        for (int index = 0,i=0,j=0;index<result.length;index++){
            if(i>=left.length){
                result[index]=right[j++];

            }else if(j>=right.length){
                result[index] = left[i++];

            }else if(left[i]>right[j]){
                result[index]=right[j++];
            }else {
                result[index]=left[i++];
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int [] arr = {465,56,4,4,5,334,7,7,165};
        int [] sorted = mergeSort(arr);
        System.out.println("归并排序如下:");
        for (int i:sorted
        ) {
            System.out.print(i+" ");
        }
    }
}

六.快速排序

算法原理:

算法背景:快速排序通过一趟排序将序列分割成独立的两部分,其中一部分均比关键字小,一部分均比关键字大,然后对分割出来的两部分继续进行快速排序的递归调用,以达到使整个序列有序的目的

  1. 从数列中挑选一个元素,将其称为‘基准’,为方便实现,我们总将最左端的元素设置为基准
  2. 重新排序数列,将所有的比基准值大的放在基准数的后边,比基准数小的放在基准数的前边(相同的数可以放在任意边),在这个分区操作退出后,基准数就交换到分区结束的位置
  3. 递归地把分区之后大于和小于基准数的子序列进行排序
代码实现:
package QuickSort;

/**
 * 快速排序方法
 */
public class QuickSort {

    public static void quickSort(int[] array, int left, int right) {
        //如果左边的索引大于右边的索引,出现错误,直接退出该排序方法
        if (left > right) {
            return;
        }
        //确定基准数,以最左开始
        int base = array[left];
        int i = left;
        int j = right;
        while (i != j) {
            while (array[j] >= base && i < j) {
                j--;
            }
            while (array[i] <= base && i < j) {
                i++;
            }
            
            //代码走到这里意味着在基准条件下找到了符合条件的元素,交换他们
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;

        }
        //i=j此时索引走到一起,交换基准数和相遇位置元素
        array[left] = array[i];
        array[i] = base;
        //一趟快排后继续排左边
        quickSort(array, left, j - 1);
        quickSort(array, j + 1, right);

    }


    public static void main(String[] args) {
        int[] arr = { 0, 41, 45, 5, 45, 47};
        quickSort(arr, 0, arr.length - 1);
        for (int i : arr
        ) {
            System.out.print(i + " ");
        }

    }

}

七.堆排序

算法原理:

堆排序是指利用堆这种数据结构所设计的排序算法。堆是一个近似于完全二叉树的结构,同时满足其自身子节点键值或索引总是小于或大于其父节点
此处墙裂推荐B站良心up视频:传送门

  1. 逐个构建大顶堆
  2. 对构建的大顶堆的父节点进行遍历,以此来得到根节点最大的堆
  3. 交换最后一个元素和根节点,此时相当于拿到了取走最大值后的序列的最大值
代码实现:
//代码注释很详细,有助于理解
package HeapSort;

/**
 * 堆排序
 */
public class HeapSort {


    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    private static void heapify(int[] tree, int n, int i) {
        if (i >= n) {//如果根节点大于节点的个数,直接跳出,结束递归
            return;
        }
        int c1 = 2 * i + 1; //当前选定根节点的左子节点
        int c2 = 2 * i + 2; //当前选定根节点的右子节点
        int max = i; //假定当前根节点是该子堆的最大值
//         * 找出子堆中的最大值,交换index
        if (c1 < n && tree[c1] > tree[max]) {
            max = c1; //如果左子节点大于根节点元素,交换其下标
        }
        if (c2 < n && tree[c2] > tree[max]) {
            max = c2; //如果右子节点大于子堆中最大值,交换下标
        }
        if (max != i) {//如果最大值不是根节点,交换找到的最大值和根节点元素
            swap(tree, max, i);//交换函数
            heapify(tree, n, max); //递归做heapify,此时如果在主函数中 进行调用只对指定根节点的子堆进行heapifY操作
        }
    }

    /**
     * 对任意数组建立大顶堆
     *
     * @param tree
     * @param n
     */

    private static void build_heap(int[] tree, int n) {
        int last_node = n - 1;//找出完全二叉树的最后一个节点
        int parent = (last_node - 1) / 2;//找出最后一个节点的父节点
        for (int i = parent; i >= 0; i--) {//对树中的所有父节点进行遍历并heapify来得到根节点最大的堆
            heapify(tree, n, i);
        }

    }


    private static void heap_sort(int[] tree, int n) {
        build_heap(tree, n);//把数组建立成一个大顶堆
        int i;
        for (i = n - 1; i >= 0; i--) {
            swap(tree, i, 0);//遍历节点交换最后一个元素和堆最顶端根节点元素
            heapify(tree, i, 0);//交换完成后相当于拿走交换的根节点(最大)再进行heapify操作
        }
    }

    public static void main(String[] args) {
        int[] arr = {4, 5, 8, 2, 10, 2};

        heap_sort(arr, arr.length);//heapsort操作后遍历,就相当于从小到大遍历数组
        for (int i : arr) {
            System.out.println(i);
        }

    }

}

八.计数排序

算法原理:
  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
  3. 对所有的计数累加(从C的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组,将每个元素i放在新数组的第C(i)项,放一个就减去1
代码实现:
package CountingSort;

import java.util.Arrays;

public class CountSort {
    public static int[] CountingSort(int[] array) {
        if (array.length == 0) {
            return array;
        }
        int bias, min = array[0], max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {//找出未排序数组中最大的数
                max = array[i];
            }
            if (array[i] < min) {//找出未排序数组中最小的数
                min = array[i];
            }
        }
        bias = 0 - min;  //确定位差
        int[] bucket = new int[max - min + 1]; //申请一个最大值与最小值范围个数的新数组
        Arrays.fill(bucket, 0);//初始化数组,使用Arrays 将初始值0全部复制,省略了繁琐的for循环
        for (int i = 0; i < array.length; i++) {
            bucket[array[i] + bias]++;   //将对应的数据加上位差后在新数组上对应后计数,并将计数结果保存在新数组中
        }
        int index = 0, i = 0;//初始化数组的索引
        while(index<array.length){
            if(bucket[i] != 0){
                array[index] = i - bias;  //将新数组的下标加上位差后重新填充到待排序数组
                bucket[i]--; //每取出一个将该位置上的计数减一
                index++; //待排序数组的下表索引加一
            }else{
                i++; //如果将新数组i索引上的计数清零,就将新数组下标i索引+1
            }
        }
        return array;//返回重新填充的待排序数组 ,此时该数组已经有序

    }
    public static void main(String[] args) {
        int [] arr = {2,4,8,5,3};
        int [] sorted = CountingSort(arr);
        for (int i:sorted
        ) {
            System.out.print(i+" ");
        }

    }

}

总结

八大排序算法----java实现_第2张图片

github地址请见:Yuhan 's blog

你可能感兴趣的:(数据结构和算法,数据结构,排序算法)