以前看了一點關於數據結構和算法的文章,這是個充滿魅力的領域,想簡單總結分享一下java
從小到大:算法
冒泡的特色:每一次輪迴後(步驟4),末排序的值都會「冒」到正確的位置,而後繼續輪迴,繼續冒泡;數組
冒泡實戰:數據結構
public static int[] bubbleSort(int[] arr) {
// 初始化第一次最終冒泡的位置,及最後一個索引
int lastSortedIndex = arr.length-1;
// 初始化設定爲排序
boolean sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0; i < lastSortedIndex; i++) {
if (arr[i] > arr[i + 1]) {
sorted = false;
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
lastSortedIndex--;
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(bubbleSort(arr))); // 1,2,3,4,5
}
複製代碼
冒泡的效率:數據結構和算法
比較:(N-1)+(N-2)+(N-3)+...+1ui
交換:最壞:(N-1)+(N-2)+(N-3)+...+1,最好:0spa
時間複雜度:O(N²)指針
從小到大:code
選擇特色:選擇最小值索引。比較時,只記錄索引值,不作置位操做,直到本次數組比較完畢,再進行至多一次交換,最小值將依次向後排列排序
選擇實戰:
public static int[] selectionSort(int[] arr) {
// 從小到大排序,依次最小的值
for (int i = 0; i < arr.length; i++) {
// 初始化最小值的索引
int minIdenx = i;
for (int j = i+1; j < arr.length; j++) {
// 當前索引值小於當前最小值,更新索引
if (arr[j] < arr[minIdenx]) {
minIdenx = j;
}
}
// 當前最小值的索引不在起點
if (minIdenx != i) {
int temp = arr[i];
arr[i] = arr[minIdenx];
arr[minIdenx] = temp;
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(selectionSort(arr)));
}
複製代碼
選擇效率:
比較:(N-1)+(N-2)+(N-3)+...+1
交換:最多:N-1,最少:0(每輪1或0次)
時間複雜度:O(N²/2) ——>忽略常數——>O(N²)
選擇排序的步數大概只有冒泡的一半
從小到大:
插入特色:每輪四個步驟,移出,比較,平移,插入
插入實戰:
public static int[] insertionSort(int[] arr) {
// 從第二個元素開始移出
for (int i = 1; i < arr.length; i++) {
// 初始空隙所在位置的指針
int position = i;
// 當前移出值保存到臨時變量
int tempValue = arr[i];
// 直到空隙移到最左側,或當前值小於臨時變量,則將臨時變量插入空隙
while (position > 0 && arr[position - 1] > tempValue) {
// 不符合條件,將左側值右移一位,即:將左側的值賦給右側,指針減一
arr[position] = arr[--position];
}
// 臨時變量插入當前空隙的指針
arr[position] = tempValue;
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(insertionSort(arr)));
}
複製代碼
插入效率:
移出:N-1
比較:最多:1+2+3+...+N-1=N²/2,最少:N-1
平移:最多:N²/2,最少:0(有序)
插入:N-1
時間複雜度:O(N²+2N-2)——>簡化——>O(N²),最壞、平均、最好狀況:N二、N2/二、N步
分區:
從小到大:
快速特色:一次分區至少有N次比較,及數組的每一個值都要與軸作比較;每次分區,左右指針豆花從兩端開始靠近,直到相遇
實戰:
public class TestQuickSort {
public static int partition(int[] arr, int leftPointer, int rightPointer) {
// 老是取最右的值做爲軸
int pivotPosition = rightPointer;
int pivot = arr[pivotPosition];
// 將右指針指向軸左邊的一格
rightPointer -= 1;
while (true) {
// 左指針只要小於軸,右移,不能超過軸
while (arr[leftPointer] < pivot && leftPointer < pivotPosition) {
leftPointer += 1;
}
// 右指針只要小於軸,左移
while (arr[rightPointer] > pivot && rightPointer > 0) {
rightPointer -= 1;
}
if (leftPointer >= rightPointer) {
break;
} else {
swap(arr, leftPointer, rightPointer);
}
}
// 將左指針的值與軸交換
swap(arr, leftPointer, pivotPosition);
// 返回左指針
return leftPointer;
}
public static void swap(int[] arr, int pointer1, int pointer2) {
int tempValue = arr[pointer1];
arr[pointer1] = arr[pointer2];
arr[pointer2] = tempValue;
}
public static int[] quickSort(int[] arr, int leftPointer, int rightPointer) {
// 基準情形:分出的子數組長度爲0或1
if (rightPointer - leftPointer <= 0) {
return arr;
}
// 將數組分紅兩部分,並返回分隔所用的軸的索引
int pivotPosition = partition(arr, leftPointer, rightPointer);
// 對軸左側的部分遞歸調用quicksort
quickSort(arr, leftPointer, pivotPosition - 1);
// 對軸右側的部分遞歸調用quicksort
quickSort(arr, pivotPosition + 1, rightPointer);
return arr;
}
public static void main(String[] args) {
// int[] arr = {0, 5, 2, 1, 6, 4};
int[] arr = {5, 6, 0, 4, 3, 2, 1, 4};
int[] sort = quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(sort));
}
}
複製代碼
快速效率:
比較:每一個值都要與軸比較
交換:在適當時候將左右指針所指的兩個值交換位置
時間複雜度:一次分區,最少交換1次,最多N/2次,分區——>O(N);總共——>O(NlogN) 最好:O(NlogN),平均O(NlogN),最壞O(N²)(每次分區都是軸落在數組的開頭或結尾,如已升序或降序)
參考書籍:數據結構與算法圖解-【美】傑伊·溫格羅