java 简单排序算法

冒泡排序

原理:从第一个数开始,进行相邻两数比较,可将大的值排到最后
 ①、相邻两个数进行比较,共为N-1轮
 ②、每轮比较之后,会把大的移到后面
 ③、.当没有数据交换的时候,说明已经是有序的,此时可退出循环

/**
 * @author stormxz
 */
public class SortTest {

    /**
     * @param arr
     * 冒泡排序
     * 相邻2组,进行比较,大的往右放。
     */
    public void doBubbleSort(int[] arr) {
       //由于最后一个数不需要比较,此时需N - 1次轮
        for (int i = 0; i < arr.length - 1; i++) {
            boolean flag = true; //如果没有位置能交换了,说明已经结束了
            //每轮进行N - 1次比较,满足条件后,交换两两值
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = false;
                }
            }
            if (flag) {   //如果为true,说明此时已经是有序的,退出循环
                break;
            }
        }
        showArry(arr);
    }

运行结果:
int[] ages = new int[]{8,3,5,4,9,6,1,7,2};
第一轮: 3 5 4 8 6 1 7 2 9
第二轮: 3 4 5 6 1 7 2 8 9
第三轮: 3 4 5 1 6 2 7 8 9
第四轮: 3 4 1 5 2 6 7 8 9
第五轮: 3 1 4 2 5 6 7 8 9
第六轮: 1 3 2 4 5 6 7 8 9
第七轮: 1 2 3 4 5 6 7 8 9

时间复杂度:
假设参与比较的数组元素个数为 N,则第一轮排序有 N-1 次比较,第二轮有 N-2 次,如此类推,这种序列的求和公式为:
  (N-1)+(N-2)+…+1 = N*(N-1)/2
2个极限:当不需要排序时,只需要一轮就可完毕O(n);当为逆序的时候,则需要O(n^2)
从概率学上讲,不需要排序的概率很低,当有一半数据需要排序,N*(N-1)/4。
当N 很大时,时间复杂度为O(n^2)

选择排序

原理:从i位置开始,往后找出比i位置i的值还小的数,将此处的值与i位置的值替换
 ①、从待排序序列中,找到关键字最小的元素
 ②、如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换
 ③、从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束

    /**
     * @param arr
     * 选择排序
     * 找到未排序数组中最小的数据,然后替换到最前面
     * 寻找下标
     */
    public void doSelectionSort(int[] arr) {
        //进行N - 1 轮
        for (int i = 0; i < arr.length - 1; i++) {
           int min = i;//每轮默认最小的为第一个位置
           //每轮进行的次数,找出最小值的下标
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) {
                    min = j;
                }
            }
            //将最小值和第一个值交换位置
            if (i != min) {
                int temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
            }
            showArry(arr);
        }
    }                

运行结果:
int[] ages = new int[]{8,3,5,4,9,6,1,7,2};
第一轮: 1 3 5 4 9 6 8 7 2
第二轮: 1 2 5 4 9 6 8 7 3
第三轮: 1 2 3 4 9 6 8 7 5
第四轮: 1 2 3 4 9 6 8 7 5
第五轮: 1 2 3 4 5 6 8 7 9
第六轮: 1 2 3 4 5 6 8 7 9
第七轮: 1 2 3 4 5 6 7 8 9
第八轮: 1 2 3 4 5 6 7 8 9
时间复杂度:
选择排序和冒泡排序执行了相同次数的比较:N*(N-1)/2,但是至多只进行了N次交换。但由于选择排序数值替换的次数比冒泡排序少很多,从性能上是优于冒泡排序。

插入排序

原理:每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。
插入排序还分为直接插入排序、二分插入排序、链表插入排序、希尔排序等等,这里我们只是以直接插入排序讲解

    /**
     * @param arr
     * 插入排序, 直接插入排序
     * 从i的位置向前比较,此时i之前的位置已经是有序的
     */
    public void insertion(int[] arr) {
        int j = 0;
        //第一个数本身为有序的,从第二个开始进行N-1轮
        for (int i = 1; i < arr.length; i++) {
            int temp = arr[i]; //记录当前用于比较的值

            j = i; //从j开始向前循环
            while(j > 0 && temp < arr[j -1]) {
                arr[j] = arr[j -1]; //将大的值,向后移一位
                j--;//将j的值往前移一位
            }
            arr[j] = temp;  //在最终位置进行添加值
        }
        showArry(arr);
    }

    //数组打印
    private void showArry(int[] arr) {
        for (int i : arr) {
            System.out.print(" " + i);
        }
        System.out.println(" ");
    }
}

运行结果:
int[] ages = new int[]{8,3,5,4,9,6,1,7,2};
第一轮:3 8 5 4 9 6 1 7 2
第二轮: 3 5 8 4 9 6 1 7 2
第三轮: 3 4 5 8 9 6 1 7 2
第四轮: 3 4 5 8 9 6 1 7 2
第五轮: 3 4 5 6 8 9 1 7 2
第六轮: 1 3 4 5 6 8 9 7 2
第七轮: 1 3 4 5 6 7 8 9 2
第八轮: 1 2 3 4 5 6 7 8 9
时间复杂度:
在第一轮排序中,它最多比较一次,第二轮最多比较两次,一次类推,第N轮,最多比较N-1次。因此有 1+2+3+…+N-1 = N*(N-1)/2。
当全部为逆序的时候,此时速度是很慢的,每一步都需要交换数据;当有一半数据需要排序,N*(N-1)/4。
当N趋向无穷大时,此时时间复杂度为O(n^2)。
排除特殊情况,总体性能是优于选择排序和冒泡排序的。

总结

上面讲的三种排序,冒泡、选择、插入用大 O 表示法都需要 O(n^2) 时间级别。一般不会选择冒泡排序,虽然冒泡排序书写是最简单的,但是平均性能是没有选择排序和插入排序好的。
选择排序把交换次数降低到最低,但是比较次数还是挺大的。当数据量小,并且交换数据相对于比较数据更加耗时的情况下,可以应用选择排序。
在大多数情况下,假设数据量比较小或基本有序时,插入排序是三种算法中最好的选择。

冒泡排序:比较,交换次数多 场景:很少使用
选择排序:比较次数多,交换次数较少 场景:数据量少
插入排序:比较次数多,交换次数较少 场景:数据量少,基本有序

猜你喜欢

转载自blog.csdn.net/weixin_39158738/article/details/80858378