算法復雜度

相關概念:
穩定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不穩定:如果a原本在b的前面,而a=b,排序之后 a 可能會出現在 b 的后面。
時間復雜度:對排序數據的總的操作次數。反映當n變化時,操作次數呈現什么規律。
空間復雜度:是指算法在計算機內執行時所需存儲空間的度量,它也是數據規模n的函數
手寫快排:
先選擇第一個數字作為標尺,然后分別從第二個數字往右找,找到比第一個數大的數,和從倒數第一個數字往左找,找到比第一個數小的數,然后將找到的兩個數進行交換,一直下去。
- 從數列中挑出一個元素,稱為 “基准”(pivot);
- 重新排序數列,所有元素比基准值小的擺放在基准前面,所有元素比基准值大的擺在基准的后面(相同的數可以到任一邊)。在這個分區退出之后,該基准就處於數列的中間位置。這個稱為分區(partition)操作;
- 遞歸地(recursive)把小於基准值元素的子數列和大於基准值元素的子數列排序。
public class quickSort {
private static int[] quickSort(int[] arr, int left, int right) {
if (left < right) {
int p = patition(arr, left, right);//基數
quickSort(arr, left, p - 1);
quickSort(arr, p + 1, right);
}
return arr;
}
private static int patition(int[] arr, int left, int right) {// 分區操作
int temp = left;
while (left < right) {
//從右邊開始找到比主鍵值a[0]小的值,移到左邊
while (left < right && arr[right] >= arr[temp])
right--;
while (left < right && arr[left] <= arr[temp])
//從左邊開始找到比主鍵值a[0]大的值,移到右邊
left++;
swap(arr,left,right);
}
//最終將基准數歸位
swap(arr, temp, right);
return right;
}
private static void swap(int[] arr, int left, int right) {
int temp=arr[left];
arr[left]=arr[right];
arr[right]=temp;
}
}
手寫歸並:
該算法采用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然后遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。
- 把長度為n的輸入序列分成兩個長度為n/2的子序列;
- 對這兩個子序列分別采用歸並排序;
- 將兩個排序好的子序列合並成一個最終的排序序列。
public class MergeSort {
public static void main(String[] args) {
int[] arr = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int[] temp = new int[arr.length];
sort(arr, 0, arr.length - 1, temp);
System.out.println(Arrays.toString(arr));
}
private static void sort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
sort(arr, left, mid, temp);
sort(arr, mid + 1, right, temp);
MergeSort(arr, left, mid, right, temp);
}
}
private static void MergeSort(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
while (i <= mid) {// 將左邊剩余的元素填充進temp
temp[t++] = arr[i++];
}
while (j <= right) {
temp[t++] = arr[j++];
}
t = 0;
while (left <= right) {
arr[left++] = temp[t++];
}
}
}
手寫堆排序:
堆排序
堆排序是利用堆這種數據結構而設計的一種排序算法,堆排序是一種選擇排序,它的最壞,最好,平均時間復雜度均為O(nlogn),它也是不穩定排序。首先簡單了解下堆結構。
堆
堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。

堆排序的基本思想是:將待排序序列構造成一個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將其與末尾元素進行交換,此時末尾就為最大值。然后將剩余n-1個元素重新構造成一個堆,這樣會得到n個元素的次小值。如此反復執行,便能得到一個有序序列了
用簡單的公式來描述一下堆的定義就是:
大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
public class HeapSort {
private static void sort(int[] arr) {
// 1、構建大頂堆
for(int i=arr.length/2-1;i>=0;i--){
//從第一個非葉子節點從下至上,從右至左調整結構
adjustHeap(arr,i,arr.length);
}
//2、調整堆結構+交換堆頂元素與末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//將堆頂元素與末尾元素進行交換
adjustHeap(arr, 0, j);//重新對堆進行調整
}
}
private static void swap(int[] arr, int a, int b) {
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
private static void adjustHeap(int[] arr, int i, int length) {
int temp=arr[i];
for(int k=i*2+1;k<length;k=k*2+1){//從i結點的左子結點開始,也就是2i+1處開始
if(k+1<length&&arr[k]<arr[k+1]){
k++;
}
if(arr[k]>temp){//如果子節點大於父節點,將子節點值賦給父節點(不用進行交換)
arr[i]=arr[k];
i=k;
}else{
break;
}
}
arr[i]=temp;//將temp值放到最終的位置
}
}
參考博文:
十大經典排序算法(動圖演示)https://www.cnblogs.com/onepixel/articles/7674659.html
