数据结构三:排序+二分查找(DataWhale系列)

Datawhale 系列数据结构

Task3.1 排序

3.1.1归并

//采用分治(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全的序列
    public static int [] mergeSort(int []arr){
        int len =arr.length;
        if(len<2){
            return arr;
        }
        int [] left=Arrays.copyOfRange(arr,0,len/2);
        int [] right=Arrays.copyOfRange(arr,len/2,len);
        return merge(mergeSort(left),mergeSort(right));
    }
    public static int [] merge(int [] left,int [] right){
        int llen=left.length;
        int rlen=right.length;
        int[] res=new int[llen+rlen];
        int li=0,ri=0,rei=0;
        while (llen-li>0 && rlen-ri>0) {
            if (left[li] <= right[ri]) {
                res[rei++]=left[li++];
            } else {
                res[rei++]=right[ri++];
            }
        }
        while (llen-li>0) {
            res[rei++]=left[li++];
        }
        while (rlen-ri>0) {
            res[rei++]=right[ri++];
        }
        return res;
    }

3.1.2 快速排序

/*快速排序使用分治法来把一个list分为两个子list:
*从数列中跳出一个元素,称为“基准”(pivot)
*重新排序数列,所有元素比基准小的摆放在基准前面,所有比基准大的放在基准后面。在这个分区推出后,该基准就处于数列的中间位置。这个称为分区操作。
*递归的,把小于基准值元素的子数列和大于基准值元素的子数列排序
*/
public static int partition(int []array,int lo,int hi){
        //固定的切分方式
        int key=array[lo];
        while(lo<hi){
            while(array[hi]>=key&&hi>lo){//从后半部分向前扫描
                hi--;
            }
            array[lo]=array[hi];
            while(array[lo]<=key&&hi>lo){从前半部分向后扫描
                lo++;
            }
            array[hi]=array[lo];
        }
        array[hi]=key;
        return hi;
    }
    
    public static void sort(int[] array,int lo ,int hi){
        if(lo>=hi){
            return ;
        }
        int index=partition(array,lo,hi);
        sort(array,lo,index-1);
        sort(array,index+1,hi); 
    }

3.1.3 插入

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

3.1.4 冒泡

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

3.1.5 选择

public static int [] selectionSort(int [] arr){
        int min = 0;
        for(int i=0;i<arr.length-1;i++){
            for(int j=i+1;j<arr.length-1;j++){
                min = arr[i]; 
                if(arr[j]<min){
                    min=arr[j];
                    arr[j]=arr[i];
                    arr[i]=min;
                }
            }
        }
        return arr;
    }

3.1.6 堆排序(选做)

/*堆排序分为三个步骤:
*    创建最大堆
*    确保最大堆中父节点的值比子节点的值都大
*    将根节点与最后一个叶子节点比较,择其大者剔除出堆,再重复第2、3步。
*第二步是整个堆排序的关键。
*/
public static void maxHeapify(int[] array, int heapsize, int i){
    int l = 2*i + 1;
    int r = 2*i + 2;
    int large = i;
    if (l < heapsize && array[i] < array[l]) {
        large = l;
    }else {
        large = i;
    }
    if (r < heapsize && array[large] < array[r]) {
        large = r;
    }
    if (large != i) {
        int temp = array[i];
        array[i] = array[large];
        array[large] = temp;
        //因为将最大值和父节点交换了位置,新的子节点并不能保证一定是比它的子节点大
        //所以需要递归,确定交换的子节点比它的子节点都大
        //而没有动的子节点是不需要进行递归的,因为它的数值没有变,如果之前满足最大堆条件,现在就还是满足的
        maxHeapify(array, heapsize, large);
    }
}
//创建堆
public static void buildMaxHeap(int[] array){
    int heapsize = array.length;
    for (int i = heapsize/2; i >= 0; i--) {
        maxHeapify(array,heapsize,i);
    }
}
public static void heapSort(int[] array){
    int heapsize = array.length;
    for (int i = heapsize - 1; i > 0; i--) {
        if (array[i] < array[0]) {
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            heapsize --;
            maxHeapify(array, heapsize, 0);
        }
    }
}

3.1.8 编程实现 O(n) 时间复杂度内找到一组数据第 K 大元素

//采用堆排序的方法
//在创建最小堆,只创建K个元素
public static void maxHeapify(int[] array, int size, int i) {
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        int small = i;
        if (left < size) {
            if (array[small] > array[left]) {
                small = left;
            }
        }
        if (right < size) {
            if (array[small] > array[right]) {
                small = right;
            }
        }
        if (small != i) {
            int temp = array[small];
            array[small] = array[i];
            array[i] = temp;
            maxHeapify(array, size, small);
        }
    }

    public static void buildHeap(int[] array, int size) {
        for (int i = size - 1; i >= 0; i--) {
            maxHeapify(array, size, i);
        }
    }
    
    public static int findKByHeap(int[] array, int k) {
        buildHeap(array, k);
        for (int i = k + 1; i < array.length; i++) {
            if (array[i] > array[0]) {
                int temp = array[i];
                array[i] = array[0];
                array[0] = temp;
                maxHeapify(array, k, 0);
            }
        }
        return array[0];
    }

TASK3.2 查找

3.2.1 实现一个有序数组的二分查找

//默认数组是有序数组
    public static int biSearch(int [] arr, int target){
        int r = arr.length-1;
        int l = 0;
        int mid=r/2;
        while(l<=r){
            mid=(l+r)/2;
            if(arr[mid]==target)
                return mid;
            else if(arr[mid]>target)
                r=mid;
            else
                l=mid;
        }
        return -1;
        
        
    } 

3.2.2 实现模糊二分查找算法(比如大于等于给定值的第一个元素)

//模糊二分查找,返回大于等于给定值的第一个值的下标
    public static int blurrySearch(int [] arr, int target){
        int r = arr.length-1;
        int l = 0;
        int mid=r/2;
        while(l<=r){
            mid=(l+r)/2;
            if(arr[mid]==target)
                return mid;
            else if(arr[mid]>target)
                r=mid-1;
            else
                l=mid+1;
        }
        return r+1;
    } 
    

3.2.3 Sqrt(x)(x的平方根)

class Solution {
    public int mySqrt(int x) {
        if(x==1) return 1;
        int min=0;
        int max = x;
        while(max-min>1){
            int m=(max+min)/2;
            if(x/m<m) max=m;
            else min = m;
        }
        return min;
    
    }
}
上一篇:C语言如何交换两变量值?5大方法告诉你!


下一篇:一个连续创业者的不破不立——对话阿里云 MVP蒋烁淼