問題
給一組整數,請將其在原地按照升序排序。使用歸併排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法。
樣例
例1:
輸入:[3,2,1,4,5],
輸出:[1,2,3,4,5]。
例2:
輸入:[2,3,1],
輸出:[1,2,3]。
快速排序
平均運行時間爲O(NlogN),最壞的運行時間爲O(N^2)
一句話總結,就是通過交換實現關鍵字左邊的元素不大於關鍵字,關鍵字右邊的元素不小於關鍵字。
快速排序利用了分治的策略。而分治的基本基本思想是:將原問題劃分爲若干與原問題類似子問題,解決這些子問題,將子問題的解組成原問題的解。
那麼如何利用分治的思想對數據進行排序呢?假如有一個元素集合A:
- 選擇A中的任意一個元素pivot,該元素作爲基準
- 將小於基準的元素移到左邊,大於基準的元素移到右邊(分區操作)
- A被pivot分爲兩部分,繼續對剩下的兩部分做同樣的處理
直到所有子集元素不再需要進行上述步驟
public class Solution {
/**
* @param A: an integer array
* @return: nothing
*/
public void sortIntegers2(int[] A) {
quickSort(A, 0, A.length - 1);
}
private void quickSort(int[] arr, int start, int end) {
if (start >= end)
return;
int left = start;
int right = end;
int pivot = arr[start];
while (left <= right) {
while (pivot < arr[right] && left <= right) {
right--;
}
while (pivot > arr[left] && left <= right) {
left++;
}
if (left <= right) {
swap(arr, left, right);
left++;
right--;
}
}
quickSort(arr, start, right);
quickSort(arr, left, end);
}
private void swap(int a[], int m, int n) {
int tmp = a[m];
a[m] = a[n];
a[n] = tmp;
}
}
歸併排序
https://www.cnblogs.com/chengxiao/p/6194356.html
歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。
可以看到這種結構很像一棵完全二叉樹,本文的歸併排序我們採用遞歸去實現(也可採用迭代的方式去實現)。分階段可以理解爲就是遞歸拆分子序列的過程,遞歸深度爲log2n。
public class Solution {
/**
* @param A: an integer array
* @return: nothing
*/
public void sortIntegers2(int[] A) {
// write your code here
if (A == null || A.length == 0)
return;
// 放在外面new會比較好,這樣只需要new一次,不用次次進函數new
int[] temp = new int[A.length];
mergeSort(A, 0, A.length - 1, temp);
}
private void mergeSort(int[] A, int start, int end, int[] temp) {
if (start >= end)
return;
// 無腦分治
int mid = start + (end - start) / 2;
mergeSort(A, start, mid, temp);
mergeSort(A, mid + 1, end, temp);
// 合併
merge(A, start, end, temp);
}
private void merge(int[] A, int start, int end, int[] temp) {
// 左右兩半邊數組的起始index
int mid = start + (end - start) / 2;
int leftIndex = start;
int rightIndex = mid + 1;
int index = leftIndex; // temp數組的下標
while (leftIndex <= mid && rightIndex <= end) {
if (A[leftIndex] < A[rightIndex])
temp[index++] = A[leftIndex++];
else
temp[index++] = A[rightIndex++];
}
// 若是有數組還未結束,手動將之加入
while (leftIndex <= mid)
temp[index++] = A[leftIndex++];
while (rightIndex <= end)
temp[index++] = A[rightIndex++];
// 將temp中的數字放回原數組組中
for (int i = start; i <= end; i++)
A[i] = temp[i];
}
}