不具有穩定性的排序:選擇排序、快速排序、堆排序java
具有穩定性的排序:冒泡排序、插入排序、歸併排序(nlogn)api
每次遍歷找到數組中最小的元素的索引,依次交換。數組
public int[] sortArray (int[] nums) { for(int i=0; i<nums.length; i++) { int minIndex = i; for(int j=i+1; j<nums.length; j++) { minIndex = nums[j] < nums[minIndex] ? j : minIndex; } swap(nums, i, minIndex); } return nums; }
基本思路:ui
low 指針找到大於 pivot 的元素,hight 指針找到小於 pivot 的元素,而後兩個元素交換位置,最後再將基準數歸位。spa
public void quickSort (int[] nums, int low, int high) { if(low < high) { int index = partition(nums, low, high); quickSort(nums, low, index-1); quickSort(nums, index+1, high); } } public int partition(int[] nums, int low, int high) { int pivot = nums[low]; while(low < high) { while(low<high && nums[high] >= pivot) { high--; } nums[low] = nums[high]; while(low<high && nums[low] <= pivot) { low++; } nums[high] = nums[low]; } nums[low] = pivot; return low; }
其實這種方法,算是對上面方法的挖坑填坑步驟進行合併,low 指針找到大於 pivot 的元素,hight 指針找到小於 pivot 的元素,而後兩個元素交換位置,最後再將基準數歸位。指針
public void quickSort (int[] nums, int low, int high) { if(low < high) { int index = partition(nums, low, high); quickSort(nums, low, index-1); quickSort(nums, index+1, high); } } public int partition(int[] nums, int low, int high) { int pivot = nums[low]; int start = low; //記錄low指針 while(low < high) { while(low < high && nums[high] >= pivot) high--; while(low < high && nums[low] <= pivot) low++; if(low >= high) { break; } swap(nums, low, high); } //基準值歸位 swap(nums, start, low); return low; } public void swap(int[] nums, int i, int j) { if(i == j) return; nums[i] = nums[i] ^ nums[j]; nums[j] = nums[i] ^ nums[j]; nums[i] = nums[i] ^ nums[j]; }
兩兩比較相鄰記錄的關鍵字,若是是反序則交換,直到沒有反序爲止。code
public int[] sortArray(int[] nums) { for(int i=0; i<nums.length; i++) { for(int j=0; j<nums.length-i-1; j++) { if(nums[j] > nums[j+1]) { swap(nums, j, j+1); } } } return nums; } private void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
冒泡排序能夠用 標識flag 改進,若是交換則標識位發生變化,若是標識爲沒有變化,說明已經排序好了!排序
不斷地與前面的數字比較,若是前面的數字比它大,它就和前面的數字交換位置。遞歸
public int[] sortArray(int[] nums) { for(int i=1; i<nums.length; i++) { int j = i; //記錄當前數字下標 //當前數字比前一個數字小,則交換 while(j >= 1 && nums[j] < nums[j-1]) { swap(nums, j, j-1); j--; //繼續向前一個元素比較 } } return nums; } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
public int[] sortArray (int[] nums) { int[] temp = new int[nums.length]; mergeSort(nums, 0, nums.length-1, temp); return nums; } public void mergeSort(int[] nums, int low, int high, int[] temp) { int mid = (low + high) / 2; if(low < high) { //對左右進行拆分 mergeSort(nums, low, mid, temp); mergeSort(nums, mid+1, high, temp); //合併 merg(nums, low, high, mid, temp); } } public void merg(int[] nums, int low, int high, int mid, int[] temp) { int index = 0; int i = low; //左邊序列起始索引 int j = mid + 1; //右邊序列起始索引 while(i <= mid && j <= high) { if(nums[i] <= nums[j]) { //這裏最好用 <= temp[index++] = nums[i++]; } else { temp[index++] = nums[j++]; } } //若左邊序列還有剩餘 while(i <= mid) { temp[index++] = nums[i++]; } //若右邊序列還有剩餘 while(j <= high) { temp[index++] = nums[j++]; } //把temp數組的賦值給原數組nums for(int t=0; t<index; t++) { nums[low + t] = temp[t]; } }
時間複雜度爲:O(NlogN)
索引
額外空間複雜度爲:O(N)
由於堆是徹底二叉樹,因此咱們徹底能夠用數組存儲。將根節點的下標視爲 0,則徹底二叉樹有以下性質:
2i + 1
2i + 2
n/2 - 1
構建大頂堆:將整個數列的初始狀態視做一棵徹底二叉樹,自底向上調整樹的結構,使其知足大頂堆的要求。
變量 heapSize 用來記錄還剩下多少個數字沒有排序完成,每當交換了一個堆頂的數字,heapSize 就會減 1。在 maxHeapify 方法中,使用 heapSize 來限制剩下的選手,不要和已經躺在數組最後,當過冠軍的人比較,省得被暴揍。
public int[] sortArray(int[] nums) { //構建初始大頂堆 buildMaxHeap(nums); for(int i=nums.length - 1; i >= 0; i--) { swap(nums, 0, i); //將最大值放到數組的最後 maxHeapify(nums, 0, i); //調整剩餘數組,使其知足大頂堆 } return nums; } public void buildMaxHeap(int[] nums) { // 從最後一個非葉子結點開始調整大頂堆,最後一個非葉子結點的下標就是 arr.length / 2-1 for(int i = nums.length / 2 - 1; i>=0; i--) { maxHeapify(nums, i, nums.length); } } //調整大頂堆(第三個參數表示剩餘未排序的數字的數量,也就是剩餘堆的大小) public void maxHeapify(int[] nums, int i, int heapSize) { int l = 2 * i + 1; // 左子結點下標 int r = l + 1; // 右子結點下標 int largest = i; //記錄根結點和兩個兒子之間的最大值 if(l < heapSize && nums[l] > nums[largest]) largest = l; if(r < heapSize && nums[r] > nums[largest]) largest = r; //若是有子結點大於根結點,則交換,並用 largest 去再次調整大頂堆。 if(largest != i) { swap(nums, i, largest); maxHeapify(nums, largest, heapSize); } } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }