數據結構三:排序+二分查找(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;
    
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章