1. 程式人生 > >常見演算法的java實現程式碼(持續更新中)

常見演算法的java實現程式碼(持續更新中)

1.快速排序演算法

快速排序演算法的原理是:假設要排序的陣列是A[1]……A[N],首先任意選取一個數據(通常選用第一個資料)作為關鍵資料,然後將所有比它的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一躺快速排序,然後遞迴該演算法,就可以將陣列快速排序,常用實現方法是這樣的:

private int[] bArray = new int[]{50,72,36,9,18,29,31,61,519,11};

int [] result = quickSort(bArray,0,bArray.length-1);

    private int[] quickSort(int[] array,int i,int j){
        // 左端小於右端時進行排序操作
        if(i < j){
        // 以陣列第一個值為標準值
            int key = array[i];
            int low = i;
            int high = j;
        // 當low小於high時開始迴圈
            while(low < high){
                //迴圈找到array[high] > key,沒有則指標左移
                while(low < high && array[high] > key){
                    high--;
                }
                // 可能已經結束,避免死迴圈,將小於標準值的右端的數放到左端
                if(low < high)
                    array[low++] = array[high];

                //迴圈找到array[low] < key,沒有則指標右移
                while(low < high && array[low] < key){
                    low++;
                }
                // 可能已經結束,避免死迴圈,將大於標準值的右端的數放到右端
                if(low < high)
                    array[high--] = array[low];
            }
        //  當左右端的迴圈結束,迴圈結束的位置即是key的位置
            array[low] = key;
        //  遞迴排序此次標準值左端的資料
            quickSort(array,i,low-1);
            // 遞迴排序此次標準值右端的資料
            quickSort(array,low+1,j);
        }

        return array;
    }

2.堆排序

堆排序演算法的原理是:1.將初始陣列R[]構造成大頂堆

      2.將堆頂R[0]與堆底R[n]互換,然後重新把堆調整成符合標準的大頂堆

      3.之後將堆底剔除,然後重複2的操作直到將R[]中的除堆頂全部排完 其實現程式碼為:

大頂堆的標準為:任何一非葉節點的關鍵字不小於其左右孩子節點的關鍵字

//    構建大頂堆
    public void createMaxdHeap(int[] data, int lastIndex) {
        for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
            // k為當前節點的上一級結點
            int k = i;
            // 此while存在的意義在於如果子節點比當前結點大時互換後需要重新排序
            while (2 * k + 1 <= lastIndex) {
                // biggerIndex總是記錄較大節點的值,先賦值為當前判斷節點的左子節點
                int biggerIndex = 2 * k + 1;
                // 判斷當前節點的子節點是否存在
                if (biggerIndex < lastIndex) {
                    // 判斷左右兩個節點那個大,選取大的那個節點與父節點比較
                    if (data[biggerIndex] < data[biggerIndex + 1]) {
                        biggerIndex++;
                    }
                }
                if (data[k] < data[biggerIndex]) {
                    // 若當前節點值比子節點最大值小,則交換2者得值,交換後將biggerIndex值賦值給k
                    swap(data, k, biggerIndex);
                    k = biggerIndex;
                } else {
                    break;
                }
            }
        }
    }

    // 交換兩個位置的值
    public void swap(int[] data, int i, int j) {
        if (i == j) {
            return;
        }
        data[i] = data[i] + data[j];
        data[j] = data[i] - data[j];
        data[i] = data[i] - data[j];
    }

3.歸併排序

歸併排序是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。我自己先實現了合併的這部分:

1.先申請空間,構建一個大小為兩個有序陣列大小之和的的陣列;

2.設定三個指標,分別指向三個陣列;

3.比較兩個有序陣列指標指向的值,取最小值放在新的陣列中;

4.將指標右移然後繼續3的操作;其實現程式碼為:

        private int[] mArray1= new int[]{1,5,17,38};
        private int[] mArray2= new int[]{2,4,12};

        merge(mArray1,mArray2);

    private void merge(int[] array1,int[] array2){
        int length = array1.length+array2.length;
        int[] newArray = new int[length];
        int i = 0;
        int j = 0;
        int z = 0;
        //  當兩個陣列的指標都不超過陣列大小時進行迴圈,最後會迴圈到只剩下一個數組的值沒新增到新陣列,或者都新增進新陣列
        while (i<= array1.length-1 && j <=array2.length-1){
            //  取指標指向的最小值,將之新增到新陣列
            if(array1[i] <= array2[j]){
            newArray[z++] = array1[i++];
            }
            if(array1[i] > array2[j]){
            newArray[z++] = array2[j++];
            }
        }
        //  當只剩下array1裡的值沒有放進新建陣列中時,將array1的值全部放進新建陣列中
        while (i<= array1.length-1){
            newArray[z++] = array1[i++];
        }
        // 當只剩下array2裡的值沒有放進新建陣列中時,將array2的值全部放進新建陣列中
        while (j <=array2.length-1){
            newArray[z++] = array2[j++];
        }

    }


4.二分法查詢

二分法查詢。。。應該不用我解釋原理吧。。話說我以前寫html的時候要是有bug就用二分法查詢來著大笑但是要注意的是使用二分法的前提是 查詢陣列時有序陣列,然後下面是我寫的查詢方法,

//    引數待查詢的陣列,待查詢的數
    private boolean binarySearch(int[] data,int number){
        int left = 0;
        int mid = (data.length-1)/2;
        int right = data.length-1;
        //  當待查詢的數大於最大或者小於最小時直接跳出
        if(number < data[left] || number > data[right])
            return false;
        //  當數字在陣列範圍內時
        while (left <= mid && mid <= right){
            //  迴圈至三個節點進行判斷,成功就跳出
            if(number == data[left]) return true;
            if(number == data[mid]) return true;
            if(number == data[right]) return true;
            //  進行迴圈時會出現left = mid的情況,即right =left + 1 在這裡進行判斷,防止死迴圈
            if(left == mid || mid == right){
                if(number == data[right] || number == data[left]) return true;
                else return false;
            }
            //  當查詢數在left與mid之間時,把right賦值為mid,mid重新賦值
            if (number > data[left] && number < data[mid]){
                right = mid;
                mid = (right + left)/2;
            }
            // 當查詢數在mid與right之間時,把left賦值為mid,mid重新賦值
            if (number >data[mid] && number <= data[right]){
                left = mid;
                mid = (right + left)/2;
            }
        }
        return false;
    }

由於上面的程式碼是我寫的所以邏輯上肯定是有多餘的地方的,剛剛看了一下別人的程式碼,他們是這樣寫的

//    引數待查詢的陣列,待查詢的數
    private boolean binarySearch(int[] data,int number){
        int left = 0;
        int right = data.length-1;
        //  當數字在陣列範圍內 開始迴圈
        while (left <= right){
            int mid = (right + left)/2;
            //  當查詢數在left與mid之間時,最右指標移至mid-1
            if (number < data[mid]){
                right = mid-1;
            }
            // 當查詢數在mid與right之間時,最左指標移至mid+1
            else if (number > data[mid]){
                left = mid+1;
            //  出現相等情況下,返回true
            }else {
                return true;
            }
        }
        return false;
    }

簡潔的地方在於把我用來規避死迴圈的那些情況都去掉了 他在最後一個else裡判斷陣列是否含有目標數字。。我用了三個。。當然最大的不同在於right = mid-1 這種寫法,一開始沒想到這種寫法的原因是害怕,這樣會把此刻大於data[mid-1]小於data[mid]的值落下,其實是沒有必要的,因為如果他此時是這種情況的話,就會一直進入else if裡直到left>right 退出迴圈