八大排序算法[一]

145 阅读3分钟

这是我参与更文挑战的第 7 天,活动详情查看: 更文挑战

  • Bubble Sort

    冒泡排序是稳定的排序算法(当有相邻的两个元素大小相等的时候,我们不做交换),时间复杂度为O(n2){O(n^2)},原地排序算法(空间复杂度为O(1){O(1)})。思想就是两个数交换顺序,一次排序至少会让一个数移到它应该在的位置,n 次肯定可以了。

    代码实现如下,可以优化的点是记住最后一次交换的位置;还有就是没有交换,提前退出。

    static int[] bubbleSort(int[] items, int length) {
            if (length <= 1){
                return items;
            }
            //最后一次交换的位置,优化
            int lastExchange = 0;
            int sortBorder = length - 1;
            for (int i = 0; i < length; i++) {
                System.out.println(items[i]);
                //提前退出标志位,优化
                boolean flag = false;
    
                for (int j = 0; j < sortBorder; j++) {
                    if (items[j] > items[j+1]){
                        swap(items,j,j+1);
                        flag = true;
                        lastExchange = j;
                    }
                }
                sortBorder = lastExchange;
                if (!flag){  //没有数据交换,提前退出
                    break;
                }
            }
            return items;
        }
        
    static void swap(int[] sortItems,int a,int b){
        int temp = sortItems[a];
       	sortItems[a] = sortItems[b];
        sortItems[b] = temp;
    }
        
    
  • Insection Sort

    插入排序是原地排序算法,对于值相同的元素,我们可以选择将后面出现的元素,插入到前面出现元素的后面,这样就可以保持原有的前后顺序不变,所以插入排序是稳定的排序算法。时间复杂度O(n2){O(n^2)}

    思想就是已排序区间,未排序区间,未排序区间的元素一个个插入到已排序区间的合适位置

    这个算法不想冒泡排序那么简单粗暴(直接两两互换),因为是原地排序算法,有点类似快排的那种数组中某个值赋值给另一个值,最后还要把原先的值再赋值过来,所以写起来需要稍微注意一下,比冒泡难写多了。

        public static void insertionSort(int[] a, int length) {
            if (length == 1) {
                return;
            }
            for (int i = 1; i < length; i++) {
                int value = a[i];
                int j = i - 1;
                for (; j >= 0; j--) {
                    if (a[j] > value){
                        a[j+1] = a[j];
                    } else {
                        break;
                    }
                }
                a[j+1] = value; //最后把 j+1 位置的值赋值为 value
            }
        }
    

    一开始取第一个数是已排序的,然后和第二个数对比,如果第一个数大于第二个数,把第二个数赋值为第一个数,然后退出内层循环,将(j+1)数赋值为第二个数;接下来已排序的是第一个,第二个数,取第三个数进行对比,如果第三个数大于第一、二个数,继续下一次循环,如果小于第二个数,参照前面,直至结束。思路理解了,就很容易写出来。

    如果最后一个值最小,那么最后一次排序时,就是最后一个值要一直从尾部移动到头部。

  • Selection Sort

    选择排序和插入排序挺像的,也是分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。

    选择排序是一种原地排序算法,选择排序每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置,这样破坏了稳定性(因此比冒泡和插入排序稍微逊色)。最好/最坏/平均时间复杂度都为O(n2){O(n^2)}

    具体代码如下:

        public static void selectionSort(int[] items, int length) {
            if (length <= 1) return;
            for (int i = 0; i < length - 1; i++) {
                //查找最小值
                int minIndex = i;
                for (int j = i + 1; j < length; j++) {
                    if (items[j] < items[minIndex]){
                        minIndex = j;
                    }
                }
                //交换
                swap(items,i,minIndex);
            }
        }
    
        private static void swap(int[] items,int i,int j){
            int temp = items[i];
            items[i] = items[j];
            items[j] = temp;
        }