常用排序总结

插入排序

在从后向前扫描的过程中,需要把已排序元素逐步向后挪位,为最新元素提供插入空间。

Public int[] insertSort(int[] arr){
    int len = arr.length();
    int preIndex;//记录前一个的index
    int current;//记录当前的值
    for(int i=1; i<len; i++){
        preIndex = i-1;
        current = arr[i];
        while(preIndex>=0 && arr[preIndex]>current){
            arr[i] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex+1] = current;
    }
    return arr;
}

空间效率:仅用了一个辅助单元。(就地排序)

时间效率:向有序表中逐个插入记录的操作,进了了n-1趟,每趟操作分为比较关键码和移动记录,而比较的次数和移动记录的次数取决于带排序列按关键码的初试排列。

最好情况下:即待排序列已按照关键码有序,每趟操作只需1次比较,0次移动。  总比较次数=n-1次;总移动次数0次。

最坏情况下:即第n趟操作,插入记录需要同前面的j个记录(包括岗哨)进行j次关键码比较,移动记录的次数为j+1次。   总的比较次数   \sum_{j=2}^{n}j=\frac{1}{2}(n+2)(n-1)   ;  总移动次数   \sum_{j=2}^{n}(j+1)=\frac{1}{2}n(n-1)+2n

直接插入排序的时间复杂度为O(n^{2})。是一个稳定的排序方法。

 

冒泡排序

重复地走访过要排序的数列,一次比较两个元素,如果它们顺序错误就把它们交换过来,走访数列的工作是重复地进行指导没有再需要交换的元素。也就是数列已经排序完成。

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

注意:冒泡排序最多进行n-1趟,提前结束条件为最后一趟没有进行“交换记录”。 

最好情况(关键字在记录序列中顺序有序):只需进行一趟冒泡。比较次数:n-1   移动次数:0

最坏情况(关键字在记录序列中逆序有序):需进行n-1次趟冒泡。 比较次数:\sum_{i=n}^{2}(i-1)=\frac{n(n-1)}{2}   移动次数:3\sum_{i=n}^{2}(i-1)=\frac{3n(n-1)}{2}

 

快速排序

快速排序的核心操作是划分。找一个记录,以它的关键字作为“基准”,凡其关键字小于基准的记录均移动至该记录之前,反之,凡关键字大于基准的记录均移动至该记录之后。之后分别对分割所得两个子序列“递归”进行快速排序。

public int[] quickSort(int[] arr, int left, int right){
    if(right>left){
        int k = partition(arr, left, right);
        quickSort(arr, left, k-1);
        quickSort(arr, k+1, right);
    }
    return arr;
}
public int partition(int[] arr, int left, int right){
    int p = arr[left];
    while(left<right){
        while(left<right && arr[right]>p){
            right--;
        }
        if(left<right){
            arr[left] = arr[right];
        }
        while(left<right && arr[left]<p){
            left++;
        }
        if(left<right){
            arr[right] = arr[left];
        }
    }
    arr[left] = p;
    return left;
}
            

时间复杂度:O(nlogn)是所有同数量级的此类排序方法中最快的一种。

最坏情况:若待排记录的初始状态为按关键字有序时,快速排序将退化为冒泡排序,其时间复杂度为O(n^{2})。

空间复杂度:递归过程中需要用到栈。如果每一趟都将记录均匀地划分为两个子序列,则栈的最大深度为\left \lfloor logn \right \rfloor+1。最坏情况:栈的深度为n

稳定性:不稳定。

 

选择排序

首先在未排序的序列中找到最小(大)元素,存放在排序序列的起始位置,然后,再从剩余未排序的元素中继续寻找最小(大)的元素,放到已排序序列的末尾,以此类推,直到所有的元素全部排列完毕。

public int[] selected(int[] arr){
    int len = arr.length();
    for(int i=0; i<len-1; i++){
        int mixIndex = i;
        for(int j=i+1; j<len; j++){
            if(arr[j]<arr[i]){
                mixIndex = j;
            }
        }
        int temp = arr[i];
        arr[i] = arr[mixIndex];
        arr[mixIndex] = temp;
    }
    return arr;
}

对n个记录进行简单选择排序,所需进行的关键字间的比较次数总计为:\sum_{i=1}^{n-1}(n-i)=\frac{n(n-1)}{2}  移动记录的次数:最小值为0;最大值为3(n-1);

 

归并排序

将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列段间有序。将两个表合并成一个有序表。

public void mergeSort(int[] arr, int[] buffer, int low, int high){
    if(low<high){
        int mid = (low + high)/2;
        mergeSort(arr, buffer, low, mid);
        mergeSort(arr, buffer, mid+1, high);
        merge(arr ,buffer, low, mid, high);
        for(int i = low; i<=high; i++){
            arr[i] = buffer[i];
        }
    }
}
public void merge(int[] arr, int[] buffer, int low, int mid, int high){
    int i = low;
    int j = mid+1;
    int k = low;
    while(i<=mid && j<=high){
        if(arr[i]<arr[j]){
            buffer[k] = arr[i];
            i++;
            k++;
        }else{
            buffer[k] = arr[j];
            j++;
            k++;
        }
    }
    if(i<=mid){
        for(int ii = i; ii<=mid; ii++){
            buffer[k] = arr[ii];
                k++;
        }
    }
    if(j<=high){
        for(int jj=j; jj<=high; jj++){
            buffer[k] = arr[jj];
                k++;
        }
    }
}

需要一个与表等长的辅助元素数组空间,所以空间复杂度为O(n)。

时间复杂度为O(nlogn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值