面试之排序算法(持续更新)

本文根据个人需要,相对排序算法进行学习。
且主要分为两部分:
常用排序算法实现(快速、二分查找、计数排序)
多种算法比较
————————————————————————————————————
1、快速排序
主要思想:选取一个关键数据(隔板),依次遍历数据,如果数据比隔板大,则放到隔板后面,如果比隔板小,则放到隔板前面。这样一趟排序就可以把隔板元素的最终位置确定下来,然后依次递归确定其他元素位置。
快速排序关键的地方在于隔板函数partition的实现,它可以确定隔板元素的最终位置并返回最终下标。
这里有两种实现方法
第一种:剑指offer中

public int partition(int data[],int start,int end){
    if(data==null||data.length<1||start<0||end>data.length-1)
        return -1;
    //small为每次递归开始的下标前一个位置,这样只有有满足小于隔板值才会移动
    int small=start-1;
    //i<=end也没用 只会增加一次循环,因为不满足data[end]<data[end]
    for(int i=start;i<end;i++){
    //不能等于 只能小于 因为small代表小于其值的最右下标,否则 直接跨过 出现data[end]左边值为等于和小于data[end],多余的计算比较
    //如果中间有>=隔板元素data[end]的值,则small不会++,除非后面有<data[end]的元素,然后small++,并交换>=和小于data[end]值交换,此时small值仍是最右小于隔板元素的下标。
        if(data[i]<data[end]){
            ++small;
            if(i!=small){
                swap(data,i,small);
            }
        }
    }
    //small的值为最右边小于隔板值得下标,所以small+1就是隔板元素的最终下标
    ++small;
    swap(data,small,end);
    return small;
}

第二种:最简单常见的

public int partition(int data[],int start,int end){
    if(data==null||data.length<1||start<0||end>data.length-1)
        return -1;
    int l=start;
    int h=end;
    int povit=data[start];
    while(l<h){
        while(data[h]>=povit&&l<h)
            h--;
        if(l<h){
            swap(data,l,h);
            l++;
        }
        while(data[l]<=povit&&l<h)
            l++;
            if(l<h){
                swap(data,l,h);
                h--;
            }
    }
    return l;   
}

快速排序

public void quickSort(int data[],int start,int end){
    //递归结束条件
    if(start==end)
        return;
    int index=partition(data,start,end);
    if(index>start)
        quickSort(data,start,index-1);
    if(index<end)
        quickSort(data,index+1,end);
}

2、二分查找

public class BinarySearch {
    public static int binarySearch(int data[],int des){
        if(data==null||data.length<1)
            return -1;
        int l=0;
        int h=data.length-1;
        //<=包含等于是可能有这种情况 小标为3和4 mid=3,但是3<key(4),l++=h 这个时候如果不能等于则会丢失可能找不到
        while(l<=h){
            int mid=(l+h)/2;
            if(data[mid]==des)
                return mid;
            else if(data[mid]>des)
                h=mid-1;
            else
                l=mid+1;
        }
        return -1;
    }

3、计数排序
一般适用于输入数组值取值范围一定,比如取值0-k或者年龄小于100等
例题:输入一个长度为n的非负整数数组,取值范围为0-k,请用线性时间复杂度完成排序

public int [] countingSort(int data[],int k){
    if(data==null||data.length<1||k<0)
        return null;
    int numbers[]=new int[k+1];
    int result[]=new int[data.length];
    for(int i=0;i<data.length;i++){
        numbers[data[i]]++;
    }
    for(int i=1;i<=k;i++){
        numbers[i]=numbers[i]+numbers[i-1];
    }
    for(int i=data.length-1;i>=0;i--){
        result[numbers[data[i]]-1]=data[i];
        numbers[data[i]]--;
    }
    return result;
}

不需要额外存储空间

    public int [] countSort(int data[],int k){
        if(data==null||data.length<1||k<0)
            return null;
        int numbers[]=new int[k+1];
        for(int i=0;i<data.length;i++){
            numbers[data[i]]++;
        }
        int index=0;
        for(int i=0;i<=k;i++){
            for(int j=0;j<numbers[i];j++){
                data[index]=i;
                index++;
            }
        }
        return data;
    }

各个算法的比较
这里写图片描述
冒泡排序与选择排序区别:冒泡排序每次选择剩余最大的放在后面,比较进行交换,在这过程中可能会发生多次交换,而选择排序可以选择剩余比较小的放在前面,但是过程中发生交换次数比较少,基本是最后找到剩余最小的放在对应的位置。
插入排序与选择排序区别:插入排序也是从前面开始有序区,但是前面有序区并非元素最终位置,会根据后面元素大小来调位置,而选择则是最终位置。

猜你喜欢

转载自blog.csdn.net/qq_26564827/article/details/81634702
今日推荐