常用排序算法学习总结

本文转自:http://www.codeceo.com/article/10-sort-algorithm-interview.html#0-tsina-1-10490-397232819ff9a47a7b7e80a40613cfe1

仅用于个人学习记录,侵删!

 

冒泡排序

通过与相邻元素的比较和交换来把小的数交换到最前面。

对5,3,8,6,4这个无序序列进行冒泡排序。

首先从后向前冒泡,4和6比较,把4交换到前面,序列变成5,3,8,4,6。

同理4和8交换,变成5,3,4,8,6   

3和4无需交换。

5和3交换,变成3,5,4,8,6,3。

这样一次冒泡就完了,把最小的数3排到最前面了。

对剩下的序列依次冒泡就会得到一个有序序列。冒泡排序的时间复杂度为O(n^2)。

/**
     * 冒泡排序算法实现
     * @param arr
     */
    public static void bubbleSort(int[] arr){
        System.out.println("排序前:");
        for (int i : arr) {
            System.out.print(i+"  ");
        }
        System.out.println();

        if(arr == null || arr.length == 0){
            return ;
        }
        for(int i = 0; i < arr.length; i++){
            for(int j = arr.length - 1; j > i; j--){
                if(arr[j] < arr[j - 1]){
                    int temp = arr[j - 1];
                    arr[j -1] = arr[j];
                    arr[j] = temp;
                }
            }
        }

        System.out.println("排序后:");
        for (int i : arr) {
            System.out.print(i+"  ");
        }
    }

 

选择排序

选择排序的思想其实和冒泡排序有点类似,都是在一次排序后把最小的元素放到最前面。但是过程不同,冒泡排序是通过相邻的比较和交换。而选择排序是通过对整体的选择。举个栗子,对5,3,8,6,4这个无序序列进行简单选择排序,首先要选择5以外的最小数来和5交换,也就是选择3和5交换,一次排序后就变成了3,5,8,6,4.对剩下的序列一次进行选择和交换,最终就会得到一个有序序列。其实选择排序可以看成冒泡排序的优化,因为其目的相同,只是选择排序只有在确定了最小数的前提下才进行交换,大大减少了交换的次数。选择排序的时间复杂度为O(n^2)

public static void selectSort(int[] arr){
        if(arr == null || arr.length == 0){
            return;
        }
        int minIndex = 0;
        for(int i = 0; i < arr.length-1; i++){
            minIndex = i;
            for(int j = i+1; j<arr.length; j++){
                if(arr[j] < arr[minIndex]){
                    minIndex = j;
                }
            }
            if(minIndex != i){
                swap(arr,i,minIndex);
            }
        }
    }

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

 

插入排序

是通过比较找到合适的位置插入元素来达到排序的目的的。

对5,3,8,6,4这个无序序列进行简单插入排序,首先假设第一个数的位置时正确的

然后3要插到5前面,把5后移一位,变成3,5,8,6,4

然后8不用动,6插在8前面,8后移一位,4插在5前面,从5开始都向后移一位。

注意在插入一个数的时候要保证这个数前面的数已经有序。简单插入排序的时间复杂度也是O(n^2)。

public static void insertSort(int[] arr){
if(arr == null || arr.length == 0){
return;
}
for (int i = 1; i < arr.length; i++) {
int j = i;
int target = arr[i]; //待插入的数

while (j > 0 && target < arr[j-1]){
// swap(arr,j,j-1);
// j--;
arr[j] = arr[j-1];
j--;
}

arr[j] = target;
}
}

 

快速排序

冒泡排序是通过相邻元素的比较和交换把最小的冒泡到最顶端,而快速排序是比较和交换小数和大数,这样一来不仅把小数冒泡到上面同时也把大数沉到下面。

举个栗子:对5,3,8,6,4这个无序序列进行快速排序,思路是右指针找比基准数小的,左指针找比基准数大的,交换之。

5,3,8,6,4 用5作为比较的基准,最终会把5小的移动到5的左边,比5大的移动到5的右边。

5,3,8,6,4 首先设置i,j两个指针分别指向两端,j指针先扫描(思考一下为什么?)4比5小停止。然后i扫描,8比5大停止。交换i,j位置。

5,3,4,6,8 然后j指针再扫描,这时j扫描4时两指针相遇。停止。然后交换4和基准数。

4,3,5,6,8 一次划分后达到了左边比5小,右边比5大的目的。之后对左右子序列递归排序,最终得到有序序列。

上面留下来了一个问题为什么一定要j指针先动呢?首先这也不是绝对的,这取决于基准数的位置,因为在最后两个指针相遇的时候,要交换基准数到相遇的位置。一般选取第一个数作为基准数,那么就是在左边,所以最后相遇的数要和基准数交换,那么相遇的数一定要比基准数小。所以j指针先移动才能先找到比基准数小的数。

快速排序是不稳定的,其时间平均时间复杂度是O(nlgn)。

  public static void quickSort(int[] arr, int left, int right){
        if(left>=right){
            return;
        }
        int pivotPos = partition(arr,left,right);
        quickSort(arr,left,pivotPos-1);
        quickSort(arr,pivotPos+1,right);
    }

    private static int partition(int[] arr, int left, int right) {
        int pivoKey = arr[left];
        int pivoPointer = left;
        while (left<right){
            while (left<right && arr[right] >=pivoKey){//如果有边大于等于基准数就继续,直到找到一个小于基准数的值
                right--;
            }
            while (left<right && arr[left] <= pivoKey){
                left++;
            }
            swap(arr,left,right);
        }
        swap(arr,pivoPointer,left);//最后交换基准数和左右指针相遇的数
        return left;
    }

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

 

转载于:https://www.cnblogs.com/763977251-sg/p/11373235.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值