常見演算法的java實現程式碼(持續更新中)
阿新 • • 發佈:2019-02-11
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 退出迴圈